A decentralized music tracking and discovery platform built on AT Protocol 🎵

[web] replace react router with tanstack react router

+964 -319
+4 -8
apps/web-mobile/bun.lock
··· 37 37 "react-dom": "^18.3.1", 38 38 "react-hook-form": "^7.54.2", 39 39 "react-i18next": "^15.4.0", 40 - "react-router": "^7.1.3", 41 - "react-router-dom": "^7.1.3", 40 + "react-router": "^7.6.3", 41 + "react-router-dom": "^7.6.3", 42 42 "recharts": "^2.15.1", 43 43 "styletron-engine-monolithic": "^1.0.0", 44 44 "styletron-react": "^6.1.1", ··· 456 456 "@types/babel__template": ["@types/babel__template@7.4.4", "", { "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" } }, "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A=="], 457 457 458 458 "@types/babel__traverse": ["@types/babel__traverse@7.20.6", "", { "dependencies": { "@babel/types": "^7.20.7" } }, "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg=="], 459 - 460 - "@types/cookie": ["@types/cookie@0.6.0", "", {}, "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA=="], 461 459 462 460 "@types/d3-array": ["@types/d3-array@3.2.1", "", {}, "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg=="], 463 461 ··· 1153 1151 1154 1152 "react-range": ["react-range@1.10.0", "", { "peerDependencies": { "react": "*", "react-dom": "*" } }, "sha512-kDo0LiBUHIQIP8menx0UoxTnHr7UXBYpIYl/DR9jCaO1o29VwvCLpkP/qOTNQz5hkJadPg1uEM07XJcJ1XGoKw=="], 1155 1153 1156 - "react-router": ["react-router@7.1.3", "", { "dependencies": { "@types/cookie": "^0.6.0", "cookie": "^1.0.1", "set-cookie-parser": "^2.6.0", "turbo-stream": "2.4.0" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" }, "optionalPeers": ["react-dom"] }, "sha512-EezYymLY6Guk/zLQ2vRA8WvdUhWFEj5fcE3RfWihhxXBW7+cd1LsIiA3lmx+KCmneAGQuyBv820o44L2+TtkSA=="], 1154 + "react-router": ["react-router@7.6.3", "", { "dependencies": { "cookie": "^1.0.1", "set-cookie-parser": "^2.6.0" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" }, "optionalPeers": ["react-dom"] }, "sha512-zf45LZp5skDC6I3jDLXQUu0u26jtuP4lEGbc7BbdyxenBN1vJSTA18czM2D+h5qyMBuMrD+9uB+mU37HIoKGRA=="], 1157 1155 1158 - "react-router-dom": ["react-router-dom@7.1.3", "", { "dependencies": { "react-router": "7.1.3" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" } }, "sha512-qQGTE+77hleBzv9SIUIkGRvuFBQGagW+TQKy53UTZAO/3+YFNBYvRsNIZ1GT17yHbc63FylMOdS+m3oUriF1GA=="], 1156 + "react-router-dom": ["react-router-dom@7.6.3", "", { "dependencies": { "react-router": "7.6.3" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" } }, "sha512-DiWJm9qdUAmiJrVWaeJdu4TKu13+iB/8IEi0EW/XgaHCjW/vWGrwzup0GVvaMteuZjKnh5bEvJP/K0MDnzawHw=="], 1159 1157 1160 1158 "react-smooth": ["react-smooth@4.0.4", "", { "dependencies": { "fast-equals": "^5.0.1", "prop-types": "^15.8.1", "react-transition-group": "^4.4.5" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q=="], 1161 1159 ··· 1292 1290 "tsconfig-paths": ["tsconfig-paths@4.2.0", "", { "dependencies": { "json5": "^2.2.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" } }, "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg=="], 1293 1291 1294 1292 "tslib": ["tslib@2.6.2", "", {}, "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="], 1295 - 1296 - "turbo-stream": ["turbo-stream@2.4.0", "", {}, "sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g=="], 1297 1293 1298 1294 "tween-functions": ["tween-functions@1.2.0", "", {}, "sha512-PZBtLYcCLtEcjL14Fzb1gSxPBeL7nWvGhO5ZFPGqziCcr8uvHp0NDmdjBchp6KHL+tExcg0m3NISmKxhU394dA=="], 1299 1295
+2 -2
apps/web-mobile/package.json
··· 47 47 "react-dom": "^18.3.1", 48 48 "react-hook-form": "^7.54.2", 49 49 "react-i18next": "^15.4.0", 50 - "react-router": "^7.1.3", 51 - "react-router-dom": "^7.1.3", 50 + "react-router": "^7.6.3", 51 + "react-router-dom": "^7.6.3", 52 52 "recharts": "^2.15.1", 53 53 "styletron-engine-monolithic": "^1.0.0", 54 54 "styletron-react": "^6.1.1",
+3 -1
apps/web/.gitignore
··· 31 31 32 32 .env 33 33 .env.prod 34 - .env.local 34 + .env.local 35 + 36 + .tanstack
+4 -2
apps/web/package.json
··· 37 37 "@tailwindcss/vite": "^4.1.4", 38 38 "@tanstack/react-query": "^5.76.0", 39 39 "@tanstack/react-query-devtools": "^5.76.0", 40 + "@tanstack/react-router": "^1.125.4", 41 + "@tanstack/react-router-devtools": "^1.125.4", 40 42 "@tanstack/react-table": "^8.21.2", 43 + "@tanstack/zod-adapter": "^1.125.4", 41 44 "@types/numeral": "^2.0.5", 42 45 "@vitest/ui": "^3.0.4", 43 46 "axios": "^1.7.9", ··· 58 61 "react-dom": "^18.3.1", 59 62 "react-hook-form": "^7.54.2", 60 63 "react-i18next": "^15.4.0", 61 - "react-router": "^7.1.3", 62 - "react-router-dom": "^7.1.3", 63 64 "recharts": "^2.15.1", 64 65 "styletron-engine-monolithic": "^1.0.0", 65 66 "styletron-react": "^6.1.1", ··· 79 80 "@storybook/react": "^8.5.2", 80 81 "@storybook/react-vite": "^8.5.2", 81 82 "@storybook/test": "^8.5.2", 83 + "@tanstack/router-plugin": "^1.125.4", 82 84 "@types/lodash": "^4.17.15", 83 85 "@types/ramda": "^0.30.2", 84 86 "@types/react": "^18.3.18",
-74
apps/web/src/App.tsx
··· 1 - import { useAtomValue } from "jotai"; 2 - import { useEffect } from "react"; 3 - import { BrowserRouter, Route, Routes } from "react-router-dom"; 4 - import { themeAtom } from "./atoms/theme"; 5 - import AlbumPage from "./pages/album"; 6 - import ApiKeys from "./pages/apikeys"; 7 - import ArtistPage from "./pages/artist"; 8 - import Dropbox from "./pages/dropbox"; 9 - import DropboxWithId from "./pages/dropbox/DropboxWithId"; 10 - import GoogleDrive from "./pages/googledrive"; 11 - import GoogleDriveWithId from "./pages/googledrive/GoogleDriveWithId"; 12 - import HomePage from "./pages/home"; 13 - import Loading from "./pages/loading"; 14 - import PlaylistPage from "./pages/playlist"; 15 - import ProfilePage from "./pages/profile"; 16 - import SongPage from "./pages/song"; 17 - 18 - function App() { 19 - const { darkMode } = useAtomValue(themeAtom); 20 - useEffect(() => { 21 - const root = document.getElementById("root"); 22 - if (darkMode) { 23 - root!.classList.add("dark"); 24 - return; 25 - } 26 - root!.classList.remove("dark"); 27 - }, [darkMode]); 28 - 29 - return ( 30 - <BrowserRouter> 31 - <Routes> 32 - <Route path="/" element={<HomePage />} /> 33 - <Route 34 - path="/:did/app.rocksky.scrobble/:rkey" 35 - element={<SongPage key={window.location.pathname} />} 36 - /> 37 - <Route 38 - path="/:did/app.rocksky.song/:rkey" 39 - element={<SongPage key={window.location.pathname} />} 40 - /> 41 - <Route 42 - path="/:did/app.rocksky.artist/:rkey" 43 - element={<ArtistPage key={window.location.pathname} />} 44 - /> 45 - <Route 46 - path="/:did/app.rocksky.album/:rkey" 47 - element={<AlbumPage key={window.location.pathname} />} 48 - /> 49 - <Route 50 - path="/:did/app.rocksky.playlist/:rkey" 51 - element={<PlaylistPage />} 52 - /> 53 - <Route 54 - path="/profile/:did" 55 - element={<ProfilePage key={window.location.pathname} />} 56 - /> 57 - <Route path="/dropbox" element={<Dropbox />} /> 58 - <Route path="/googledrive" element={<GoogleDrive />} /> 59 - <Route 60 - path="/dropbox/:id" 61 - element={<DropboxWithId key={window.location.pathname} />} 62 - /> 63 - <Route 64 - path="/googledrive/:id" 65 - element={<GoogleDriveWithId key={window.location.pathname} />} 66 - /> 67 - <Route path="/apikeys" element={<ApiKeys />} /> 68 - <Route path="/loading" element={<Loading />} /> 69 - </Routes> 70 - </BrowserRouter> 71 - ); 72 - } 73 - 74 - export default App;
+1 -1
apps/web/src/components/Handle/Handle.tsx
··· 1 + import { Link } from "@tanstack/react-router"; 1 2 import { Avatar } from "baseui/avatar"; 2 3 import { Block } from "baseui/block"; 3 4 import { StatefulPopover, TRIGGER_TYPE } from "baseui/popover"; 4 5 import { LabelMedium, LabelSmall } from "baseui/typography"; 5 6 import { useAtom } from "jotai"; 6 7 import { useEffect } from "react"; 7 - import { Link } from "react-router"; 8 8 import { profilesAtom } from "../../atoms/profiles"; 9 9 import { statsAtom } from "../../atoms/stats"; 10 10 import {
+6 -4
apps/web/src/components/Handle/NowPlaying/NowPlaying.tsx
··· 1 1 import styled from "@emotion/styled"; 2 + import { Link as DefaultLink } from "@tanstack/react-router"; 2 3 import axios from "axios"; 3 4 import { ProgressBar } from "baseui/progress-bar"; 4 5 import { LabelXSmall } from "baseui/typography"; 5 6 import { useAtom, useAtomValue } from "jotai"; 6 7 import _ from "lodash"; 7 8 import { useCallback, useEffect, useRef } from "react"; 8 - import { Link as DefaultLink } from "react-router"; 9 9 import { playerAtom } from "../../../atoms/player"; 10 10 import { userNowPlayingAtom } from "../../../atoms/userNowplaying"; 11 11 import { API_URL } from "../../../consts"; ··· 187 187 <> 188 188 <div className="flex flex-row items-center mt-[25px]"> 189 189 {!!nowPlaying[did]?.albumUri && ( 190 - <Link to={`/${nowPlaying[did]?.albumUri?.split("at://")[1]}`}> 190 + <Link 191 + to={`/${nowPlaying[did]?.albumUri?.split("at://")[1].replace("app.rocksky.", "")}`} 192 + > 191 193 <Cover src={nowPlaying[did]?.albumArt} /> 192 194 </Link> 193 195 )} ··· 198 200 <div className="max-w-[316px] overflow-hidden truncate"> 199 201 {nowPlaying[did]?.songUri && ( 200 202 <Link 201 - to={`/${nowPlaying[did]?.songUri?.split("at://")[1]}`} 203 + to={`/${nowPlaying[did]?.songUri?.split("at://")[1].replace("app.rocksky.", "")}`} 202 204 className="font-semibold truncate whitespace-nowrap text-[var(--color-text)]" 203 205 > 204 206 {nowPlaying[did]?.title} ··· 213 215 <div className="max-w-[316px] overflow-hidden truncate"> 214 216 {!!nowPlaying[did]?.artistUri?.split("at://")[1] && ( 215 217 <Link 216 - to={`/${nowPlaying[did]?.artistUri?.split("at://")[1]}`} 218 + to={`/${nowPlaying[did]?.artistUri?.split("at://")[1].replace("app.rocksky.", "")}`} 217 219 className="text-[var(--color-text-muted)] font-semibold truncate whitespace-nowrap text-sm" 218 220 style={{ color: "var(--color-text-muted)" }} 219 221 >
+7 -3
apps/web/src/components/ScrobblesAreaChart/ScrobblesAreaChart.tsx
··· 1 + import { useParams, useRouter } from "@tanstack/react-router"; 1 2 import { LabelMedium } from "baseui/typography"; 2 3 import dayjs from "dayjs"; 3 4 import numeral from "numeral"; 4 5 import { useEffect, useState } from "react"; 5 - import { useLocation, useParams } from "react-router"; 6 6 import { Area, AreaChart, Tooltip, TooltipProps, XAxis } from "recharts"; 7 7 import useChart from "../../hooks/useChart"; 8 8 ··· 37 37 getSongChart, 38 38 getProfileChart, 39 39 } = useChart(); 40 - const { pathname } = useLocation(); 41 - const { did, rkey } = useParams<{ did: string; rkey: string }>(); 40 + const { 41 + state: { 42 + location: { pathname }, 43 + }, 44 + } = useRouter(); 45 + const { did, rkey } = useParams({ strict: false }); 42 46 const [data, setData] = useState< 43 47 { 44 48 date: string;
+7 -7
apps/web/src/components/Shout/Shout.tsx
··· 1 1 /* eslint-disable @typescript-eslint/no-explicit-any */ 2 2 import { zodResolver } from "@hookform/resolvers/zod"; 3 + import { useParams } from "@tanstack/react-router"; 3 4 import { Button } from "baseui/button"; 4 5 import { Spinner } from "baseui/spinner"; 5 6 import { Textarea } from "baseui/textarea"; ··· 7 8 import { useAtomValue, useSetAtom } from "jotai"; 8 9 import { useState } from "react"; 9 10 import { Controller, useForm } from "react-hook-form"; 10 - import { useLocation, useParams } from "react-router"; 11 11 import z from "zod"; 12 12 import { profileAtom } from "../../atoms/profile"; 13 13 import { shoutsAtom } from "../../atoms/shouts"; ··· 44 44 message: "", 45 45 }, 46 46 }); 47 - const { did, rkey } = useParams<{ did: string; rkey: string }>(); 48 - const location = useLocation(); 47 + const { did, rkey } = useParams({ strict: false }); 48 + const location = window.location; 49 49 const [loading, setLoading] = useState(false); 50 50 51 51 const onShout = async ({ message }: z.infer<typeof ShoutSchema>) => { ··· 56 56 uri = `at://${did}`; 57 57 } 58 58 59 - if (location.pathname.includes("app.rocksky.song")) { 59 + if (location.pathname.includes("/song/")) { 60 60 uri = `at://${did}/app.rocksky.song/${rkey}`; 61 61 } 62 62 63 - if (location.pathname.includes("app.rocksky.album")) { 63 + if (location.pathname.includes("/album/")) { 64 64 uri = `at://${did}/app.rocksky.album/${rkey}`; 65 65 } 66 66 67 - if (location.pathname.includes("app.rocksky.artist")) { 67 + if (location.pathname.includes("/artist/")) { 68 68 uri = `at://${did}/app.rocksky.artist/${rkey}`; 69 69 } 70 70 71 - if (location.pathname.includes("app.rocksky.scrobble")) { 71 + if (location.pathname.includes("/scrobble/")) { 72 72 uri = `at://${did}/app.rocksky.scrobble/${rkey}`; 73 73 } 74 74
+6 -6
apps/web/src/components/Shout/ShoutList/Shout/ReplyModal/ReplyModal.tsx
··· 1 1 /* eslint-disable @typescript-eslint/no-explicit-any */ 2 2 import styled from "@emotion/styled"; 3 3 import { zodResolver } from "@hookform/resolvers/zod"; 4 + import { Link as DefaultLink, useParams } from "@tanstack/react-router"; 4 5 import { 5 6 Modal, 6 7 ModalBody, ··· 14 15 import { useAtomValue, useSetAtom } from "jotai"; 15 16 import { useState } from "react"; 16 17 import { Controller, useForm } from "react-hook-form"; 17 - import { Link as DefaultLink, useParams } from "react-router"; 18 18 import z from "zod"; 19 19 import { profileAtom } from "../../../../../atoms/profile"; 20 20 import { shoutsAtom } from "../../../../../atoms/shouts"; ··· 67 67 const profile = useAtomValue(profileAtom); 68 68 const shouts = useAtomValue(shoutsAtom); 69 69 const setShouts = useSetAtom(shoutsAtom); 70 - const { did, rkey } = useParams<{ did: string; rkey: string }>(); 70 + const { did, rkey } = useParams({ strict: false }); 71 71 const [loading, setLoading] = useState(false); 72 72 73 73 const { control, handleSubmit, reset, watch } = useForm< ··· 98 98 uri = `at://${did}`; 99 99 } 100 100 101 - if (location.pathname.includes("app.rocksky.scrobble")) { 101 + if (location.pathname.includes("/scrobble/")) { 102 102 uri = `at://${did}/app.rocksky.scrobble/${rkey}`; 103 103 } 104 104 105 - if (location.pathname.includes("app.rocksky.song")) { 105 + if (location.pathname.includes("/song/")) { 106 106 uri = `at://${did}/app.rocksky.song/${rkey}`; 107 107 } 108 108 109 - if (location.pathname.includes("app.rocksky.album")) { 109 + if (location.pathname.includes("/album/")) { 110 110 uri = `at://${did}/app.rocksky.album/${rkey}`; 111 111 } 112 112 113 - if (location.pathname.includes("app.rocksky.artist")) { 113 + if (location.pathname.includes("/artist/")) { 114 114 uri = `at://${did}/app.rocksky.artist/${rkey}`; 115 115 } 116 116
+1 -1
apps/web/src/components/Shout/ShoutList/Shout/Shout.tsx
··· 1 1 import styled from "@emotion/styled"; 2 2 import { Ellipsis } from "@styled-icons/fa-solid"; 3 3 import { ArrowReplyDown } from "@styled-icons/fluentui-system-filled"; 4 + import { Link as DefaultLink } from "@tanstack/react-router"; 4 5 import { ListItem } from "baseui/list"; 5 6 import { NestedMenus, StatefulMenu } from "baseui/menu"; 6 7 import { PLACEMENT, StatefulPopover } from "baseui/popover"; ··· 9 10 import dayjs from "dayjs"; 10 11 import { useAtomValue } from "jotai"; 11 12 import { useState } from "react"; 12 - import { Link as DefaultLink } from "react-router"; 13 13 import { profileAtom } from "../../../../atoms/profile"; 14 14 import useLike from "../../../../hooks/useLike"; 15 15 import useShout from "../../../../hooks/useShout";
+11 -7
apps/web/src/components/Shout/ShoutList/ShoutList.tsx
··· 1 1 /* eslint-disable @typescript-eslint/no-explicit-any */ 2 + import { useParams, useRouter } from "@tanstack/react-router"; 2 3 import { useAtomValue, useSetAtom } from "jotai"; 3 4 import { useEffect } from "react"; 4 - import { useLocation, useParams } from "react-router"; 5 5 import { shoutsAtom } from "../../../atoms/shouts"; 6 6 import useShout from "../../../hooks/useShout"; 7 7 import Shout from "./Shout"; ··· 9 9 function ShoutList() { 10 10 const shouts = useAtomValue(shoutsAtom); 11 11 const setShouts = useSetAtom(shoutsAtom); 12 - const { pathname } = useLocation(); 12 + const { 13 + state: { 14 + location: { pathname }, 15 + }, 16 + } = useRouter(); 13 17 const { getShouts } = useShout(); 14 - const { did, rkey } = useParams<{ did: string; rkey: string }>(); 18 + const { did, rkey } = useParams({ strict: false }); 15 19 16 20 useEffect(() => { 17 21 fetchShouts(); ··· 34 38 return; 35 39 } 36 40 37 - if (pathname.includes("app.rocksky.scrobble")) { 41 + if (pathname.includes("/scrobble/")) { 38 42 uri = `at://${did}/app.rocksky.scrobble/${rkey}`; 39 43 } 40 44 41 - if (pathname.includes("app.rocksky.song")) { 45 + if (pathname.includes("/song/")) { 42 46 uri = `at://${did}/app.rocksky.song/${rkey}`; 43 47 } 44 48 45 - if (pathname.includes("app.rocksky.album")) { 49 + if (pathname.includes("/album/")) { 46 50 uri = `at://${did}/app.rocksky.album/${rkey}`; 47 51 } 48 52 49 - if (pathname.includes("app.rocksky.artist")) { 53 + if (pathname.includes("/artist/")) { 50 54 uri = `at://${did}/app.rocksky.artist/${rkey}`; 51 55 } 52 56
+6 -4
apps/web/src/components/StickyPlayer/StrickyPlayer.tsx
··· 1 1 import styled from "@emotion/styled"; 2 + import { Link as DefaultLink } from "@tanstack/react-router"; 2 3 import { ProgressBar } from "baseui/progress-bar"; 3 4 import { LabelSmall } from "baseui/typography"; 4 5 import { useRef } from "react"; 5 - import { Link as DefaultLink } from "react-router-dom"; 6 6 import { useTimeFormat } from "../../hooks/useFormat"; 7 7 import Equalizer from "../Icons/Equalizer"; 8 8 import Heart from "../Icons/Heart"; ··· 135 135 <MiniPlayerWrapper> 136 136 <MiniPlayer className="!bg-[var(--color-background)]"> 137 137 {nowPlaying?.albumUri && ( 138 - <Link to={`/${nowPlaying.albumUri.split("at://")[1]}`}> 138 + <Link 139 + to={`/${nowPlaying.albumUri.split("at://")[1].replace("app.rocksky.", "")}`} 140 + > 139 141 <Cover src={nowPlaying?.albumArt} key={nowPlaying.albumUri} /> 140 142 </Link> 141 143 )} ··· 146 148 <div className="max-w-[310px] text-ellipsis overflow-hidden"> 147 149 {!!nowPlaying?.songUri && ( 148 150 <Link 149 - to={`/${nowPlaying?.songUri?.split("at://")[1]}`} 151 + to={`/${nowPlaying?.songUri?.split("at://")[1].replace("app.rocksky.", "")}`} 150 152 style={{ 151 153 fontWeight: 600, 152 154 }} ··· 169 171 <div className="max-w-[310px] overflow-hidden text-ellipsis"> 170 172 {!!nowPlaying?.artistUri && ( 171 173 <Link 172 - to={`/${nowPlaying?.artistUri?.split("at://")[1]}`} 174 + to={`/${nowPlaying?.artistUri?.split("at://")[1].replace("app.rocksky.", "")}`} 173 175 style={{ 174 176 fontFamily: "RockfordSansLight", 175 177 fontWeight: 600,
+7 -8
apps/web/src/hooks/useDropbox.tsx
··· 1 1 import { useQuery } from "@tanstack/react-query"; 2 - import axios from "axios"; 2 + import { client } from "../api"; 3 3 import { getFile, getFiles, getTemporaryLink } from "../api/dropbox"; 4 - import { API_URL } from "../consts"; 5 4 6 5 export const useFilesQuery = (id?: string) => 7 6 useQuery({ ··· 23 22 24 23 function useDropbox() { 25 24 const getFiles = async (id?: string) => { 26 - const response = await axios.get<{ 25 + const response = await client.get<{ 27 26 cursor: string; 28 27 entries: { 29 28 ".tag": string; ··· 32 31 path_display: string; 33 32 }[]; 34 33 has_more: boolean; 35 - }>(`${API_URL}/dropbox/files`, { 34 + }>(`/dropbox/files`, { 36 35 headers: { 37 36 Authorization: `Bearer ${localStorage.getItem("token")}`, 38 37 }, ··· 44 43 }; 45 44 46 45 const getFile = async (id: string) => { 47 - const response = await axios.get<{ 46 + const response = await client.get<{ 48 47 ".tag": string; 49 48 id: string; 50 49 name: string; 51 50 path_display: string; 52 - }>(`${API_URL}/dropbox/file`, { 51 + }>(`/dropbox/file`, { 53 52 headers: { 54 53 Authorization: `Bearer ${localStorage.getItem("token")}`, 55 54 }, ··· 61 60 }; 62 61 63 62 const getTemporaryLink = async (id: string) => { 64 - const response = await axios.get<{ 63 + const response = await client.get<{ 65 64 link: string; 66 - }>(`${API_URL}/dropbox/temporary-link`, { 65 + }>(`/dropbox/temporary-link`, { 67 66 headers: { 68 67 Authorization: `Bearer ${localStorage.getItem("token")}`, 69 68 },
+3 -3
apps/web/src/layouts/CloudDrive/CloudDrive.tsx
··· 1 1 import styled from "@emotion/styled"; 2 + import { useNavigate } from "@tanstack/react-router"; 2 3 import { LabelMedium } from "baseui/typography"; 3 4 import { useAtomValue } from "jotai"; 4 5 import { useState } from "react"; 5 - import { useNavigate } from "react-router"; 6 6 import { profileAtom } from "../../atoms/profile"; 7 7 import Dropbox from "../../components/Icons/Dropbox"; 8 8 import GoogleDrive from "../../components/Icons/GoogleDrive"; ··· 35 35 } 36 36 37 37 if (profile?.googledriveUser?.isBeta) { 38 - navigate("/googledrive"); 38 + navigate({ to: "/googledrive" }); 39 39 return; 40 40 } 41 41 ··· 62 62 } 63 63 64 64 if (profile?.dropboxUser?.isBeta) { 65 - navigate("/dropbox"); 65 + navigate({ to: "/dropbox" }); 66 66 return; 67 67 } 68 68
+6 -3
apps/web/src/layouts/ExternalLinks/ExternalLinks.tsx
··· 1 1 import styled from "@emotion/styled"; 2 2 import { Spotify } from "@styled-icons/boxicons-logos"; 3 + import { useRouter } from "@tanstack/react-router"; 3 4 import { LabelLarge } from "baseui/typography"; 4 5 import { useAtomValue } from "jotai"; 5 - import { useLocation } from "react-router"; 6 6 import { songAtom } from "../../atoms/song"; 7 7 8 8 const Link = styled.a` ··· 15 15 16 16 function ExternalLinks() { 17 17 const song = useAtomValue(songAtom); 18 - const location = useLocation(); 19 - const { pathname } = location; 18 + const { 19 + state: { 20 + location: { pathname }, 21 + }, 22 + } = useRouter(); 20 23 const display = 21 24 pathname.includes("app.rocksky.scrobble") || 22 25 pathname.includes("app.rocksky.song");
+4 -7
apps/web/src/layouts/Main.tsx
··· 1 1 import styled from "@emotion/styled"; 2 + import { useSearch } from "@tanstack/react-router"; 2 3 import { Button } from "baseui/button"; 3 4 import { Input } from "baseui/input"; 4 5 import { PLACEMENT, ToasterContainer } from "baseui/toast"; 5 6 import { LabelMedium } from "baseui/typography"; 6 7 import { useAtomValue } from "jotai"; 7 8 import { useEffect, useState } from "react"; 8 - import { useLocation } from "react-router"; 9 9 import { profileAtom } from "../atoms/profile"; 10 10 import ScrobblesAreaChart from "../components/ScrobblesAreaChart"; 11 11 import StickyPlayer from "../components/StickyPlayer"; ··· 69 69 const { children } = props; 70 70 const withRightPane = props.withRightPane ?? true; 71 71 const [handle, setHandle] = useState(""); 72 - const { search } = useLocation(); 73 72 const jwt = localStorage.getItem("token"); 74 73 const profile = useAtomValue(profileAtom); 75 74 const [token, setToken] = useState<string | null>(null); 75 + const { did, cli } = useSearch({ strict: false }); 76 76 77 77 useEffect(() => { 78 - const query = new URLSearchParams(search); 79 - const did = query.get("did"); 80 - 81 78 if (did && did !== "null") { 82 79 localStorage.setItem("did", did); 83 80 ··· 93 90 localStorage.setItem("token", data.token); 94 91 setToken(data.token); 95 92 96 - if (query.get("cli")) { 93 + if (cli) { 97 94 await fetch("http://localhost:6996/token", { 98 95 method: "POST", 99 96 headers: { ··· 113 110 fetchToken(); 114 111 } 115 112 // eslint-disable-next-line react-hooks/exhaustive-deps 116 - }, [search]); 113 + }, []); 117 114 118 115 useProfile(token || localStorage.getItem("token")); 119 116
+11 -5
apps/web/src/layouts/Navbar/Navbar.tsx
··· 1 1 import styled from "@emotion/styled"; 2 2 import { Copy } from "@styled-icons/ionicons-outline"; 3 3 import { useQuery } from "@tanstack/react-query"; 4 + import { Link, useNavigate } from "@tanstack/react-router"; 4 5 import { Avatar } from "baseui/avatar"; 5 6 import { Checkbox, LABEL_PLACEMENT, STYLE_TYPE } from "baseui/checkbox"; 6 7 import { NestedMenus, StatefulMenu } from "baseui/menu"; ··· 14 15 import numeral from "numeral"; 15 16 import * as R from "ramda"; 16 17 import { useEffect, useMemo, useState } from "react"; 17 - import { Link, useNavigate } from "react-router"; 18 18 import { profileAtom } from "../../atoms/profile"; 19 19 import { themeAtom } from "../../atoms/theme"; 20 20 import { API_URL } from "../../consts"; ··· 120 120 <div className="flex items-center justify-center bg-[var(--color-background)] pl-[20px] pr-[20px]"> 121 121 <div className="flex flex-col items-center"> 122 122 <div className="mb-[5px]"> 123 - <Link to={`/profile/${profile.handle}`}> 123 + <Link to="/profile/$did" params={{ did: profile.handle }}> 124 124 <Avatar 125 125 src={profile.avatar} 126 126 name={profile.displayName} ··· 130 130 </div> 131 131 132 132 <Link 133 - to={`/profile/${profile.handle}`} 133 + to="/profile/$did" 134 + params={{ did: profile.handle }} 134 135 className="no-underline" 135 136 > 136 137 <LabelMedium className="text-center text-[20px] !text-[var(--color-text)]"> ··· 232 233 onItemSelect={({ item }) => { 233 234 switch (item.id) { 234 235 case "profile": 235 - navigate(`/profile/${profile.handle}`); 236 + navigate({ 237 + to: "/profile/$did", 238 + params: { did: profile.handle }, 239 + }); 236 240 break; 237 241 case "api-applications": 238 - navigate("/apikeys"); 242 + navigate({ 243 + to: "/apikeys", 244 + }); 239 245 break; 240 246 case "signout": 241 247 setProfile(null);
+4 -2
apps/web/src/layouts/Search/Search.tsx
··· 2 2 import styled from "@emotion/styled"; 3 3 import { zodResolver } from "@hookform/resolvers/zod"; 4 4 import { Search as SearchIcon } from "@styled-icons/evaicons-solid"; 5 + import { Link as DefaultLink } from "@tanstack/react-router"; 5 6 import { Input } from "baseui/input"; 6 7 import { PLACEMENT, Popover } from "baseui/popover"; 7 8 import _ from "lodash"; 8 9 import { useEffect, useState } from "react"; 9 10 import { Controller, useForm } from "react-hook-form"; 10 - import { Link as DefaultLink } from "react-router"; 11 11 import z from "zod"; 12 12 import Artist from "../../components/Icons/Artist"; 13 13 import Disc from "../../components/Icons/Disc"; ··· 108 108 (item.name || item.title) && 109 109 item._federation.indexUid !== "users" && ( 110 110 <Link 111 - to={`/${item.uri?.split("at://")[1]}`} 111 + to={`/${item.uri 112 + ?.split("at://")[1] 113 + .replace("app.rocksky.", "")}`} 112 114 key={item.id} 113 115 > 114 116 <div
+17 -2
apps/web/src/main.tsx
··· 1 1 import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; 2 + import { createRouter, RouterProvider } from "@tanstack/react-router"; 2 3 import { BaseProvider, createLightTheme } from "baseui"; 3 4 import { PLACEMENT, SnackbarProvider } from "baseui/snackbar"; 4 5 import { ToasterContainer } from "baseui/toast/toaster"; 6 + import dayjs from "dayjs"; 7 + import relativeTime from "dayjs/plugin/relativeTime"; 8 + import utc from "dayjs/plugin/utc"; 5 9 import { PostHogProvider } from "posthog-js/react"; 6 10 import { createRoot } from "react-dom/client"; 7 11 import { Client as Styletron } from "styletron-engine-monolithic"; 8 12 import { Provider as StyletronProvider } from "styletron-react"; 9 - import App from "./App.tsx"; 10 13 import "./index.css"; 14 + import { routeTree } from "./routeTree.gen.ts"; 15 + 16 + dayjs.extend(relativeTime); 17 + dayjs.extend(utc); 11 18 12 19 const primitives = { 13 20 primaryFontFamily: "RockfordSansRegular", ··· 18 25 19 26 const queryClient = new QueryClient(); 20 27 28 + const router = createRouter({ routeTree }); 29 + 30 + declare module "@tanstack/react-router" { 31 + interface Register { 32 + router: typeof router; 33 + } 34 + } 35 + 21 36 createRoot(document.getElementById("root")!).render( 22 37 //<StrictMode> 23 38 <QueryClientProvider client={queryClient}> ··· 31 46 api_host: "https://us.i.posthog.com", 32 47 }} 33 48 > 34 - <App /> 49 + <RouterProvider router={router} /> 35 50 </PostHogProvider> 36 51 </SnackbarProvider> 37 52 </ToasterContainer>
+9 -7
apps/web/src/pages/album/Album.tsx
··· 1 1 import styled from "@emotion/styled"; 2 2 import { ExternalLink } from "@styled-icons/evaicons-solid"; 3 + import { Link as DefaultLink, useParams } from "@tanstack/react-router"; 3 4 import { TableBuilder, TableBuilderColumn } from "baseui/table-semantic"; 4 5 import { 5 6 HeadingMedium, ··· 11 12 import numeral from "numeral"; 12 13 import { useEffect, useState } from "react"; 13 14 import ContentLoader from "react-content-loader"; 14 - import { Link as DefaultLink, useParams } from "react-router"; 15 15 import Disc from "../../components/Icons/Disc"; 16 16 import Shout from "../../components/Shout/Shout"; 17 17 import SongCover from "../../components/SongCover"; ··· 49 49 50 50 const Album = () => { 51 51 const { formatTime } = useTimeFormat(); 52 - const { did, rkey } = useParams<{ did: string; rkey: string }>(); 52 + const { did, rkey } = useParams({ strict: false }); 53 53 const { data, isLoading, isError } = useAlbumQuery(did!, rkey!); 54 54 55 55 const [disc, setDisc] = useState(1); ··· 140 140 {album.title} 141 141 </HeadingMedium> 142 142 {album.artistUri && ( 143 - <Link to={`/${album.artistUri.split("at://")[1]}`}> 143 + <Link 144 + to={`/${album.artistUri.split("at://")[1].replace("app.rocksky.", "")}`} 145 + > 144 146 <LabelLarge margin={0} className="!text-[var(--color-text)]"> 145 147 {album.artist} 146 148 </LabelLarge> ··· 261 263 <div> 262 264 {row.uri && ( 263 265 <Link 264 - to={`/${row.uri.split("at://")[1]}`} 266 + to={`/${row.uri.split("at://")[1].replace("app.rocksky.", "")}`} 265 267 className="!text-[var(--color-text)]" 266 268 > 267 269 {row.title} ··· 276 278 <div> 277 279 {row.artistUri && ( 278 280 <Link 279 - to={`/${row.artistUri.split("at://")[1]}`} 281 + to={`/${row.artistUri.split("at://")[1].replace("app.rocksky.", "")}`} 280 282 className="!text-[var(--color-text-muted)]" 281 283 > 282 284 {row.albumArtist} ··· 362 364 <div> 363 365 {row.uri && ( 364 366 <Link 365 - to={`/${row.uri.split("at://")[1]}`} 367 + to={`/${row.uri.split("at://")[1].replace("app.rocksky.", "")}`} 366 368 className="!text-[var(--color-text)]" 367 369 > 368 370 {row.title} ··· 377 379 <div> 378 380 {row.artistUri && ( 379 381 <Link 380 - to={`/${row.artistUri.split("at://")[1]}`} 382 + to={`/${row.artistUri.split("at://")[1].replace("app.rocksky.", "")}`} 381 383 className="!text-[var(--color-text-muted)]" 382 384 > 383 385 {row.albumArtist}
+2 -2
apps/web/src/pages/apikeys/ApiKeys.tsx
··· 1 1 import { zodResolver } from "@hookform/resolvers/zod"; 2 2 import { Plus } from "@styled-icons/evaicons-solid"; 3 3 import { Copy, Trash } from "@styled-icons/ionicons-outline"; 4 + import { useNavigate } from "@tanstack/react-router"; 4 5 import { Button } from "baseui/button"; 5 6 import { Input } from "baseui/input"; 6 7 import { Modal, ModalBody, ModalFooter, ModalHeader } from "baseui/modal"; ··· 11 12 import copy from "copy-to-clipboard"; 12 13 import { useState } from "react"; 13 14 import { Controller, useForm } from "react-hook-form"; 14 - import { useNavigate } from "react-router"; 15 15 import z from "zod"; 16 16 import { 17 17 useApikeysQuery, ··· 90 90 }; 91 91 92 92 if (!jwt) { 93 - navigate("/"); 93 + navigate({ to: "/" }); 94 94 } 95 95 96 96 return (
+10 -4
apps/web/src/pages/artist/Albums/Albums.tsx
··· 1 1 import styled from "@emotion/styled"; 2 + import { Link as DefaultLink } from "@tanstack/react-router"; 2 3 import { BlockProps } from "baseui/block"; 3 4 import { FlexGrid, FlexGridItem } from "baseui/flex-grid"; 4 5 import { HeadingSmall, LabelMedium, LabelSmall } from "baseui/typography"; 5 - import { Link as DefaultLink } from "react-router"; 6 6 import SongCover from "../../../components/SongCover"; 7 7 8 8 const Link = styled(DefaultLink)` ··· 46 46 props.topAlbums.map((album: any) => ( 47 47 <FlexGridItem {...itemProps} key={album.id}> 48 48 {album.uri && ( 49 - <Link to={`/${album.uri.split("at://")[1]}`}> 49 + <Link 50 + to={`/${album.uri.split("at://")[1].replace("app.rocksky.", "")}`} 51 + > 50 52 <SongCover cover={album.albumArt} size={230} /> 51 53 </Link> 52 54 )} 53 55 {!album.uri && <SongCover cover={album.albumArt} size={230} />} 54 56 {album.uri && ( 55 - <Link to={`/${album.uri.split("at://")[1]}`}> 57 + <Link 58 + to={`/${album.uri.split("at://")[1].replace("app.rocksky.", "")}`} 59 + > 56 60 <LabelMedium className="!text-[var(--color-text)]"> 57 61 {album.title} 58 62 </LabelMedium> ··· 60 64 )} 61 65 {!album.uri && <LabelMedium>{album.title}</LabelMedium>} 62 66 {album.artistUri && ( 63 - <Link to={`/${album.artistUri.split("at://")[1]}`}> 67 + <Link 68 + to={`/${album.artistUri.split("at://")[1]?.replace("app.rocksky.", "")}`} 69 + > 64 70 <LabelSmall className="!text-[var(--color-text-muted)]"> 65 71 {album.artist} 66 72 </LabelSmall>
+2 -2
apps/web/src/pages/artist/Artist.tsx
··· 1 1 import styled from "@emotion/styled"; 2 2 import { ExternalLink } from "@styled-icons/evaicons-solid"; 3 + import { useParams } from "@tanstack/react-router"; 3 4 import { Avatar } from "baseui/avatar"; 4 5 import { HeadingMedium, HeadingXSmall, LabelMedium } from "baseui/typography"; 5 6 import { useAtomValue, useSetAtom } from "jotai"; 6 7 import numeral from "numeral"; 7 8 import { useEffect, useState } from "react"; 8 - import { useParams } from "react-router"; 9 9 import { artistAtom } from "../../atoms/artist"; 10 10 import ArtistIcon from "../../components/Icons/Artist"; 11 11 import Shout from "../../components/Shout/Shout"; ··· 26 26 `; 27 27 28 28 const Artist = () => { 29 - const { did, rkey } = useParams<{ did: string; rkey: string }>(); 29 + const { did, rkey } = useParams({ strict: false }); 30 30 31 31 const uri = `at://${did}/app.rocksky.artist/${rkey}`; 32 32 const artistResult = useArtistQuery(did!, rkey!);
+6 -4
apps/web/src/pages/artist/PopularSongs/PopularSongs.tsx
··· 1 1 import styled from "@emotion/styled"; 2 + import { Link as DefaultLink } from "@tanstack/react-router"; 2 3 import { TableBuilder, TableBuilderColumn } from "baseui/table-semantic"; 3 4 import { HeadingSmall } from "baseui/typography"; 4 - import { Link as DefaultLink } from "react-router"; 5 5 6 6 const Link = styled(DefaultLink)` 7 7 color: inherit; ··· 94 94 </div> 95 95 </div> 96 96 {row.albumUri && ( 97 - <Link to={`/${row.albumUri?.split("at://")[1]}`}> 97 + <Link 98 + to={`/${row.albumUri?.split("at://")[1].replace("app.rocksky.", "")}`} 99 + > 98 100 {!!row.albumArt && ( 99 101 <img 100 102 src={row.albumArt} ··· 123 125 )} 124 126 <div className="flex flex-col"> 125 127 <Link 126 - to={`/${row.uri?.split("at://")[1]}`} 128 + to={`/${row.uri?.split("at://")[1].replace("app.rocksky.", "")}`} 127 129 className="!text-[var(--color-text)]" 128 130 > 129 131 {row.title} 130 132 </Link> 131 133 {row.artistUri && ( 132 134 <Link 133 - to={`/${row.artistUri?.split("at://")[1]}`} 135 + to={`/${row.artistUri?.split("at://")[1].replace("app.rocksky.", "")}`} 134 136 className="!text-[var(--color-text-muted)]" 135 137 > 136 138 {row.albumArtist}
+8 -5
apps/web/src/pages/dropbox/Dropbox.tsx
··· 1 1 /* eslint-disable @typescript-eslint/no-explicit-any */ 2 2 import { Folder2, MusicNoteBeamed } from "@styled-icons/bootstrap"; 3 + import { Link, useRouter } from "@tanstack/react-router"; 3 4 import { createColumnHelper } from "@tanstack/react-table"; 4 5 import { Breadcrumbs } from "baseui/breadcrumbs"; 5 6 import { HeadingMedium } from "baseui/typography"; ··· 7 8 import _ from "lodash"; 8 9 import { useEffect, useState } from "react"; 9 10 import ContentLoader from "react-content-loader"; 10 - import { Link, useLocation } from "react-router"; 11 11 import { dropboxAtom } from "../../atoms/dropbox"; 12 12 import Table from "../../components/Table"; 13 13 import { AUDIO_EXTENSIONS } from "../../consts"; ··· 35 35 36 36 const { getFiles, getFile, getTemporaryLink } = useDropbox(); 37 37 const [loading, setLoading] = useState(true); 38 - const { pathname } = useLocation(); 38 + const { 39 + state: { 40 + location: { pathname }, 41 + }, 42 + } = useRouter(); 39 43 40 44 const playFile = async (id: string) => { 41 45 const { link } = await getTemporaryLink(id); ··· 149 153 <Breadcrumbs> 150 154 {parent_dir && current_dir !== "Music" && ( 151 155 <Link 152 - to={ 153 - current_dir === "Music" ? `/dropbox` : `/dropbox/${parent_id}` 154 - } 156 + to={current_dir === "Music" ? `/dropbox` : `/dropbox/$id`} 157 + params={{ id: parent_id }} 155 158 className="!text-[var(--color-text)]" 156 159 > 157 160 {parent_dir}
+3 -2
apps/web/src/pages/dropbox/DropboxWithId.tsx
··· 1 - import { useParams } from "react-router"; 1 + import { useParams } from "@tanstack/react-router"; 2 2 import Dropbox from "./Dropbox"; 3 3 4 4 function DropboxWithId() { 5 - const { id } = useParams<{ id: string }>(); 5 + const { id } = useParams({ strict: false }); 6 + console.log(">> id", id); 6 7 return <Dropbox fileId={id} />; 7 8 } 8 9
+1 -1
apps/web/src/pages/dropbox/styles.tsx
··· 1 1 import styled from "@emotion/styled"; 2 - import { Link } from "react-router"; 2 + import { Link } from "@tanstack/react-router"; 3 3 4 4 export const Directory = styled(Link)` 5 5 color: var(--color-text) !important;
+8 -5
apps/web/src/pages/googledrive/GoogleDrive.tsx
··· 1 1 /* eslint-disable @typescript-eslint/no-explicit-any */ 2 2 import { Folder2, MusicNoteBeamed } from "@styled-icons/bootstrap"; 3 + import { Link, useRouter } from "@tanstack/react-router"; 3 4 import { createColumnHelper } from "@tanstack/react-table"; 4 5 import { Breadcrumbs } from "baseui/breadcrumbs"; 5 6 import { HeadingMedium } from "baseui/typography"; ··· 7 8 import _ from "lodash"; 8 9 import { useEffect, useState } from "react"; 9 10 import ContentLoader from "react-content-loader"; 10 - import { Link, useLocation } from "react-router"; 11 11 import googleDriveAtom from "../../atoms/googledrive"; 12 12 import Table from "../../components/Table"; 13 13 import { AUDIO_EXTENSIONS } from "../../consts"; ··· 32 32 33 33 const { getFiles, getFile } = useGoogleDrive(); 34 34 const [loading, setLoading] = useState(true); 35 - const { pathname } = useLocation(); 35 + const { 36 + state: { 37 + location: { pathname }, 38 + }, 39 + } = useRouter(); 36 40 37 41 const columns = [ 38 42 columnHelper.accessor("name", { ··· 146 150 {parent_dir && current_dir !== "Music" && ( 147 151 <Link 148 152 to={ 149 - current_dir === "Music" 150 - ? `/googledrive` 151 - : `/googledrive/${parent_id}` 153 + current_dir === "Music" ? "/googledrive" : "/googledrive/$id" 152 154 } 155 + params={{ id: parent_id || "/Music" }} 153 156 className="!text-[var(--color-text)]" 154 157 > 155 158 {parent_dir}
+2 -2
apps/web/src/pages/googledrive/GoogleDriveWithId.tsx
··· 1 - import { useParams } from "react-router"; 1 + import { useParams } from "@tanstack/react-router"; 2 2 import GoogleDrive from "./GoogleDrive"; 3 3 4 4 function GoogleDriveWithId() { 5 - const { id } = useParams<{ id: string }>(); 5 + const { id } = useParams({ strict: false }); 6 6 return <GoogleDrive fileId={id} />; 7 7 } 8 8
+1 -1
apps/web/src/pages/googledrive/styles.tsx
··· 1 1 import styled from "@emotion/styled"; 2 - import { Link } from "react-router"; 2 + import { Link } from "@tanstack/react-router"; 3 3 4 4 export const Directory = styled(Link)` 5 5 color: var(--color-text) !important;
+8 -2
apps/web/src/pages/home/feed/Feed.tsx
··· 1 1 import styled from "@emotion/styled"; 2 + import { Link } from "@tanstack/react-router"; 2 3 import { BlockProps } from "baseui/block"; 3 4 import { FlexGrid, FlexGridItem } from "baseui/flex-grid"; 4 5 import { StatefulTooltip } from "baseui/tooltip"; ··· 6 7 import dayjs from "dayjs"; 7 8 import relativeTime from "dayjs/plugin/relativeTime"; 8 9 import ContentLoader from "react-content-loader"; 9 - import { Link } from "react-router"; 10 10 import Handle from "../../../components/Handle"; 11 11 import SongCover from "../../../components/SongCover"; 12 12 import { useFeedQuery } from "../../../hooks/useFeed"; ··· 75 75 // eslint-disable-next-line @typescript-eslint/no-explicit-any 76 76 data.map((song: any) => ( 77 77 <FlexGridItem {...itemProps} key={song.id}> 78 - <Link to={`/${song.uri?.split("at://")[1]}`}> 78 + <Link 79 + to="/$did/scrobble/$rkey" 80 + params={{ 81 + did: song.uri?.split("at://")[1]?.split("/")[0] || "", 82 + rkey: song.uri?.split("/").pop() || "", 83 + }} 84 + > 79 85 <SongCover 80 86 cover={song.cover} 81 87 artist={song.artist}
+1 -1
apps/web/src/pages/home/nowplayings/NowPlayings.tsx
··· 1 1 import styled from "@emotion/styled"; 2 2 import { ChevronLeft, ChevronRight } from "@styled-icons/evaicons-solid"; 3 + import { Link as DefaultLink } from "@tanstack/react-router"; 3 4 import { Modal, ModalBody, ModalHeader, ROLE } from "baseui/modal"; 4 5 import { ProgressBar } from "baseui/progress-bar"; 5 6 import { StatefulTooltip } from "baseui/tooltip"; ··· 7 8 import relativeTime from "dayjs/plugin/relativeTime"; 8 9 import utc from "dayjs/plugin/utc"; 9 10 import { useEffect, useState } from "react"; 10 - import { Link as DefaultLink } from "react-router"; 11 11 import { useNowPlayingsQuery } from "../../../hooks/useNowPlaying"; 12 12 import styles from "./styles"; 13 13
+3 -6
apps/web/src/pages/loading/Loading.tsx
··· 1 + import { useSearch } from "@tanstack/react-router"; 1 2 import { Spinner } from "baseui/spinner"; 2 3 import { useEffect } from "react"; 3 - import { useLocation } from "react-router"; 4 4 import { API_URL } from "../../consts"; 5 5 6 6 function Loading() { 7 - const { search } = useLocation(); 7 + const { handle } = useSearch({ strict: false }); 8 8 9 9 useEffect(() => { 10 - const query = new URLSearchParams(search); 11 - const handle = query.get("handle"); 12 - 13 10 if (handle) { 14 11 window.location.href = `${API_URL}/login?handle=${handle}`; 15 12 } 16 - }, [search]); 13 + }, [handle]); 17 14 18 15 return ( 19 16 <div className="flex justify-center items-center h-screen bg-[#fff] fixed top-0 left-0 w-full">
+4 -5
apps/web/src/pages/playlist/Playlist.tsx
··· 1 1 import styled from "@emotion/styled"; 2 2 import { ExternalLink } from "@styled-icons/evaicons-solid"; 3 + import { Link as DefaultLink, useParams } from "@tanstack/react-router"; 3 4 import { Avatar } from "baseui/avatar"; 4 5 import { TableBuilder, TableBuilderColumn } from "baseui/table-semantic"; 5 6 import { HeadingMedium, LabelMedium } from "baseui/typography"; 6 7 import { useEffect, useState } from "react"; 7 8 import ContentLoader from "react-content-loader"; 8 - import { useParams } from "react-router"; 9 - import { Link as DefaultLink } from "react-router-dom"; 10 9 import Disc from "../../components/Icons/Disc"; 11 10 import SongCover from "../../components/SongCover"; 12 11 import { useTimeFormat } from "../../hooks/useFormat"; ··· 43 42 }; 44 43 45 44 function Playlist() { 46 - const { did, rkey } = useParams<{ did: string; rkey: string }>(); 45 + const { did, rkey } = useParams({ strict: false }); 47 46 const { formatTime } = useTimeFormat(); 48 47 const [playlist, setPlaylist] = useState<{ 49 48 id: string; ··· 252 251 <div> 253 252 {row.uri && ( 254 253 <Link 255 - to={`/${row.uri.split("at://")[1]}`} 254 + to={`/${row.uri.split("at://")[1].replace("app.rocksky.", "")}`} 256 255 className="!text-[var(--color-text)]" 257 256 > 258 257 {row.title} ··· 267 266 <div> 268 267 {row.artistUri && ( 269 268 <Link 270 - to={`/${row.artistUri.split("at://")[1]}`} 269 + to={`/${row.artistUri.split("at://")[1].replace("app.rocksky.", "")}`} 271 270 className="!text-[var(--color-text-muted)]" 272 271 > 273 272 {row.albumArtist}
+4 -6
apps/web/src/pages/profile/Profile.tsx
··· 1 1 import styled from "@emotion/styled"; 2 2 import { ExternalLink } from "@styled-icons/evaicons-solid"; 3 + import { useParams, useSearch } from "@tanstack/react-router"; 3 4 import { Avatar } from "baseui/avatar"; 4 5 import { Tab, Tabs } from "baseui/tabs-motion"; 5 6 import { HeadingMedium, LabelLarge } from "baseui/typography"; 6 7 import dayjs from "dayjs"; 7 8 import { useAtom, useSetAtom } from "jotai"; 8 9 import { Key, useEffect, useState } from "react"; 9 - import { useParams, useSearchParams } from "react-router"; 10 10 import { profilesAtom } from "../../atoms/profiles"; 11 11 import { userAtom } from "../../atoms/user"; 12 12 import Shout from "../../components/Shout/Shout"; ··· 27 27 function Profile() { 28 28 const [profiles, setProfiles] = useAtom(profilesAtom); 29 29 const [activeKey, setActiveKey] = useState<Key>("0"); 30 - const { did } = useParams<{ did: string }>(); 30 + const { did } = useParams({ strict: false }); 31 31 const profile = useProfileByDidQuery(did!); 32 32 const setUser = useSetAtom(userAtom); 33 - const [searchParams] = useSearchParams(); 33 + const { tab } = useSearch({ strict: false }); 34 34 35 35 useEffect(() => { 36 - const tab = searchParams.get("tab"); 37 - 38 36 if (!tab) { 39 37 return; 40 38 } 41 39 42 40 setActiveKey(1); 43 - }, [searchParams]); 41 + }, [tab]); 44 42 45 43 useEffect(() => { 46 44 if (profile.isLoading || profile.isError) {
+4 -5
apps/web/src/pages/profile/library/Library.tsx
··· 1 + import { useSearch } from "@tanstack/react-router"; 1 2 import { Tab, Tabs } from "baseui/tabs-motion"; 2 3 import { HeadingSmall } from "baseui/typography"; 3 4 import { Key, useEffect, useState } from "react"; 4 - import { useSearchParams } from "react-router"; 5 5 import RecentTracks from "../overview/recenttracks"; 6 6 import TopArtists from "../overview/topartists"; 7 7 import TopTracks from "../overview/toptracks"; ··· 9 9 10 10 function Library() { 11 11 const [activeKey, setActiveKey] = useState<Key>("0"); 12 - const [searchParams] = useSearchParams(); 12 + const { tab } = useSearch({ strict: false }); 13 + console.log("tab", tab); 13 14 14 15 useEffect(() => { 15 - const tab = searchParams.get("tab"); 16 - 17 16 if (!tab) { 18 17 return; 19 18 } 20 19 21 20 setActiveKey(tab); 22 - }, [searchParams]); 21 + }, [tab]); 23 22 24 23 return ( 25 24 <>
+7 -5
apps/web/src/pages/profile/library/albums/Albums.tsx
··· 1 1 import { css } from "@emotion/react"; 2 2 import styled from "@emotion/styled"; 3 + import { Link as DefaultLink, useParams } from "@tanstack/react-router"; 3 4 import { Pagination } from "baseui/pagination"; 4 5 import { TableBuilder, TableBuilderColumn } from "baseui/table-semantic"; 5 6 import { HeadingXSmall, LabelSmall } from "baseui/typography"; 6 7 import { useAtomValue, useSetAtom } from "jotai"; 7 8 import numeral from "numeral"; 8 9 import { useEffect, useMemo, useState } from "react"; 9 - import { Link as DefaultLink, useParams } from "react-router"; 10 10 import { themeAtom } from "../../../../atoms/theme"; 11 11 import { topAlbumsAtom } from "../../../../atoms/topAlbums"; 12 12 import { userAtom } from "../../../../atoms/user"; ··· 55 55 const setTopAlbums = useSetAtom(topAlbumsAtom); 56 56 const topAlbums = useAtomValue(topAlbumsAtom); 57 57 const { darkMode } = useAtomValue(themeAtom); 58 - const { did } = useParams<{ did: string }>(); 58 + const { did } = useParams({ strict: false }); 59 59 const profileStats = useProfileStatsByDidQuery(did!); 60 60 const [currentPage, setCurrentPage] = useState(1); 61 61 const albumsResult = useAlbumsQuery(did!, (currentPage - 1) * size, size); ··· 158 158 </div> 159 159 </div> 160 160 {row.uri && ( 161 - <Link to={`/${row.uri?.split("at://")[1]}`}> 161 + <Link 162 + to={`/${row.uri?.split("at://")[1].replace("app.rocksky.", "")}`} 163 + > 162 164 {!!row.albumArt && ( 163 165 <img 164 166 src={row.albumArt} ··· 187 189 )} 188 190 <div className="flex flex-col"> 189 191 <Link 190 - to={`/${row.uri?.split("at://")[1]}`} 192 + to={`/${row.uri?.split("at://")[1].replace("app.rocksky.", "")}`} 191 193 className="!text-[var(--color-text)]" 192 194 > 193 195 {row.title} 194 196 </Link> 195 197 {row.artistUri && ( 196 198 <Link 197 - to={`/${row.artistUri?.split("at://")[1]}`} 199 + to={`/${row.artistUri?.split("at://")[1].replace("app.rocksky.", "")}`} 198 200 className="!text-[var(--color-text-muted)]" 199 201 > 200 202 {row.artist}
+7 -5
apps/web/src/pages/profile/lovedtracks/LovedTracks.tsx
··· 1 1 import styled from "@emotion/styled"; 2 + import { Link as DefaultLink, useParams } from "@tanstack/react-router"; 2 3 import { Pagination } from "baseui/pagination"; 3 4 import { TableBuilder, TableBuilderColumn } from "baseui/table-semantic"; 4 5 import { StatefulTooltip } from "baseui/tooltip"; ··· 7 8 import { useAtomValue, useSetAtom } from "jotai"; 8 9 import numeral from "numeral"; 9 10 import { useEffect, useMemo, useState } from "react"; 10 - import { Link as DefaultLink, useParams } from "react-router"; 11 11 import { lovedTracksAtom } from "../../../atoms/lovedTracks"; 12 12 import { userAtom } from "../../../atoms/user"; 13 13 import { useLovedTracksQuery } from "../../../hooks/useLibrary"; ··· 38 38 39 39 function LovedTracks() { 40 40 const size = 50; 41 - const { did } = useParams<{ did: string }>(); 41 + const { did } = useParams({ strict: false }); 42 42 const lovedTracks = useAtomValue(lovedTracksAtom); 43 43 const setLovedTracks = useSetAtom(lovedTracksAtom); 44 44 const [currentPage, setCurrentPage] = useState(1); ··· 133 133 {(row: Row) => ( 134 134 <div className="flex flex-row items-center"> 135 135 {row.albumUri && ( 136 - <Link to={`/${row.albumUri?.split("at://")[1]}`}> 136 + <Link 137 + to={`/${row.albumUri?.split("at://")[1].replace("app.rocksky.", "")}`} 138 + > 137 139 {!!row.albumArt && ( 138 140 <img 139 141 src={row.albumArt} ··· 166 168 > 167 169 {row.uri && ( 168 170 <Link 169 - to={`/${row.uri?.split("at://")[1]}`} 171 + to={`/${row.uri?.split("at://")[1].replace("app.rocksky.", "")}`} 170 172 className="!text-[var(--color-text)]" 171 173 > 172 174 {row.title} ··· 175 177 {!row.uri && <div>{row.title}</div>} 176 178 {row.artistUri && ( 177 179 <Link 178 - to={`/${row.artistUri?.split("at://")[1]}`} 180 + to={`/${row.artistUri?.split("at://")[1].replace("app.rocksky.", "")}`} 179 181 className="text-[var(--color-text-muted)]" 180 182 > 181 183 {row.albumArtist}
+2 -2
apps/web/src/pages/profile/overview/Overview.tsx
··· 1 + import { useParams } from "@tanstack/react-router"; 1 2 import { useAtomValue, useSetAtom } from "jotai"; 2 3 import { useEffect } from "react"; 3 - import { useParams } from "react-router"; 4 4 import { statsAtom } from "../../../atoms/stats"; 5 5 import Stats from "../../../components/Stats/Stats"; 6 6 import { useProfileStatsByDidQuery } from "../../../hooks/useProfile"; ··· 10 10 import TopTracks from "./toptracks"; 11 11 12 12 function Overview() { 13 - const { did } = useParams<{ did: string }>(); 13 + const { did } = useParams({ strict: false }); 14 14 const profileStats = useProfileStatsByDidQuery(did!); 15 15 const setStats = useSetAtom(statsAtom); 16 16 const stats = useAtomValue(statsAtom);
+7 -5
apps/web/src/pages/profile/overview/recenttracks/RecentTracks.tsx
··· 1 1 import { css } from "@emotion/react"; 2 2 import styled from "@emotion/styled"; 3 + import { Link as DefaultLink, useParams } from "@tanstack/react-router"; 3 4 import { Pagination } from "baseui/pagination"; 4 5 import { TableBuilder, TableBuilderColumn } from "baseui/table-semantic"; 5 6 import { StatefulTooltip } from "baseui/tooltip"; ··· 8 9 import { useAtomValue, useSetAtom } from "jotai"; 9 10 import numeral from "numeral"; 10 11 import { useEffect, useMemo, useState } from "react"; 11 - import { Link as DefaultLink, useParams } from "react-router"; 12 12 import { recentTracksAtom } from "../../../../atoms/recentTracks"; 13 13 import { userAtom } from "../../../../atoms/user"; 14 14 import { ··· 63 63 size: 10, 64 64 ...props, 65 65 }; 66 - const { did } = useParams<{ did: string }>(); 66 + const { did } = useParams({ strict: false }); 67 67 const profileStats = useProfileStatsByDidQuery(did!); 68 68 const [currentPage, setCurrentPage] = useState(1); 69 69 const recentTracksResult = useRecentTracksByDidQuery( ··· 197 197 <TableBuilderColumn header="Title"> 198 198 {(row: Row) => ( 199 199 <div className="flex flex-row items-center"> 200 - <Link to={`/${row.albumUri?.split("at://")[1]}`}> 200 + <Link 201 + to={`/${row.albumUri?.split("at://")[1].replace("app.rocksky.", "")}`} 202 + > 201 203 <img 202 204 src={row.albumArt} 203 205 alt={row.title} ··· 207 209 </Link> 208 210 <div> 209 211 <Link 210 - to={`/${row.uri?.split("at://")[1]}`} 212 + to={`/${row.uri?.split("at://")[1].replace("app.rocksky.", "")}`} 211 213 className="!text-[var(--color-text)]" 212 214 > 213 215 {row.title} ··· 219 221 <TableBuilderColumn header="Artist"> 220 222 {(row: Row) => ( 221 223 <Link 222 - to={`/${row.artistUri?.split("at://")[1]}`} 224 + to={`/${row.artistUri?.split("at://")[1].replace("app.rocksky.", "")}`} 223 225 style={{ fontFamily: "RockfordSansLight" }} 224 226 className="!text-[var(--color-text)]" 225 227 >
+11 -5
apps/web/src/pages/profile/overview/topalbums/TopAlbums.tsx
··· 1 1 import styled from "@emotion/styled"; 2 + import { Link as DefaultLink, useParams } from "@tanstack/react-router"; 2 3 import { BlockProps } from "baseui/block"; 3 4 import { FlexGrid, FlexGridItem } from "baseui/flex-grid"; 4 5 import { HeadingSmall, LabelMedium, LabelSmall } from "baseui/typography"; 5 6 import { useAtomValue, useSetAtom } from "jotai"; 6 7 import { useEffect } from "react"; 7 - import { Link as DefaultLink, useParams } from "react-router"; 8 8 import { topAlbumsAtom } from "../../../../atoms/topAlbums"; 9 9 import { userAtom } from "../../../../atoms/user"; 10 10 import SongCover from "../../../../components/SongCover"; ··· 27 27 function TopAlbums() { 28 28 const setTopAlbums = useSetAtom(topAlbumsAtom); 29 29 const topAlbums = useAtomValue(topAlbumsAtom); 30 - const { did } = useParams<{ did: string }>(); 30 + const { did } = useParams({ strict: false }); 31 31 const albumsResult = useAlbumsQuery(did!); 32 32 const user = useAtomValue(userAtom); 33 33 ··· 75 75 // eslint-disable-next-line @typescript-eslint/no-explicit-any 76 76 topAlbums.map((album: any) => ( 77 77 <FlexGridItem {...itemProps} key={album.id}> 78 - <Link to={`/${album.uri?.split("at://")[1]}`}> 78 + <Link 79 + to={`/${album.uri?.split("at://")[1].replace("app.rocksky.", "")}`} 80 + > 79 81 <SongCover cover={album.albumArt} size={230} /> 80 82 </Link> 81 - <Link to={`/${album.uri?.split("at://")[1]}`}> 83 + <Link 84 + to={`/${album.uri?.split("at://")[1].replace("app.rocksky.", "")}`} 85 + > 82 86 <LabelMedium className="!text-[var(--color-text)]"> 83 87 {album.title} 84 88 </LabelMedium> 85 89 </Link> 86 90 {album.artistUri && ( 87 - <Link to={`/${album.artistUri.split("at://")[1]}`}> 91 + <Link 92 + to={`/${album.artistUri.split("at://")[1].replace("app.rocksky.", "")}`} 93 + > 88 94 <LabelSmall className="!text-[var(--color-text-muted)]"> 89 95 {album.artist} 90 96 </LabelSmall>
+14 -4
apps/web/src/pages/profile/overview/topartists/TopArtists.tsx
··· 1 1 import { css } from "@emotion/react"; 2 2 import styled from "@emotion/styled"; 3 + import { Link, useParams } from "@tanstack/react-router"; 3 4 import { Pagination } from "baseui/pagination"; 4 5 import { TableBuilder, TableBuilderColumn } from "baseui/table-semantic"; 5 6 import { HeadingSmall, HeadingXSmall, LabelSmall } from "baseui/typography"; 6 7 import { useAtomValue, useSetAtom } from "jotai"; 7 8 import numeral from "numeral"; 8 9 import { useEffect, useMemo, useState } from "react"; 9 - import { Link, useParams } from "react-router"; 10 10 import { themeAtom } from "../../../../atoms/theme"; 11 11 import { topArtistsAtom } from "../../../../atoms/topArtists"; 12 12 import { userAtom } from "../../../../atoms/user"; ··· 47 47 const setTopArtists = useSetAtom(topArtistsAtom); 48 48 const topArtists = useAtomValue(topArtistsAtom); 49 49 const { darkMode } = useAtomValue(themeAtom); 50 - const { did } = useParams<{ did: string }>(); 50 + const { did } = useParams({ strict: false }); 51 51 const profileStats = useProfileStatsByDidQuery(did!); 52 52 const [currentPage, setCurrentPage] = useState(1); 53 53 const artistsResult = useArtistsQuery(did!, (currentPage - 1) * size, size); ··· 158 158 : row.index + 1} 159 159 </div> 160 160 </div> 161 - <Link to={`/${row.uri?.split("at://")[1]}`}> 161 + <Link 162 + to="/$did/artist/$rkey" 163 + params={{ 164 + did: row.uri?.split("at://")[1]?.split("/")[0] || "", 165 + rkey: row.uri?.split("/").pop() || "", 166 + }} 167 + > 162 168 {!!row.picture && ( 163 169 <img 164 170 src={row.picture} ··· 177 183 </Link> 178 184 <div> 179 185 <Link 180 - to={`/${row.uri?.split("at://")[1]}`} 186 + to="/$did/artist/$rkey" 187 + params={{ 188 + did: row.uri?.split("at://")[1]?.split("/")[0] || "", 189 + rkey: row.uri?.split("/").pop() || "", 190 + }} 181 191 className="no-underline !text-[var(--color-text)]" 182 192 > 183 193 {row.name}
+7 -5
apps/web/src/pages/profile/overview/toptracks/TopTracks.tsx
··· 1 1 import { css } from "@emotion/react"; 2 2 import styled from "@emotion/styled"; 3 + import { Link as DefaultLink, useParams } from "@tanstack/react-router"; 3 4 import { Pagination } from "baseui/pagination"; 4 5 import { TableBuilder, TableBuilderColumn } from "baseui/table-semantic"; 5 6 import { HeadingSmall, HeadingXSmall, LabelSmall } from "baseui/typography"; 6 7 import { useAtomValue, useSetAtom } from "jotai"; 7 8 import numeral from "numeral"; 8 9 import { useEffect, useMemo, useState } from "react"; 9 - import { Link as DefaultLink, useParams } from "react-router"; 10 10 import { themeAtom } from "../../../../atoms/theme"; 11 11 import { topTracksAtom } from "../../../../atoms/topTracks"; 12 12 import { userAtom } from "../../../../atoms/user"; ··· 63 63 const setTopTracks = useSetAtom(topTracksAtom); 64 64 const topTracks = useAtomValue(topTracksAtom); 65 65 const { darkMode } = useAtomValue(themeAtom); 66 - const { did } = useParams<{ did: string }>(); 66 + const { did } = useParams({ strict: false }); 67 67 const profileStats = useProfileStatsByDidQuery(did!); 68 68 const [currentPage, setCurrentPage] = useState(1); 69 69 const tracksResult = useTracksQuery( ··· 181 181 </div> 182 182 </div> 183 183 {row.albumUri && ( 184 - <Link to={`/${row.albumUri?.split("at://")[1]}`}> 184 + <Link 185 + to={`/${row.albumUri?.split("at://")[1].replace("app.rocksky.", "")}`} 186 + > 185 187 {!!row.albumArt && ( 186 188 <img 187 189 src={row.albumArt} ··· 212 214 )} 213 215 <div className="flex flex-col"> 214 216 <Link 215 - to={`/${row.uri?.split("at://")[1]}`} 217 + to={`/${row.uri?.split("at://")[1]?.replace("app.rocksky.", "")}`} 216 218 className="!text-[var(--color-text)]" 217 219 > 218 220 {row.title} 219 221 </Link> 220 222 {row.artistUri && ( 221 223 <Link 222 - to={`/${row.artistUri?.split("at://")[1]}`} 224 + to={`/${row.artistUri?.split("at://")[1]?.replace("app.rocksky.", "")}`} 223 225 className="!text-[var(--color-text-muted)]" 224 226 > 225 227 {row.albumArtist}
+8 -4
apps/web/src/pages/profile/playlists/Playlists.tsx
··· 1 1 import styled from "@emotion/styled"; 2 + import { Link as DefaultLink, useParams } from "@tanstack/react-router"; 2 3 import { BlockProps } from "baseui/block"; 3 4 import { FlexGrid, FlexGridItem } from "baseui/flex-grid"; 4 5 import { HeadingSmall, LabelMedium, LabelSmall } from "baseui/typography"; 5 6 import { useAtomValue, useSetAtom } from "jotai"; 6 7 import { useEffect } from "react"; 7 - import { Link as DefaultLink, useParams } from "react-router"; 8 8 import { playlistsAtom } from "../../../atoms/playlists"; 9 9 import SongCover from "../../../components/SongCover"; 10 10 import { usePlaylistsQuery } from "../../../hooks/usePlaylists"; ··· 24 24 `; 25 25 26 26 function Playlists() { 27 - const { did } = useParams<{ did: string }>(); 27 + const { did } = useParams({ strict: false }); 28 28 const playlists = useAtomValue(playlistsAtom); 29 29 const setPlaylists = useSetAtom(playlistsAtom); 30 30 const playlistsData = usePlaylistsQuery(did!); ··· 58 58 // eslint-disable-next-line @typescript-eslint/no-explicit-any 59 59 playlists.map((playlist: any) => ( 60 60 <FlexGridItem {...itemProps} key={playlist.id}> 61 - <Link to={`/${playlist.uri?.split("at://")[1]}`}> 61 + <Link 62 + to={`/${playlist.uri?.split("at://")[1].replace("app.rocksky.", "")}`} 63 + > 62 64 <SongCover cover={playlist?.picture} /> 63 65 </Link> 64 - <Link to={`/${playlist.uri?.split("at://")[1]}`}> 66 + <Link 67 + to={`/${playlist.uri?.split("at://")[1].replace("app.rocksky.", "")}`} 68 + > 65 69 <LabelMedium className="!text-[var(--color-text)]"> 66 70 {playlist.name} 67 71 </LabelMedium>
+10 -4
apps/web/src/pages/song/PopularAlbums/PopularAlbums.tsx
··· 1 1 import styled from "@emotion/styled"; 2 + import { Link as DefaultLink } from "@tanstack/react-router"; 2 3 import { BlockProps } from "baseui/block"; 3 4 import { FlexGrid, FlexGridItem } from "baseui/flex-grid"; 4 5 import { HeadingXSmall, LabelMedium, LabelSmall } from "baseui/typography"; 5 - import { Link as DefaultLink } from "react-router"; 6 6 import SongCover from "../../../components/SongCover"; 7 7 8 8 const Link = styled(DefaultLink)` ··· 50 50 props.topAlbums.map((album: any) => ( 51 51 <FlexGridItem {...itemProps} key={album.id}> 52 52 {album.uri && ( 53 - <Link to={`/${album.uri.split("at://")[1]}`}> 53 + <Link 54 + to={`/${album.uri.split("at://")[1].replace("app.rocksky.", "")}`} 55 + > 54 56 <SongCover cover={album.albumArt} size={230} /> 55 57 </Link> 56 58 )} 57 59 {!album.uri && <SongCover cover={album.albumArt} size={230} />} 58 60 {album.uri && ( 59 - <Link to={`/${album.uri.split("at://")[1]}`}> 61 + <Link 62 + to={`/${album.uri.split("at://")[1].replace("app.rocksky.", "")}`} 63 + > 60 64 <LabelMedium className="!text-[var(--color-text)]"> 61 65 {album.title} 62 66 </LabelMedium> ··· 64 68 )} 65 69 {!album.uri && <LabelMedium>{album.title}</LabelMedium>} 66 70 {album.artistUri && ( 67 - <Link to={`/${album.artistUri.split("at://")[1]}`}> 71 + <Link 72 + to={`/${album.artistUri.split("at://")[1].replace("app.rocksky.", "")}`} 73 + > 68 74 <LabelSmall className="!text-[var(--color-text-muted)]"> 69 75 {album.artist} 70 76 </LabelSmall>
+11 -41
apps/web/src/pages/song/PopularTracks/PopularTracks.tsx
··· 1 1 import styled from "@emotion/styled"; 2 + import { Link as DefaultLink } from "@tanstack/react-router"; 2 3 import { TableBuilder, TableBuilderColumn } from "baseui/table-semantic"; 3 4 import { HeadingXSmall, LabelMedium } from "baseui/typography"; 4 - import { Link as DefaultLink } from "react-router"; 5 5 6 6 const Link = styled(DefaultLink)` 7 7 color: inherit; ··· 99 99 > 100 100 <TableBuilderColumn header="Name"> 101 101 {(row: Row) => ( 102 - <div 103 - style={{ 104 - display: "flex", 105 - flexDirection: "row", 106 - alignItems: "center", 107 - }} 108 - > 102 + <div className="flex flex-row items-center"> 109 103 <div> 110 104 <div className="!text-[var(--color-text)] mr-[20px]"> 111 105 {row.index + 1} 112 106 </div> 113 107 </div> 114 108 {row.albumUri && ( 115 - <Link to={`/${row.albumUri?.split("at://")[1]}`}> 109 + <Link 110 + to={`/${row.albumUri?.split("at://")[1].replace("app.rocksky.", "")}`} 111 + > 116 112 {!!row.albumArt && ( 117 113 <img 118 114 src={row.albumArt} 119 115 alt={row.title} 120 - style={{ 121 - width: 60, 122 - height: 60, 123 - marginRight: 20, 124 - borderRadius: 5, 125 - }} 116 + className="w-[60px] h-[60px] mr-[20px] rounded-[5px]" 126 117 /> 127 118 )} 128 119 {!row.albumArt && ( 129 - <div 130 - style={{ 131 - width: 60, 132 - height: 60, 133 - marginRight: 20, 134 - borderRadius: 5, 135 - backgroundColor: "rgba(243, 243, 243, 0.725)", 136 - }} 137 - /> 120 + <div className="w-[60px] h-[60px] rounded-[5px] mr-[20px] bg-[rgba(243, 243, 243, 0.725)]" /> 138 121 )} 139 122 </Link> 140 123 )} ··· 144 127 <img 145 128 src={row.albumArt} 146 129 alt={row.title} 147 - style={{ 148 - width: 60, 149 - height: 60, 150 - marginRight: 20, 151 - borderRadius: 5, 152 - }} 130 + className="w-[60px] h-[60px] mr-[20px] rounded-[5px]" 153 131 /> 154 132 )} 155 133 {!row.albumArt && ( 156 - <div 157 - style={{ 158 - width: 60, 159 - height: 60, 160 - marginRight: 20, 161 - borderRadius: 5, 162 - backgroundColor: "rgba(243, 243, 243, 0.725)", 163 - }} 164 - /> 134 + <div className="w-[60px] h-[60px] rounded-[5px] bg-[rgba(243, 243, 243, 0.725)]" /> 165 135 )} 166 136 </div> 167 137 )} 168 138 <div className="flex flex-col"> 169 139 <Link 170 - to={`/${row.uri?.split("at://")[1]}`} 140 + to={`/${row.uri?.split("at://")[1].replace("app.rocksky.", "")}`} 171 141 className="!text-[var(--color-text)]" 172 142 > 173 143 {row.title} 174 144 </Link> 175 145 {row.artistUri && ( 176 146 <Link 177 - to={`/${row.artistUri?.split("at://")[1]}`} 147 + to={`/${row.artistUri?.split("at://")[1].replace("app.rocksky.", "")}`} 178 148 className="!text-[var(--color-text-muted)]" 179 149 > 180 150 {row.albumArtist}
+22 -8
apps/web/src/pages/song/Song.tsx
··· 1 1 import styled from "@emotion/styled"; 2 2 import { ExternalLink } from "@styled-icons/evaicons-solid"; 3 + import { 4 + Link as DefaultLink, 5 + useParams, 6 + useRouter, 7 + } from "@tanstack/react-router"; 3 8 import { KIND, Tag } from "baseui/tag"; 4 9 import { 5 10 HeadingMedium, ··· 11 16 import numeral from "numeral"; 12 17 import { useEffect, useState } from "react"; 13 18 import ContentLoader from "react-content-loader"; 14 - import { Link as DefaultLink, useParams } from "react-router"; 15 19 import { songAtom } from "../../atoms/song"; 16 20 import Disc from "../../components/Icons/Disc"; 17 21 import Shout from "../../components/Shout/Shout"; ··· 54 58 `; 55 59 56 60 const Song = () => { 57 - const { did, rkey } = useParams<{ did: string; rkey: string }>(); 61 + const { did, rkey } = useParams({ strict: false }); 62 + const { 63 + state: { 64 + location: { pathname }, 65 + }, 66 + } = useRouter(); 58 67 59 68 let uri = `at://${did}/app.rocksky.scrobble/${rkey}`; 60 69 61 - if (window.location.pathname.includes("app.rocksky.song")) { 70 + if (pathname.includes("/song/")) { 62 71 uri = `at://${did}/app.rocksky.song/${rkey}`; 63 72 } 64 - if (window.location.pathname.includes("app.rocksky.scrobble")) { 73 + if (pathname.includes("/scrobble/")) { 65 74 uri = `at://${did}/app.rocksky.scrobble/${rkey}`; 66 75 } 67 76 ··· 113 122 }; 114 123 115 124 useEffect(() => { 116 - if (!window.location.pathname.includes("app.rocksky.song")) { 125 + if (!pathname.includes("/song/")) { 117 126 return; 118 127 } 119 128 ··· 130 139 }, [songResult.data, songResult.isLoading, songResult.isError, did]); 131 140 132 141 useEffect(() => { 133 - if (!window.location.pathname.includes("app.rocksky.scrobble")) { 142 + if (!pathname.includes("/scrobble/")) { 134 143 return; 135 144 } 136 145 ··· 164 173 albumArt: x.albumArt, 165 174 uri: x.uri, 166 175 artistUri: x.artistUri, 176 + albumUri: x.albumUri, 167 177 scrobbles: x.playCount, 168 178 })) 169 179 ); ··· 212 222 <> 213 223 <Group> 214 224 {song?.albumUri && ( 215 - <Link to={`/${song.albumUri.split("at://")[1]}`}> 225 + <Link 226 + to={`/${song.albumUri.split("at://")[1].replace("app.rocksky.", "")}`} 227 + > 216 228 {song.cover && <SongCover cover={song?.cover} size={150} />} 217 229 {!song.cover && ( 218 230 <div className="w-[150px] h-[150px] mr-[12px] rounded-[8px] bg-[rgba(243, 243, 243, 0.725)] flex justify-center items-center"> ··· 240 252 {song?.title} 241 253 </HeadingMedium> 242 254 {song?.artistUri && ( 243 - <Link to={`/${song.artistUri.split("at://")[1]}`}> 255 + <Link 256 + to={`/${song.artistUri.split("at://")[1].replace("app.rocksky.", "")}`} 257 + > 244 258 <LabelLarge 245 259 margin={0} 246 260 className="!text-[var(--color-text)]"
+355
apps/web/src/routeTree.gen.ts
··· 1 + /* eslint-disable */ 2 + 3 + // @ts-nocheck 4 + 5 + // noinspection JSUnusedGlobalSymbols 6 + 7 + // This file was automatically generated by TanStack Router. 8 + // You should NOT make any changes in this file as it will be overwritten. 9 + // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. 10 + 11 + import { Route as rootRouteImport } from './routes/__root' 12 + import { Route as ScrobbleRouteImport } from './routes/scrobble' 13 + import { Route as LoadingRouteImport } from './routes/loading' 14 + import { Route as GoogledriveRouteImport } from './routes/googledrive' 15 + import { Route as DropboxRouteImport } from './routes/dropbox' 16 + import { Route as ApikeysRouteImport } from './routes/apikeys' 17 + import { Route as IndexRouteImport } from './routes/index' 18 + import { Route as ProfileDidRouteImport } from './routes/profile.$did' 19 + import { Route as GoogledriveIdRouteImport } from './routes/googledrive.$id' 20 + import { Route as DropboxIdRouteImport } from './routes/dropbox.$id' 21 + import { Route as DidSongRkeyRouteImport } from './routes/$did.song.$rkey' 22 + import { Route as DidScrobbleRkeyRouteImport } from './routes/$did.scrobble.$rkey' 23 + import { Route as DidPlaylistRkeyRouteImport } from './routes/$did.playlist.$rkey' 24 + import { Route as DidArtistRkeyRouteImport } from './routes/$did.artist.$rkey' 25 + import { Route as DidAlbumRkeyRouteImport } from './routes/$did.album.$rkey' 26 + 27 + const ScrobbleRoute = ScrobbleRouteImport.update({ 28 + id: '/scrobble', 29 + path: '/scrobble', 30 + getParentRoute: () => rootRouteImport, 31 + } as any) 32 + const LoadingRoute = LoadingRouteImport.update({ 33 + id: '/loading', 34 + path: '/loading', 35 + getParentRoute: () => rootRouteImport, 36 + } as any) 37 + const GoogledriveRoute = GoogledriveRouteImport.update({ 38 + id: '/googledrive', 39 + path: '/googledrive', 40 + getParentRoute: () => rootRouteImport, 41 + } as any) 42 + const DropboxRoute = DropboxRouteImport.update({ 43 + id: '/dropbox', 44 + path: '/dropbox', 45 + getParentRoute: () => rootRouteImport, 46 + } as any) 47 + const ApikeysRoute = ApikeysRouteImport.update({ 48 + id: '/apikeys', 49 + path: '/apikeys', 50 + getParentRoute: () => rootRouteImport, 51 + } as any) 52 + const IndexRoute = IndexRouteImport.update({ 53 + id: '/', 54 + path: '/', 55 + getParentRoute: () => rootRouteImport, 56 + } as any) 57 + const ProfileDidRoute = ProfileDidRouteImport.update({ 58 + id: '/profile/$did', 59 + path: '/profile/$did', 60 + getParentRoute: () => rootRouteImport, 61 + } as any) 62 + const GoogledriveIdRoute = GoogledriveIdRouteImport.update({ 63 + id: '/$id', 64 + path: '/$id', 65 + getParentRoute: () => GoogledriveRoute, 66 + } as any) 67 + const DropboxIdRoute = DropboxIdRouteImport.update({ 68 + id: '/$id', 69 + path: '/$id', 70 + getParentRoute: () => DropboxRoute, 71 + } as any) 72 + const DidSongRkeyRoute = DidSongRkeyRouteImport.update({ 73 + id: '/$did/song/$rkey', 74 + path: '/$did/song/$rkey', 75 + getParentRoute: () => rootRouteImport, 76 + } as any) 77 + const DidScrobbleRkeyRoute = DidScrobbleRkeyRouteImport.update({ 78 + id: '/$did/scrobble/$rkey', 79 + path: '/$did/scrobble/$rkey', 80 + getParentRoute: () => rootRouteImport, 81 + } as any) 82 + const DidPlaylistRkeyRoute = DidPlaylistRkeyRouteImport.update({ 83 + id: '/$did/playlist/$rkey', 84 + path: '/$did/playlist/$rkey', 85 + getParentRoute: () => rootRouteImport, 86 + } as any) 87 + const DidArtistRkeyRoute = DidArtistRkeyRouteImport.update({ 88 + id: '/$did/artist/$rkey', 89 + path: '/$did/artist/$rkey', 90 + getParentRoute: () => rootRouteImport, 91 + } as any) 92 + const DidAlbumRkeyRoute = DidAlbumRkeyRouteImport.update({ 93 + id: '/$did/album/$rkey', 94 + path: '/$did/album/$rkey', 95 + getParentRoute: () => rootRouteImport, 96 + } as any) 97 + 98 + export interface FileRoutesByFullPath { 99 + '/': typeof IndexRoute 100 + '/apikeys': typeof ApikeysRoute 101 + '/dropbox': typeof DropboxRouteWithChildren 102 + '/googledrive': typeof GoogledriveRouteWithChildren 103 + '/loading': typeof LoadingRoute 104 + '/scrobble': typeof ScrobbleRoute 105 + '/dropbox/$id': typeof DropboxIdRoute 106 + '/googledrive/$id': typeof GoogledriveIdRoute 107 + '/profile/$did': typeof ProfileDidRoute 108 + '/$did/album/$rkey': typeof DidAlbumRkeyRoute 109 + '/$did/artist/$rkey': typeof DidArtistRkeyRoute 110 + '/$did/playlist/$rkey': typeof DidPlaylistRkeyRoute 111 + '/$did/scrobble/$rkey': typeof DidScrobbleRkeyRoute 112 + '/$did/song/$rkey': typeof DidSongRkeyRoute 113 + } 114 + export interface FileRoutesByTo { 115 + '/': typeof IndexRoute 116 + '/apikeys': typeof ApikeysRoute 117 + '/dropbox': typeof DropboxRouteWithChildren 118 + '/googledrive': typeof GoogledriveRouteWithChildren 119 + '/loading': typeof LoadingRoute 120 + '/scrobble': typeof ScrobbleRoute 121 + '/dropbox/$id': typeof DropboxIdRoute 122 + '/googledrive/$id': typeof GoogledriveIdRoute 123 + '/profile/$did': typeof ProfileDidRoute 124 + '/$did/album/$rkey': typeof DidAlbumRkeyRoute 125 + '/$did/artist/$rkey': typeof DidArtistRkeyRoute 126 + '/$did/playlist/$rkey': typeof DidPlaylistRkeyRoute 127 + '/$did/scrobble/$rkey': typeof DidScrobbleRkeyRoute 128 + '/$did/song/$rkey': typeof DidSongRkeyRoute 129 + } 130 + export interface FileRoutesById { 131 + __root__: typeof rootRouteImport 132 + '/': typeof IndexRoute 133 + '/apikeys': typeof ApikeysRoute 134 + '/dropbox': typeof DropboxRouteWithChildren 135 + '/googledrive': typeof GoogledriveRouteWithChildren 136 + '/loading': typeof LoadingRoute 137 + '/scrobble': typeof ScrobbleRoute 138 + '/dropbox/$id': typeof DropboxIdRoute 139 + '/googledrive/$id': typeof GoogledriveIdRoute 140 + '/profile/$did': typeof ProfileDidRoute 141 + '/$did/album/$rkey': typeof DidAlbumRkeyRoute 142 + '/$did/artist/$rkey': typeof DidArtistRkeyRoute 143 + '/$did/playlist/$rkey': typeof DidPlaylistRkeyRoute 144 + '/$did/scrobble/$rkey': typeof DidScrobbleRkeyRoute 145 + '/$did/song/$rkey': typeof DidSongRkeyRoute 146 + } 147 + export interface FileRouteTypes { 148 + fileRoutesByFullPath: FileRoutesByFullPath 149 + fullPaths: 150 + | '/' 151 + | '/apikeys' 152 + | '/dropbox' 153 + | '/googledrive' 154 + | '/loading' 155 + | '/scrobble' 156 + | '/dropbox/$id' 157 + | '/googledrive/$id' 158 + | '/profile/$did' 159 + | '/$did/album/$rkey' 160 + | '/$did/artist/$rkey' 161 + | '/$did/playlist/$rkey' 162 + | '/$did/scrobble/$rkey' 163 + | '/$did/song/$rkey' 164 + fileRoutesByTo: FileRoutesByTo 165 + to: 166 + | '/' 167 + | '/apikeys' 168 + | '/dropbox' 169 + | '/googledrive' 170 + | '/loading' 171 + | '/scrobble' 172 + | '/dropbox/$id' 173 + | '/googledrive/$id' 174 + | '/profile/$did' 175 + | '/$did/album/$rkey' 176 + | '/$did/artist/$rkey' 177 + | '/$did/playlist/$rkey' 178 + | '/$did/scrobble/$rkey' 179 + | '/$did/song/$rkey' 180 + id: 181 + | '__root__' 182 + | '/' 183 + | '/apikeys' 184 + | '/dropbox' 185 + | '/googledrive' 186 + | '/loading' 187 + | '/scrobble' 188 + | '/dropbox/$id' 189 + | '/googledrive/$id' 190 + | '/profile/$did' 191 + | '/$did/album/$rkey' 192 + | '/$did/artist/$rkey' 193 + | '/$did/playlist/$rkey' 194 + | '/$did/scrobble/$rkey' 195 + | '/$did/song/$rkey' 196 + fileRoutesById: FileRoutesById 197 + } 198 + export interface RootRouteChildren { 199 + IndexRoute: typeof IndexRoute 200 + ApikeysRoute: typeof ApikeysRoute 201 + DropboxRoute: typeof DropboxRouteWithChildren 202 + GoogledriveRoute: typeof GoogledriveRouteWithChildren 203 + LoadingRoute: typeof LoadingRoute 204 + ScrobbleRoute: typeof ScrobbleRoute 205 + ProfileDidRoute: typeof ProfileDidRoute 206 + DidAlbumRkeyRoute: typeof DidAlbumRkeyRoute 207 + DidArtistRkeyRoute: typeof DidArtistRkeyRoute 208 + DidPlaylistRkeyRoute: typeof DidPlaylistRkeyRoute 209 + DidScrobbleRkeyRoute: typeof DidScrobbleRkeyRoute 210 + DidSongRkeyRoute: typeof DidSongRkeyRoute 211 + } 212 + 213 + declare module '@tanstack/react-router' { 214 + interface FileRoutesByPath { 215 + '/scrobble': { 216 + id: '/scrobble' 217 + path: '/scrobble' 218 + fullPath: '/scrobble' 219 + preLoaderRoute: typeof ScrobbleRouteImport 220 + parentRoute: typeof rootRouteImport 221 + } 222 + '/loading': { 223 + id: '/loading' 224 + path: '/loading' 225 + fullPath: '/loading' 226 + preLoaderRoute: typeof LoadingRouteImport 227 + parentRoute: typeof rootRouteImport 228 + } 229 + '/googledrive': { 230 + id: '/googledrive' 231 + path: '/googledrive' 232 + fullPath: '/googledrive' 233 + preLoaderRoute: typeof GoogledriveRouteImport 234 + parentRoute: typeof rootRouteImport 235 + } 236 + '/dropbox': { 237 + id: '/dropbox' 238 + path: '/dropbox' 239 + fullPath: '/dropbox' 240 + preLoaderRoute: typeof DropboxRouteImport 241 + parentRoute: typeof rootRouteImport 242 + } 243 + '/apikeys': { 244 + id: '/apikeys' 245 + path: '/apikeys' 246 + fullPath: '/apikeys' 247 + preLoaderRoute: typeof ApikeysRouteImport 248 + parentRoute: typeof rootRouteImport 249 + } 250 + '/': { 251 + id: '/' 252 + path: '/' 253 + fullPath: '/' 254 + preLoaderRoute: typeof IndexRouteImport 255 + parentRoute: typeof rootRouteImport 256 + } 257 + '/profile/$did': { 258 + id: '/profile/$did' 259 + path: '/profile/$did' 260 + fullPath: '/profile/$did' 261 + preLoaderRoute: typeof ProfileDidRouteImport 262 + parentRoute: typeof rootRouteImport 263 + } 264 + '/googledrive/$id': { 265 + id: '/googledrive/$id' 266 + path: '/$id' 267 + fullPath: '/googledrive/$id' 268 + preLoaderRoute: typeof GoogledriveIdRouteImport 269 + parentRoute: typeof GoogledriveRoute 270 + } 271 + '/dropbox/$id': { 272 + id: '/dropbox/$id' 273 + path: '/$id' 274 + fullPath: '/dropbox/$id' 275 + preLoaderRoute: typeof DropboxIdRouteImport 276 + parentRoute: typeof DropboxRoute 277 + } 278 + '/$did/song/$rkey': { 279 + id: '/$did/song/$rkey' 280 + path: '/$did/song/$rkey' 281 + fullPath: '/$did/song/$rkey' 282 + preLoaderRoute: typeof DidSongRkeyRouteImport 283 + parentRoute: typeof rootRouteImport 284 + } 285 + '/$did/scrobble/$rkey': { 286 + id: '/$did/scrobble/$rkey' 287 + path: '/$did/scrobble/$rkey' 288 + fullPath: '/$did/scrobble/$rkey' 289 + preLoaderRoute: typeof DidScrobbleRkeyRouteImport 290 + parentRoute: typeof rootRouteImport 291 + } 292 + '/$did/playlist/$rkey': { 293 + id: '/$did/playlist/$rkey' 294 + path: '/$did/playlist/$rkey' 295 + fullPath: '/$did/playlist/$rkey' 296 + preLoaderRoute: typeof DidPlaylistRkeyRouteImport 297 + parentRoute: typeof rootRouteImport 298 + } 299 + '/$did/artist/$rkey': { 300 + id: '/$did/artist/$rkey' 301 + path: '/$did/artist/$rkey' 302 + fullPath: '/$did/artist/$rkey' 303 + preLoaderRoute: typeof DidArtistRkeyRouteImport 304 + parentRoute: typeof rootRouteImport 305 + } 306 + '/$did/album/$rkey': { 307 + id: '/$did/album/$rkey' 308 + path: '/$did/album/$rkey' 309 + fullPath: '/$did/album/$rkey' 310 + preLoaderRoute: typeof DidAlbumRkeyRouteImport 311 + parentRoute: typeof rootRouteImport 312 + } 313 + } 314 + } 315 + 316 + interface DropboxRouteChildren { 317 + DropboxIdRoute: typeof DropboxIdRoute 318 + } 319 + 320 + const DropboxRouteChildren: DropboxRouteChildren = { 321 + DropboxIdRoute: DropboxIdRoute, 322 + } 323 + 324 + const DropboxRouteWithChildren = 325 + DropboxRoute._addFileChildren(DropboxRouteChildren) 326 + 327 + interface GoogledriveRouteChildren { 328 + GoogledriveIdRoute: typeof GoogledriveIdRoute 329 + } 330 + 331 + const GoogledriveRouteChildren: GoogledriveRouteChildren = { 332 + GoogledriveIdRoute: GoogledriveIdRoute, 333 + } 334 + 335 + const GoogledriveRouteWithChildren = GoogledriveRoute._addFileChildren( 336 + GoogledriveRouteChildren, 337 + ) 338 + 339 + const rootRouteChildren: RootRouteChildren = { 340 + IndexRoute: IndexRoute, 341 + ApikeysRoute: ApikeysRoute, 342 + DropboxRoute: DropboxRouteWithChildren, 343 + GoogledriveRoute: GoogledriveRouteWithChildren, 344 + LoadingRoute: LoadingRoute, 345 + ScrobbleRoute: ScrobbleRoute, 346 + ProfileDidRoute: ProfileDidRoute, 347 + DidAlbumRkeyRoute: DidAlbumRkeyRoute, 348 + DidArtistRkeyRoute: DidArtistRkeyRoute, 349 + DidPlaylistRkeyRoute: DidPlaylistRkeyRoute, 350 + DidScrobbleRkeyRoute: DidScrobbleRkeyRoute, 351 + DidSongRkeyRoute: DidSongRkeyRoute, 352 + } 353 + export const routeTree = rootRouteImport 354 + ._addFileChildren(rootRouteChildren) 355 + ._addFileTypes<FileRouteTypes>()
+6
apps/web/src/routes/$did.album.$rkey.tsx
··· 1 + import { createFileRoute } from "@tanstack/react-router"; 2 + import AlbumPage from "../pages/album"; 3 + 4 + export const Route = createFileRoute("/$did/album/$rkey")({ 5 + component: AlbumPage, 6 + });
+6
apps/web/src/routes/$did.artist.$rkey.tsx
··· 1 + import { createFileRoute } from "@tanstack/react-router"; 2 + import ArtistPage from "../pages/artist"; 3 + 4 + export const Route = createFileRoute("/$did/artist/$rkey")({ 5 + component: ArtistPage, 6 + });
+6
apps/web/src/routes/$did.playlist.$rkey.tsx
··· 1 + import { createFileRoute } from "@tanstack/react-router"; 2 + import PlaylistPage from "../pages/playlist"; 3 + 4 + export const Route = createFileRoute("/$did/playlist/$rkey")({ 5 + component: PlaylistPage, 6 + });
+6
apps/web/src/routes/$did.scrobble.$rkey.tsx
··· 1 + import { createFileRoute } from "@tanstack/react-router"; 2 + import SongPage from "../pages/song"; 3 + 4 + export const Route = createFileRoute("/$did/scrobble/$rkey")({ 5 + component: SongPage, 6 + });
+6
apps/web/src/routes/$did.song.$rkey.tsx
··· 1 + import { createFileRoute } from "@tanstack/react-router"; 2 + import SongPage from "../pages/song"; 3 + 4 + export const Route = createFileRoute("/$did/song/$rkey")({ 5 + component: SongPage, 6 + });
+27
apps/web/src/routes/__root.tsx
··· 1 + import { Outlet, createRootRoute } from "@tanstack/react-router"; 2 + import { useAtomValue } from "jotai"; 3 + import * as React from "react"; 4 + import { themeAtom } from "../atoms/theme"; 5 + 6 + export const Route = createRootRoute({ 7 + component: RootComponent, 8 + }); 9 + 10 + function RootComponent() { 11 + const { darkMode } = useAtomValue(themeAtom); 12 + 13 + React.useEffect(() => { 14 + const root = document.getElementById("root"); 15 + if (darkMode) { 16 + root!.classList.add("dark"); 17 + return; 18 + } 19 + root!.classList.remove("dark"); 20 + }, [darkMode]); 21 + 22 + return ( 23 + <React.Fragment> 24 + <Outlet /> 25 + </React.Fragment> 26 + ); 27 + }
+6
apps/web/src/routes/apikeys.tsx
··· 1 + import { createFileRoute } from "@tanstack/react-router"; 2 + import ApiKeysPage from "../pages/apikeys"; 3 + 4 + export const Route = createFileRoute("/apikeys")({ 5 + component: ApiKeysPage, 6 + });
+6
apps/web/src/routes/dropbox.$id.tsx
··· 1 + import { createFileRoute } from "@tanstack/react-router"; 2 + import DropboxWithIdPage from "../pages/dropbox/DropboxWithId"; 3 + 4 + export const Route = createFileRoute("/dropbox/$id")({ 5 + component: DropboxWithIdPage, 6 + });
+6
apps/web/src/routes/dropbox.tsx
··· 1 + import { createFileRoute } from "@tanstack/react-router"; 2 + import DropboxPage from "../pages/dropbox"; 3 + 4 + export const Route = createFileRoute("/dropbox")({ 5 + component: DropboxPage, 6 + });
+6
apps/web/src/routes/googledrive.$id.tsx
··· 1 + import { createFileRoute } from "@tanstack/react-router"; 2 + import GoogleDriveWithIdPage from "../pages/googledrive/GoogleDriveWithId"; 3 + 4 + export const Route = createFileRoute("/googledrive/$id")({ 5 + component: GoogleDriveWithIdPage, 6 + });
+6
apps/web/src/routes/googledrive.tsx
··· 1 + import { createFileRoute } from "@tanstack/react-router"; 2 + import GoogleDrivePage from "../pages/googledrive"; 3 + 4 + export const Route = createFileRoute("/googledrive")({ 5 + component: GoogleDrivePage, 6 + });
+14
apps/web/src/routes/index.tsx
··· 1 + import { createFileRoute } from "@tanstack/react-router"; 2 + import { zodValidator } from "@tanstack/zod-adapter"; 3 + import z from "zod"; 4 + import HomePage from "../pages/home"; 5 + 6 + export const HomePageSchema = z.object({ 7 + did: z.string().optional(), 8 + cli: z.string().optional(), 9 + }); 10 + 11 + export const Route = createFileRoute("/")({ 12 + component: HomePage, 13 + validateSearch: zodValidator(HomePageSchema), 14 + });
+13
apps/web/src/routes/loading.tsx
··· 1 + import { createFileRoute } from "@tanstack/react-router"; 2 + import { zodValidator } from "@tanstack/zod-adapter"; 3 + import z from "zod"; 4 + import LoadingPage from "../pages/loading"; 5 + 6 + const validateSearch = z.object({ 7 + handle: z.string(), 8 + }); 9 + 10 + export const Route = createFileRoute("/loading")({ 11 + component: LoadingPage, 12 + validateSearch: zodValidator(validateSearch), 13 + });
+13
apps/web/src/routes/profile.$did.tsx
··· 1 + import { createFileRoute } from "@tanstack/react-router"; 2 + import { zodValidator } from "@tanstack/zod-adapter"; 3 + import z from "zod"; 4 + import ProfilePage from "../pages/profile"; 5 + 6 + const validateSearch = z.object({ 7 + tab: z.number().optional(), 8 + }); 9 + 10 + export const Route = createFileRoute("/profile/$did")({ 11 + component: ProfilePage, 12 + validateSearch: zodValidator(validateSearch), 13 + });
+6
apps/web/src/routes/scrobble.tsx
··· 1 + import { createFileRoute } from "@tanstack/react-router"; 2 + import SongPage from "../pages/song"; 3 + 4 + export const Route = createFileRoute("/scrobble")({ 5 + component: SongPage, 6 + });
+10 -1
apps/web/vite.config.ts
··· 1 1 import tailwindcss from "@tailwindcss/vite"; 2 + import { tanstackRouter } from "@tanstack/router-plugin/vite"; 2 3 import react from "@vitejs/plugin-react-swc"; 3 4 import { defineConfig } from "vite"; 5 + 4 6 // https://vite.dev/config/ 5 7 export default defineConfig({ 6 - plugins: [react(), tailwindcss()], 8 + plugins: [ 9 + tanstackRouter({ 10 + target: "react", 11 + autoCodeSplitting: true, 12 + }), 13 + react(), 14 + tailwindcss(), 15 + ], 7 16 optimizeDeps: { 8 17 force: true, 9 18 },
+174 -20
bun.lock
··· 179 179 "@tailwindcss/vite": "^4.1.4", 180 180 "@tanstack/react-query": "^5.76.0", 181 181 "@tanstack/react-query-devtools": "^5.76.0", 182 + "@tanstack/react-router": "^1.125.4", 183 + "@tanstack/react-router-devtools": "^1.125.4", 182 184 "@tanstack/react-table": "^8.21.2", 185 + "@tanstack/zod-adapter": "^1.125.4", 183 186 "@types/numeral": "^2.0.5", 184 187 "@vitest/ui": "^3.0.4", 185 188 "axios": "^1.7.9", ··· 200 203 "react-dom": "^18.3.1", 201 204 "react-hook-form": "^7.54.2", 202 205 "react-i18next": "^15.4.0", 203 - "react-router": "^7.1.3", 204 - "react-router-dom": "^7.1.3", 205 206 "recharts": "^2.15.1", 206 207 "styletron-engine-monolithic": "^1.0.0", 207 208 "styletron-react": "^6.1.1", ··· 221 222 "@storybook/react": "^8.5.2", 222 223 "@storybook/react-vite": "^8.5.2", 223 224 "@storybook/test": "^8.5.2", 225 + "@tanstack/router-plugin": "^1.125.4", 224 226 "@types/lodash": "^4.17.15", 225 227 "@types/ramda": "^0.30.2", 226 228 "@types/react": "^18.3.18", ··· 320 322 321 323 "@babel/compat-data": ["@babel/compat-data@7.27.5", "", {}, "sha512-KiRAp/VoJaWkkte84TvUd9qjdbZAdiqyvMxrGl1N6vzFogKmaLgoM3L1kgtLicp2HP5fBJS8JrZKLVIZGVJAVg=="], 322 324 323 - "@babel/core": ["@babel/core@7.27.4", "", { "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.27.3", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.27.3", "@babel/helpers": "^7.27.4", "@babel/parser": "^7.27.4", "@babel/template": "^7.27.2", "@babel/traverse": "^7.27.4", "@babel/types": "^7.27.3", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-bXYxrXFubeYdvB0NhD/NBB3Qi6aZeV20GOWVI47t2dkecCEoneR4NPVcb7abpXDEvejgrUfFtG6vG/zxAKmg+g=="], 325 + "@babel/core": ["@babel/core@7.28.0", "", { "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.0", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.27.3", "@babel/helpers": "^7.27.6", "@babel/parser": "^7.28.0", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.0", "@babel/types": "^7.28.0", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ=="], 326 + 327 + "@babel/generator": ["@babel/generator@7.28.0", "", { "dependencies": { "@babel/parser": "^7.28.0", "@babel/types": "^7.28.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg=="], 324 328 325 - "@babel/generator": ["@babel/generator@7.27.5", "", { "dependencies": { "@babel/parser": "^7.27.5", "@babel/types": "^7.27.3", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" } }, "sha512-ZGhA37l0e/g2s1Cnzdix0O3aLYm66eF8aufiVteOgnwxgnRP8GoyMj7VWsgWnQbVKXyge7hqrFh2K2TQM6t1Hw=="], 329 + "@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="], 326 330 327 331 "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.27.2", "", { "dependencies": { "@babel/compat-data": "^7.27.2", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ=="], 328 332 333 + "@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.27.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-QwGAmuvM17btKU5VqXfb+Giw4JcN0hjuufz3DYnpeVDvZLAObloM77bhMXiqry3Iio+Ai4phVRDwl6WU10+r5A=="], 334 + 335 + "@babel/helper-globals": ["@babel/helper-globals@7.28.0", "", {}, "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="], 336 + 337 + "@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA=="], 338 + 329 339 "@babel/helper-module-imports": ["@babel/helper-module-imports@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w=="], 330 340 331 341 "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.27.3", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", "@babel/traverse": "^7.27.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg=="], 332 342 343 + "@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="], 344 + 345 + "@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.27.1", "", {}, "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw=="], 346 + 347 + "@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="], 348 + 349 + "@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="], 350 + 333 351 "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="], 334 352 335 353 "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.27.1", "", {}, "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow=="], ··· 338 356 339 357 "@babel/helpers": ["@babel/helpers@7.27.6", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/types": "^7.27.6" } }, "sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug=="], 340 358 341 - "@babel/parser": ["@babel/parser@7.27.5", "", { "dependencies": { "@babel/types": "^7.27.3" }, "bin": "./bin/babel-parser.js" }, "sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg=="], 359 + "@babel/parser": ["@babel/parser@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.0" }, "bin": "./bin/babel-parser.js" }, "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g=="], 360 + 361 + "@babel/plugin-syntax-jsx": ["@babel/plugin-syntax-jsx@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w=="], 362 + 363 + "@babel/plugin-syntax-typescript": ["@babel/plugin-syntax-typescript@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ=="], 364 + 365 + "@babel/plugin-transform-modules-commonjs": ["@babel/plugin-transform-modules-commonjs@7.27.1", "", { "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw=="], 366 + 367 + "@babel/plugin-transform-typescript": ["@babel/plugin-transform-typescript@7.28.0", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-4AEiDEBPIZvLQaWlc9liCavE0xRM0dNca41WtBeM3jgFptfUOSG9z0uteLhq6+3rq+WB6jIvUwKDTpXEHPJ2Vg=="], 368 + 369 + "@babel/preset-typescript": ["@babel/preset-typescript@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-transform-modules-commonjs": "^7.27.1", "@babel/plugin-transform-typescript": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-l7WfQfX0WK4M0v2RudjuQK4u99BS6yLHYEmdtVPP7lKV013zr9DygFuWNlnbvQ9LR+LS0Egz/XAvGx5U9MX0fQ=="], 342 370 343 371 "@babel/runtime": ["@babel/runtime@7.27.6", "", {}, "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q=="], 344 372 345 373 "@babel/template": ["@babel/template@7.27.2", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/parser": "^7.27.2", "@babel/types": "^7.27.1" } }, "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw=="], 346 374 347 - "@babel/traverse": ["@babel/traverse@7.27.4", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.27.3", "@babel/parser": "^7.27.4", "@babel/template": "^7.27.2", "@babel/types": "^7.27.3", "debug": "^4.3.1", "globals": "^11.1.0" } }, "sha512-oNcu2QbHqts9BtOWJosOVJapWjBDSxGCpFvikNR5TGDYDQf3JwpIoMzIKrvfoti93cLfPJEG4tH9SPVeyCGgdA=="], 375 + "@babel/traverse": ["@babel/traverse@7.28.0", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.0", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.0", "@babel/template": "^7.27.2", "@babel/types": "^7.28.0", "debug": "^4.3.1" } }, "sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg=="], 348 376 349 - "@babel/types": ["@babel/types@7.27.6", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q=="], 377 + "@babel/types": ["@babel/types@7.28.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-jYnje+JyZG5YThjHiF28oT4SIZLnYOcSBb6+SDaFIyzDVSkXQmQQYclJ2R+YxcdmK0AX6x1E5OQNtuh3jHDrUg=="], 350 378 351 379 "@cbor-extract/cbor-extract-darwin-arm64": ["@cbor-extract/cbor-extract-darwin-arm64@2.2.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-P7swiOAdF7aSi0H+tHtHtr6zrpF3aAq/W9FXx5HektRvLTM2O89xCyXF3pk7pLc7QpaY7AoaE8UowVf9QBdh3w=="], 352 380 ··· 1038 1066 1039 1067 "@tailwindcss/vite": ["@tailwindcss/vite@4.1.10", "", { "dependencies": { "@tailwindcss/node": "4.1.10", "@tailwindcss/oxide": "4.1.10", "tailwindcss": "4.1.10" }, "peerDependencies": { "vite": "^5.2.0 || ^6" } }, "sha512-QWnD5HDY2IADv+vYR82lOhqOlS1jSCUUAmfem52cXAhRTKxpDh3ARX8TTXJTCCO7Rv7cD2Nlekabv02bwP3a2A=="], 1040 1068 1069 + "@tanstack/history": ["@tanstack/history@1.121.34", "", {}, "sha512-YL8dGi5ZU+xvtav2boRlw4zrRghkY6hvdcmHhA0RGSJ/CBgzv+cbADW9eYJLx74XMZvIQ1pp6VMbrpXnnM5gHA=="], 1070 + 1041 1071 "@tanstack/query-core": ["@tanstack/query-core@5.81.2", "", {}, "sha512-QLYkPdrudoMATDFa3MiLEwRhNnAlzHWDf0LKaXUqJd0/+QxN8uTPi7bahRlxoAyH0UbLMBdeDbYzWALj7THOtw=="], 1042 1072 1043 1073 "@tanstack/query-devtools": ["@tanstack/query-devtools@5.81.2", "", {}, "sha512-jCeJcDCwKfoyyBXjXe9+Lo8aTkavygHHsUHAlxQKKaDeyT0qyQNLKl7+UyqYH2dDF6UN/14873IPBHchcsU+Zg=="], ··· 1046 1076 1047 1077 "@tanstack/react-query-devtools": ["@tanstack/react-query-devtools@5.81.2", "", { "dependencies": { "@tanstack/query-devtools": "5.81.2" }, "peerDependencies": { "@tanstack/react-query": "^5.81.2", "react": "^18 || ^19" } }, "sha512-TX0OQ4cbgX6z2uN8c9x0QUNbyePGyUGdcgrGnV6TYEJc7KPT8PqeASuzoA5NGw1CiMGvyFAkIGA2KipvhM9d1g=="], 1048 1078 1079 + "@tanstack/react-router": ["@tanstack/react-router@1.125.4", "", { "dependencies": { "@tanstack/history": "1.121.34", "@tanstack/react-store": "^0.7.0", "@tanstack/router-core": "1.125.4", "isbot": "^5.1.22", "jsesc": "^3.1.0", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" }, "peerDependencies": { "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" } }, "sha512-IIlDiFCR+RN/17dWtYKMYiJvH38tmtgTyciHkeZvr8vSWhThAeuwjzKneF4mQl3B//YHYcrFm7rZM59c24As/A=="], 1080 + 1081 + "@tanstack/react-router-devtools": ["@tanstack/react-router-devtools@1.125.4", "", { "dependencies": { "@tanstack/router-devtools-core": "^1.125.4" }, "peerDependencies": { "@tanstack/react-router": "^1.125.4", "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" } }, "sha512-eRg6Ht6bLno+Eo2Gps3cfjp++Mvy0brc6qs81At4beKZsCkS7jlmqHgrq6pXdH3l2bAQ/Dhr8J9zXvzxvRxf/g=="], 1082 + 1083 + "@tanstack/react-store": ["@tanstack/react-store@0.7.1", "", { "dependencies": { "@tanstack/store": "0.7.1", "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-qUTEKdId6QPWGiWyKAPf/gkN29scEsz6EUSJ0C3HgLMgaqTAyBsQ2sMCfGVcqb+kkhEXAdjleCgH6LAPD6f2sA=="], 1084 + 1049 1085 "@tanstack/react-table": ["@tanstack/react-table@8.21.3", "", { "dependencies": { "@tanstack/table-core": "8.21.3" }, "peerDependencies": { "react": ">=16.8", "react-dom": ">=16.8" } }, "sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww=="], 1050 1086 1087 + "@tanstack/router-core": ["@tanstack/router-core@1.125.4", "", { "dependencies": { "@tanstack/history": "1.121.34", "@tanstack/store": "^0.7.0", "cookie-es": "^1.2.2", "jsesc": "^3.1.0", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" } }, "sha512-tdgGI0Kwt3Lgs9ceLbG32NPh4I2H1T9t2TKjcS+I78sifm5rjTWV8lfqVRNrvMPk5ek60vXPOL2AHAUg6ohwsA=="], 1088 + 1089 + "@tanstack/router-devtools-core": ["@tanstack/router-devtools-core@1.125.4", "", { "dependencies": { "clsx": "^2.1.1", "goober": "^2.1.16", "solid-js": "^1.9.5" }, "peerDependencies": { "@tanstack/router-core": "^1.125.4", "csstype": "^3.0.10", "tiny-invariant": "^1.3.3" }, "optionalPeers": ["csstype"] }, "sha512-5QbCQCcJcN/M0NF2TARKqauJ8QeRuk7kyHQMCqOoSJWWGUVcDHEmcbg1ZCJevfPVZPgnUjV9mqDfCPTYWT8/+w=="], 1090 + 1091 + "@tanstack/router-generator": ["@tanstack/router-generator@1.125.4", "", { "dependencies": { "@tanstack/router-core": "^1.125.4", "@tanstack/router-utils": "1.121.21", "@tanstack/virtual-file-routes": "^1.121.21", "prettier": "^3.5.0", "recast": "^0.23.11", "source-map": "^0.7.4", "tsx": "^4.19.2", "zod": "^3.24.2" } }, "sha512-jF71znMvpZxmkQF0MxfjKKyvXtft9NWRCVcLhb+6d/8nrVGNiEw+dsXn/CLpeRQLk7Mg/fsp/WipBql1dd3Qaw=="], 1092 + 1093 + "@tanstack/router-plugin": ["@tanstack/router-plugin@1.125.4", "", { "dependencies": { "@babel/core": "^7.27.7", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.27.1", "@babel/template": "^7.27.2", "@babel/traverse": "^7.27.7", "@babel/types": "^7.27.7", "@tanstack/router-core": "^1.125.4", "@tanstack/router-generator": "1.125.4", "@tanstack/router-utils": "1.121.21", "@tanstack/virtual-file-routes": "^1.121.21", "babel-dead-code-elimination": "^1.0.10", "chokidar": "^3.6.0", "unplugin": "^2.1.2", "zod": "^3.24.2" }, "peerDependencies": { "@rsbuild/core": ">=1.0.2", "@tanstack/react-router": "^1.125.4", "vite": ">=5.0.0 || >=6.0.0", "vite-plugin-solid": "^2.11.2", "webpack": ">=5.92.0" }, "optionalPeers": ["@rsbuild/core", "@tanstack/react-router", "vite", "vite-plugin-solid", "webpack"] }, "sha512-k3m7z5p64IT8MHG+PwecqCm/vUyzz4ZnEAdOJ1W1Kz6ZreP+FAMDNKY69U82MbhV5TU6a/luWIH/7IyfXDxs3A=="], 1094 + 1095 + "@tanstack/router-utils": ["@tanstack/router-utils@1.121.21", "", { "dependencies": { "@babel/core": "^7.27.4", "@babel/generator": "^7.27.5", "@babel/parser": "^7.27.5", "@babel/preset-typescript": "^7.27.1", "ansis": "^4.1.0", "diff": "^8.0.2" } }, "sha512-u7ubq1xPBtNiU7Fm+EOWlVWdgFLzuKOa1thhqdscVn8R4dNMUd1VoOjZ6AKmLw201VaUhFtlX+u0pjzI6szX7A=="], 1096 + 1097 + "@tanstack/store": ["@tanstack/store@0.7.1", "", {}, "sha512-PjUQKXEXhLYj2X5/6c1Xn/0/qKY0IVFxTJweopRfF26xfjVyb14yALydJrHupDh3/d+1WKmfEgZPBVCmDkzzwg=="], 1098 + 1051 1099 "@tanstack/table-core": ["@tanstack/table-core@8.21.3", "", {}, "sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg=="], 1100 + 1101 + "@tanstack/virtual-file-routes": ["@tanstack/virtual-file-routes@1.121.21", "", {}, "sha512-3nuYsTyaq6ZN7jRZ9z6Gj3GXZqBOqOT0yzd/WZ33ZFfv4yVNIvsa5Lw+M1j3sgyEAxKMqGu/FaNi7FCjr3yOdw=="], 1102 + 1103 + "@tanstack/zod-adapter": ["@tanstack/zod-adapter@1.125.4", "", { "peerDependencies": { "@tanstack/react-router": ">=1.43.2", "zod": "^3.23.8" } }, "sha512-3/ycN2IM43gicOk5ZY/yrXCQ4B2NVqsgVkIab1WlPWNkvCKP+vp4+j4b42BuHMv501kBnSsGBdhaRs11IUHLoQ=="], 1052 1104 1053 1105 "@testing-library/dom": ["@testing-library/dom@10.4.0", "", { "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", "@types/aria-query": "^5.0.1", "aria-query": "5.3.0", "chalk": "^4.1.0", "dom-accessibility-api": "^0.5.9", "lz-string": "^1.5.0", "pretty-format": "^27.0.2" } }, "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ=="], 1054 1106 ··· 1222 1274 1223 1275 "ansi-styles": ["ansi-styles@2.2.1", "", {}, "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA=="], 1224 1276 1277 + "ansis": ["ansis@4.1.0", "", {}, "sha512-BGcItUBWSMRgOCe+SVZJ+S7yTRG0eGt9cXAHev72yuGcY23hnLA7Bky5L/xLyPINoSN95geovfBkqoTlNZYa7w=="], 1278 + 1225 1279 "any-promise": ["any-promise@1.3.0", "", {}, "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="], 1226 1280 1227 1281 "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], ··· 1264 1318 1265 1319 "axios": ["axios@1.10.0", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } }, "sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw=="], 1266 1320 1321 + "babel-dead-code-elimination": ["babel-dead-code-elimination@1.0.10", "", { "dependencies": { "@babel/core": "^7.23.7", "@babel/parser": "^7.23.6", "@babel/traverse": "^7.23.7", "@babel/types": "^7.23.6" } }, "sha512-DV5bdJZTzZ0zn0DC24v3jD7Mnidh6xhKa4GfKCbq3sfW8kaWhDdZjP3i81geA8T33tdYqWKw4D3fVv0CwEgKVA=="], 1322 + 1267 1323 "babel-plugin-macros": ["babel-plugin-macros@3.1.0", "", { "dependencies": { "@babel/runtime": "^7.12.5", "cosmiconfig": "^7.0.0", "resolve": "^1.19.0" } }, "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg=="], 1268 1324 1269 1325 "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], ··· 1279 1335 "better-sqlite3": ["better-sqlite3@11.10.0", "", { "dependencies": { "bindings": "^1.5.0", "prebuild-install": "^7.1.1" } }, "sha512-EwhOpyXiOEL/lKzHz9AW1msWFNzGc/z+LzeB3/jnFJpxu+th2yqvzsSWas1v9jgs9+xiXJcD5A8CJxAG2TaghQ=="], 1280 1336 1281 1337 "bignumber.js": ["bignumber.js@9.3.0", "", {}, "sha512-EM7aMFTXbptt/wZdMlBv2t8IViwQL+h6SLHosp8Yf0dqJMTnY6iL32opnAB6kAdL0SZPuvcAzFr31o0c/R3/RA=="], 1338 + 1339 + "binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="], 1282 1340 1283 1341 "bindings": ["bindings@1.5.0", "", { "dependencies": { "file-uri-to-path": "1.0.0" } }, "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ=="], 1284 1342 ··· 1390 1448 1391 1449 "content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="], 1392 1450 1393 - "convert-source-map": ["convert-source-map@1.9.0", "", {}, "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="], 1451 + "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], 1394 1452 1395 1453 "cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], 1396 1454 ··· 1545 1603 "detect-node-es": ["detect-node-es@1.1.0", "", {}, "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="], 1546 1604 1547 1605 "devalue": ["devalue@4.3.3", "", {}, "sha512-UH8EL6H2ifcY8TbD2QsxwCC/pr5xSwPvv85LrLXVihmHVC3T3YqTCIwnR5ak0yO1KYqlxrPVOA/JVZJYPy2ATg=="], 1606 + 1607 + "diff": ["diff@8.0.2", "", {}, "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg=="], 1548 1608 1549 1609 "doctrine": ["doctrine@3.0.0", "", { "dependencies": { "esutils": "^2.0.2" } }, "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w=="], 1550 1610 ··· 1776 1836 1777 1837 "globals": ["globals@15.15.0", "", {}, "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg=="], 1778 1838 1839 + "goober": ["goober@2.1.16", "", { "peerDependencies": { "csstype": "^3.0.10" } }, "sha512-erjk19y1U33+XAMe1VTvIONHYoSqE4iS7BYUZfHaqeohLmnC0FdxEh7rQU+6MZ4OajItzjZFSRtVANrQwNq6/g=="], 1840 + 1779 1841 "google-auth-library": ["google-auth-library@9.15.1", "", { "dependencies": { "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", "gaxios": "^6.1.1", "gcp-metadata": "^6.1.0", "gtoken": "^7.0.0", "jws": "^4.0.0" } }, "sha512-Jb6Z0+nvECVz+2lzSMt9u98UsoakXxA2HGHMCxh+so3n90XgYWkq5dur19JAJV7ONiJY22yBTyJB1TSkvPq9Ng=="], 1780 1842 1781 1843 "google-logging-utils": ["google-logging-utils@0.0.2", "", {}, "sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ=="], ··· 1870 1932 1871 1933 "is-arrayish": ["is-arrayish@0.3.2", "", {}, "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="], 1872 1934 1935 + "is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="], 1936 + 1873 1937 "is-buffer": ["is-buffer@1.1.6", "", {}, "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="], 1874 1938 1875 1939 "is-callable": ["is-callable@1.2.7", "", {}, "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA=="], ··· 1907 1971 "is-typedarray": ["is-typedarray@1.0.0", "", {}, "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA=="], 1908 1972 1909 1973 "is-wsl": ["is-wsl@3.1.0", "", { "dependencies": { "is-inside-container": "^1.0.0" } }, "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw=="], 1974 + 1975 + "isbot": ["isbot@5.1.28", "", {}, "sha512-qrOp4g3xj8YNse4biorv6O5ZShwsJM0trsoda4y7j/Su7ZtTTfVXFzbKkpgcSoDrHS8FcTuUwcU04YimZlZOxw=="], 1910 1976 1911 1977 "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], 1912 1978 ··· 2360 2426 2361 2427 "react-range": ["react-range@1.10.0", "", { "peerDependencies": { "react": "*", "react-dom": "*" } }, "sha512-kDo0LiBUHIQIP8menx0UoxTnHr7UXBYpIYl/DR9jCaO1o29VwvCLpkP/qOTNQz5hkJadPg1uEM07XJcJ1XGoKw=="], 2362 2428 2363 - "react-router": ["react-router@7.6.2", "", { "dependencies": { "cookie": "^1.0.1", "set-cookie-parser": "^2.6.0" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" }, "optionalPeers": ["react-dom"] }, "sha512-U7Nv3y+bMimgWjhlT5CRdzHPu2/KVmqPwKUCChW8en5P3znxUqwlYFlbmyj8Rgp1SF6zs5X4+77kBVknkg6a0w=="], 2364 - 2365 - "react-router-dom": ["react-router-dom@7.6.2", "", { "dependencies": { "react-router": "7.6.2" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" } }, "sha512-Q8zb6VlTbdYKK5JJBLQEN06oTUa/RAbG/oQS1auK1I0TbJOXktqm+QENEVJU6QvWynlXPRBXI3fiOQcSEA78rA=="], 2366 - 2367 2429 "react-smooth": ["react-smooth@4.0.4", "", { "dependencies": { "fast-equals": "^5.0.1", "prop-types": "^15.8.1", "react-transition-group": "^4.4.5" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q=="], 2368 2430 2369 2431 "react-transition-group": ["react-transition-group@4.4.5", "", { "dependencies": { "@babel/runtime": "^7.5.5", "dom-helpers": "^5.0.1", "loose-envify": "^1.4.0", "prop-types": "^15.6.2" }, "peerDependencies": { "react": ">=16.6.0", "react-dom": ">=16.6.0" } }, "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g=="], ··· 2456 2518 2457 2519 "send": ["send@1.2.0", "", { "dependencies": { "debug": "^4.3.5", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.0", "mime-types": "^3.0.1", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.1" } }, "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw=="], 2458 2520 2459 - "serve-static": ["serve-static@2.2.0", "", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ=="], 2521 + "seroval": ["seroval@1.3.2", "", {}, "sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ=="], 2460 2522 2461 - "set-cookie-parser": ["set-cookie-parser@2.7.1", "", {}, "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ=="], 2523 + "seroval-plugins": ["seroval-plugins@1.3.2", "", { "peerDependencies": { "seroval": "^1.0" } }, "sha512-0QvCV2lM3aj/U3YozDiVwx9zpH0q8A60CTWIv4Jszj/givcudPb48B+rkU5D51NJ0pTpweGMttHjboPa9/zoIQ=="], 2524 + 2525 + "serve-static": ["serve-static@2.2.0", "", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ=="], 2462 2526 2463 2527 "set-function-length": ["set-function-length@1.2.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2" } }, "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg=="], 2464 2528 ··· 2495 2559 "sirv": ["sirv@3.0.1", "", { "dependencies": { "@polka/url": "^1.0.0-next.24", "mrmime": "^2.0.0", "totalist": "^3.0.0" } }, "sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A=="], 2496 2560 2497 2561 "slice-ansi": ["slice-ansi@4.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "astral-regex": "^2.0.0", "is-fullwidth-code-point": "^3.0.0" } }, "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ=="], 2562 + 2563 + "solid-js": ["solid-js@1.9.7", "", { "dependencies": { "csstype": "^3.1.0", "seroval": "~1.3.0", "seroval-plugins": "~1.3.0" } }, "sha512-/saTKi8iWEM233n5OSi1YHCCuh66ZIQ7aK2hsToPe4tqGm7qAejU1SwNuTPivbWAYq7SjuHVVYxxuZQNRbICiw=="], 2498 2564 2499 2565 "sonic-boom": ["sonic-boom@3.8.1", "", { "dependencies": { "atomic-sleep": "^1.0.0" } }, "sha512-y4Z8LCDBuum+PBP3lSV7RHrXscqksve/bi0as7mhwVnBW+/wUqKT/2Kb7um8yqcFy0duYbbPxzt89Zy2nOCaxg=="], 2500 2566 ··· 2578 2644 2579 2645 "tiny-invariant": ["tiny-invariant@1.3.3", "", {}, "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg=="], 2580 2646 2647 + "tiny-warning": ["tiny-warning@1.0.3", "", {}, "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA=="], 2648 + 2581 2649 "tinybench": ["tinybench@2.9.0", "", {}, "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg=="], 2582 2650 2583 2651 "tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="], ··· 2668 2736 2669 2737 "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], 2670 2738 2671 - "unplugin": ["unplugin@1.16.1", "", { "dependencies": { "acorn": "^8.14.0", "webpack-virtual-modules": "^0.6.2" } }, "sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w=="], 2739 + "unplugin": ["unplugin@2.3.5", "", { "dependencies": { "acorn": "^8.14.1", "picomatch": "^4.0.2", "webpack-virtual-modules": "^0.6.2" } }, "sha512-RyWSb5AHmGtjjNQ6gIlA67sHOsWpsbWpwDokLwTcejVdOjEkJZh7QKu14J00gDDVSh8kGH4KYC/TNBceXFZhtw=="], 2672 2740 2673 2741 "unstorage": ["unstorage@1.16.0", "", { "dependencies": { "anymatch": "^3.1.3", "chokidar": "^4.0.3", "destr": "^2.0.5", "h3": "^1.15.2", "lru-cache": "^10.4.3", "node-fetch-native": "^1.6.6", "ofetch": "^1.4.1", "ufo": "^1.6.1" }, "peerDependencies": { "@azure/app-configuration": "^1.8.0", "@azure/cosmos": "^4.2.0", "@azure/data-tables": "^13.3.0", "@azure/identity": "^4.6.0", "@azure/keyvault-secrets": "^4.9.0", "@azure/storage-blob": "^12.26.0", "@capacitor/preferences": "^6.0.3 || ^7.0.0", "@deno/kv": ">=0.9.0", "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0", "@planetscale/database": "^1.19.0", "@upstash/redis": "^1.34.3", "@vercel/blob": ">=0.27.1", "@vercel/kv": "^1.0.1", "aws4fetch": "^1.0.20", "db0": ">=0.2.1", "idb-keyval": "^6.2.1", "ioredis": "^5.4.2", "uploadthing": "^7.4.4" }, "optionalPeers": ["@azure/app-configuration", "@azure/cosmos", "@azure/data-tables", "@azure/identity", "@azure/keyvault-secrets", "@azure/storage-blob", "@capacitor/preferences", "@deno/kv", "@netlify/blobs", "@planetscale/database", "@upstash/redis", "@vercel/blob", "@vercel/kv", "aws4fetch", "db0", "idb-keyval", "ioredis", "uploadthing"] }, "sha512-WQ37/H5A7LcRPWfYOrDa1Ys02xAbpPJq6q5GkO88FBXVSQzHd7+BjEwfRqyaSWCv9MbsJy058GWjjPjcJ16GGA=="], 2674 2742 ··· 2796 2864 2797 2865 "@atproto/xrpc-server/express": ["express@4.21.2", "", { "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "0.19.0", "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" } }, "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA=="], 2798 2866 2799 - "@babel/core/convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], 2800 - 2801 2867 "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], 2802 2868 2803 - "@babel/generator/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="], 2869 + "@babel/generator/@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.12", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg=="], 2870 + 2871 + "@babel/generator/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.29", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ=="], 2804 2872 2805 2873 "@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], 2806 2874 2807 2875 "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], 2808 2876 2809 - "@babel/traverse/globals": ["globals@11.12.0", "", {}, "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="], 2877 + "@babel/helper-create-class-features-plugin/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], 2878 + 2879 + "@babel/helper-module-imports/@babel/traverse": ["@babel/traverse@7.27.4", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.27.3", "@babel/parser": "^7.27.4", "@babel/template": "^7.27.2", "@babel/types": "^7.27.3", "debug": "^4.3.1", "globals": "^11.1.0" } }, "sha512-oNcu2QbHqts9BtOWJosOVJapWjBDSxGCpFvikNR5TGDYDQf3JwpIoMzIKrvfoti93cLfPJEG4tH9SPVeyCGgdA=="], 2880 + 2881 + "@babel/helper-module-imports/@babel/types": ["@babel/types@7.27.6", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q=="], 2882 + 2883 + "@babel/helper-module-transforms/@babel/traverse": ["@babel/traverse@7.27.4", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.27.3", "@babel/parser": "^7.27.4", "@babel/template": "^7.27.2", "@babel/types": "^7.27.3", "debug": "^4.3.1", "globals": "^11.1.0" } }, "sha512-oNcu2QbHqts9BtOWJosOVJapWjBDSxGCpFvikNR5TGDYDQf3JwpIoMzIKrvfoti93cLfPJEG4tH9SPVeyCGgdA=="], 2884 + 2885 + "@babel/helpers/@babel/types": ["@babel/types@7.27.6", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q=="], 2886 + 2887 + "@babel/template/@babel/parser": ["@babel/parser@7.27.5", "", { "dependencies": { "@babel/types": "^7.27.3" }, "bin": "./bin/babel-parser.js" }, "sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg=="], 2888 + 2889 + "@babel/template/@babel/types": ["@babel/types@7.27.6", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q=="], 2810 2890 2811 2891 "@chromatic-com/storybook/strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="], 2812 2892 2813 2893 "@cloudflare/vitest-pool-workers/esbuild": ["esbuild@0.17.19", "", { "optionalDependencies": { "@esbuild/android-arm": "0.17.19", "@esbuild/android-arm64": "0.17.19", "@esbuild/android-x64": "0.17.19", "@esbuild/darwin-arm64": "0.17.19", "@esbuild/darwin-x64": "0.17.19", "@esbuild/freebsd-arm64": "0.17.19", "@esbuild/freebsd-x64": "0.17.19", "@esbuild/linux-arm": "0.17.19", "@esbuild/linux-arm64": "0.17.19", "@esbuild/linux-ia32": "0.17.19", "@esbuild/linux-loong64": "0.17.19", "@esbuild/linux-mips64el": "0.17.19", "@esbuild/linux-ppc64": "0.17.19", "@esbuild/linux-riscv64": "0.17.19", "@esbuild/linux-s390x": "0.17.19", "@esbuild/linux-x64": "0.17.19", "@esbuild/netbsd-x64": "0.17.19", "@esbuild/openbsd-x64": "0.17.19", "@esbuild/sunos-x64": "0.17.19", "@esbuild/win32-arm64": "0.17.19", "@esbuild/win32-ia32": "0.17.19", "@esbuild/win32-x64": "0.17.19" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw=="], 2814 2894 2815 2895 "@cloudflare/vitest-pool-workers/wrangler": ["wrangler@3.109.1", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.3.4", "@esbuild-plugins/node-globals-polyfill": "0.2.3", "@esbuild-plugins/node-modules-polyfill": "0.2.2", "blake3-wasm": "2.1.5", "esbuild": "0.17.19", "miniflare": "3.20250204.1", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.1", "workerd": "1.20250204.0" }, "optionalDependencies": { "fsevents": "~2.3.2", "sharp": "^0.33.5" }, "peerDependencies": { "@cloudflare/workers-types": "^4.20250204.0" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" } }, "sha512-1Jx+nZ6eCXPQ2rsGdrV6Qy/LGvhpqudeuTl4AYHl9P8Zugp44Uzxnj5w11qF4v/rv1dOZoA5TydSt9xMFfhpKg=="], 2896 + 2897 + "@emotion/babel-plugin/convert-source-map": ["convert-source-map@1.9.0", "", {}, "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="], 2816 2898 2817 2899 "@emotion/babel-plugin/source-map": ["source-map@0.5.7", "", {}, "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ=="], 2818 2900 ··· 2929 3011 "@storybook/addon-actions/uuid": ["uuid@9.0.1", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="], 2930 3012 2931 3013 "@storybook/core/esbuild": ["esbuild@0.25.5", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.5", "@esbuild/android-arm": "0.25.5", "@esbuild/android-arm64": "0.25.5", "@esbuild/android-x64": "0.25.5", "@esbuild/darwin-arm64": "0.25.5", "@esbuild/darwin-x64": "0.25.5", "@esbuild/freebsd-arm64": "0.25.5", "@esbuild/freebsd-x64": "0.25.5", "@esbuild/linux-arm": "0.25.5", "@esbuild/linux-arm64": "0.25.5", "@esbuild/linux-ia32": "0.25.5", "@esbuild/linux-loong64": "0.25.5", "@esbuild/linux-mips64el": "0.25.5", "@esbuild/linux-ppc64": "0.25.5", "@esbuild/linux-riscv64": "0.25.5", "@esbuild/linux-s390x": "0.25.5", "@esbuild/linux-x64": "0.25.5", "@esbuild/netbsd-arm64": "0.25.5", "@esbuild/netbsd-x64": "0.25.5", "@esbuild/openbsd-arm64": "0.25.5", "@esbuild/openbsd-x64": "0.25.5", "@esbuild/sunos-x64": "0.25.5", "@esbuild/win32-arm64": "0.25.5", "@esbuild/win32-ia32": "0.25.5", "@esbuild/win32-x64": "0.25.5" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ=="], 3014 + 3015 + "@storybook/csf-plugin/unplugin": ["unplugin@1.16.1", "", { "dependencies": { "acorn": "^8.14.0", "webpack-virtual-modules": "^0.6.2" } }, "sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w=="], 2932 3016 2933 3017 "@storybook/instrumenter/@vitest/utils": ["@vitest/utils@2.1.9", "", { "dependencies": { "@vitest/pretty-format": "2.1.9", "loupe": "^3.1.2", "tinyrainbow": "^1.2.0" } }, "sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ=="], 2934 3018 ··· 2948 3032 2949 3033 "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], 2950 3034 3035 + "@tanstack/router-plugin/chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], 3036 + 3037 + "@tanstack/router-utils/@babel/generator": ["@babel/generator@7.27.5", "", { "dependencies": { "@babel/parser": "^7.27.5", "@babel/types": "^7.27.3", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" } }, "sha512-ZGhA37l0e/g2s1Cnzdix0O3aLYm66eF8aufiVteOgnwxgnRP8GoyMj7VWsgWnQbVKXyge7hqrFh2K2TQM6t1Hw=="], 3038 + 3039 + "@tanstack/router-utils/@babel/parser": ["@babel/parser@7.27.5", "", { "dependencies": { "@babel/types": "^7.27.3" }, "bin": "./bin/babel-parser.js" }, "sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg=="], 3040 + 2951 3041 "@testing-library/dom/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], 2952 3042 2953 3043 "@testing-library/jest-dom/chalk": ["chalk@3.0.0", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg=="], ··· 2955 3045 "@testing-library/jest-dom/dom-accessibility-api": ["dom-accessibility-api@0.6.3", "", {}, "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w=="], 2956 3046 2957 3047 "@ts-morph/common/minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="], 3048 + 3049 + "@types/babel__core/@babel/parser": ["@babel/parser@7.27.5", "", { "dependencies": { "@babel/types": "^7.27.3" }, "bin": "./bin/babel-parser.js" }, "sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg=="], 3050 + 3051 + "@types/babel__core/@babel/types": ["@babel/types@7.27.6", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q=="], 3052 + 3053 + "@types/babel__generator/@babel/types": ["@babel/types@7.27.6", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q=="], 3054 + 3055 + "@types/babel__template/@babel/parser": ["@babel/parser@7.27.5", "", { "dependencies": { "@babel/types": "^7.27.3" }, "bin": "./bin/babel-parser.js" }, "sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg=="], 3056 + 3057 + "@types/babel__template/@babel/types": ["@babel/types@7.27.6", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q=="], 3058 + 3059 + "@types/babel__traverse/@babel/types": ["@babel/types@7.27.6", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q=="], 2958 3060 2959 3061 "@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], 2960 3062 ··· 3094 3196 3095 3197 "rc/strip-json-comments": ["strip-json-comments@2.0.1", "", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="], 3096 3198 3097 - "react-router/cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="], 3199 + "react-docgen/@babel/core": ["@babel/core@7.27.4", "", { "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.27.3", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.27.3", "@babel/helpers": "^7.27.4", "@babel/parser": "^7.27.4", "@babel/template": "^7.27.2", "@babel/traverse": "^7.27.4", "@babel/types": "^7.27.3", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-bXYxrXFubeYdvB0NhD/NBB3Qi6aZeV20GOWVI47t2dkecCEoneR4NPVcb7abpXDEvejgrUfFtG6vG/zxAKmg+g=="], 3200 + 3201 + "react-docgen/@babel/traverse": ["@babel/traverse@7.27.4", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.27.3", "@babel/parser": "^7.27.4", "@babel/template": "^7.27.2", "@babel/types": "^7.27.3", "debug": "^4.3.1", "globals": "^11.1.0" } }, "sha512-oNcu2QbHqts9BtOWJosOVJapWjBDSxGCpFvikNR5TGDYDQf3JwpIoMzIKrvfoti93cLfPJEG4tH9SPVeyCGgdA=="], 3202 + 3203 + "react-docgen/@babel/types": ["@babel/types@7.27.6", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q=="], 3098 3204 3099 3205 "react-uid/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="], 3100 3206 ··· 3248 3354 3249 3355 "@babel/helper-compilation-targets/lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], 3250 3356 3357 + "@babel/helper-module-imports/@babel/traverse/@babel/generator": ["@babel/generator@7.27.5", "", { "dependencies": { "@babel/parser": "^7.27.5", "@babel/types": "^7.27.3", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" } }, "sha512-ZGhA37l0e/g2s1Cnzdix0O3aLYm66eF8aufiVteOgnwxgnRP8GoyMj7VWsgWnQbVKXyge7hqrFh2K2TQM6t1Hw=="], 3358 + 3359 + "@babel/helper-module-imports/@babel/traverse/@babel/parser": ["@babel/parser@7.27.5", "", { "dependencies": { "@babel/types": "^7.27.3" }, "bin": "./bin/babel-parser.js" }, "sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg=="], 3360 + 3361 + "@babel/helper-module-imports/@babel/traverse/globals": ["globals@11.12.0", "", {}, "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="], 3362 + 3363 + "@babel/helper-module-transforms/@babel/traverse/@babel/generator": ["@babel/generator@7.27.5", "", { "dependencies": { "@babel/parser": "^7.27.5", "@babel/types": "^7.27.3", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" } }, "sha512-ZGhA37l0e/g2s1Cnzdix0O3aLYm66eF8aufiVteOgnwxgnRP8GoyMj7VWsgWnQbVKXyge7hqrFh2K2TQM6t1Hw=="], 3364 + 3365 + "@babel/helper-module-transforms/@babel/traverse/@babel/parser": ["@babel/parser@7.27.5", "", { "dependencies": { "@babel/types": "^7.27.3" }, "bin": "./bin/babel-parser.js" }, "sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg=="], 3366 + 3367 + "@babel/helper-module-transforms/@babel/traverse/@babel/types": ["@babel/types@7.27.6", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q=="], 3368 + 3369 + "@babel/helper-module-transforms/@babel/traverse/globals": ["globals@11.12.0", "", {}, "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="], 3370 + 3251 3371 "@chromatic-com/storybook/strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="], 3252 3372 3253 3373 "@cloudflare/vitest-pool-workers/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.17.19", "", { "os": "android", "cpu": "arm" }, "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A=="], ··· 3464 3584 3465 3585 "@storybook/core/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.5", "", { "os": "win32", "cpu": "x64" }, "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g=="], 3466 3586 3587 + "@storybook/csf-plugin/unplugin/acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], 3588 + 3467 3589 "@storybook/test/@vitest/expect/@vitest/utils": ["@vitest/utils@2.0.5", "", { "dependencies": { "@vitest/pretty-format": "2.0.5", "estree-walker": "^3.0.3", "loupe": "^3.1.1", "tinyrainbow": "^1.2.0" } }, "sha512-d8HKbqIcya+GR67mkZbrzhS5kKhtp8dQLcmRZLGTscGVg7yImT82cIrhtn2L8+VujWcy6KZweApgNmPsTAO/UQ=="], 3468 3590 3469 3591 "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime/tslib": ["tslib@2.6.2", "", {}, "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="], 3470 3592 3593 + "@tanstack/router-plugin/chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], 3594 + 3595 + "@tanstack/router-plugin/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], 3596 + 3597 + "@tanstack/router-utils/@babel/generator/@babel/types": ["@babel/types@7.27.6", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q=="], 3598 + 3599 + "@tanstack/router-utils/@babel/generator/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="], 3600 + 3601 + "@tanstack/router-utils/@babel/parser/@babel/types": ["@babel/types@7.27.6", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q=="], 3602 + 3471 3603 "@testing-library/dom/chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], 3472 3604 3473 3605 "@testing-library/dom/chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], ··· 3592 3724 3593 3725 "pkgroll/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.5", "", { "os": "win32", "cpu": "x64" }, "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g=="], 3594 3726 3727 + "react-docgen/@babel/core/@babel/generator": ["@babel/generator@7.27.5", "", { "dependencies": { "@babel/parser": "^7.27.5", "@babel/types": "^7.27.3", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" } }, "sha512-ZGhA37l0e/g2s1Cnzdix0O3aLYm66eF8aufiVteOgnwxgnRP8GoyMj7VWsgWnQbVKXyge7hqrFh2K2TQM6t1Hw=="], 3728 + 3729 + "react-docgen/@babel/core/@babel/parser": ["@babel/parser@7.27.5", "", { "dependencies": { "@babel/types": "^7.27.3" }, "bin": "./bin/babel-parser.js" }, "sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg=="], 3730 + 3731 + "react-docgen/@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], 3732 + 3733 + "react-docgen/@babel/traverse/@babel/generator": ["@babel/generator@7.27.5", "", { "dependencies": { "@babel/parser": "^7.27.5", "@babel/types": "^7.27.3", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" } }, "sha512-ZGhA37l0e/g2s1Cnzdix0O3aLYm66eF8aufiVteOgnwxgnRP8GoyMj7VWsgWnQbVKXyge7hqrFh2K2TQM6t1Hw=="], 3734 + 3735 + "react-docgen/@babel/traverse/@babel/parser": ["@babel/parser@7.27.5", "", { "dependencies": { "@babel/types": "^7.27.3" }, "bin": "./bin/babel-parser.js" }, "sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg=="], 3736 + 3737 + "react-docgen/@babel/traverse/globals": ["globals@11.12.0", "", {}, "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="], 3738 + 3595 3739 "send/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], 3596 3740 3597 3741 "styled-components/@emotion/is-prop-valid/@emotion/memoize": ["@emotion/memoize@0.8.1", "", {}, "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA=="], ··· 3756 3900 3757 3901 "@atproto/xrpc-server/express/type-is/media-typer": ["media-typer@0.3.0", "", {}, "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ=="], 3758 3902 3903 + "@babel/helper-module-imports/@babel/traverse/@babel/generator/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="], 3904 + 3905 + "@babel/helper-module-transforms/@babel/traverse/@babel/generator/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="], 3906 + 3759 3907 "@cloudflare/vitest-pool-workers/wrangler/unenv/ohash": ["ohash@1.1.6", "", {}, "sha512-TBu7PtV8YkAZn0tSxobKY2n2aAQva936lhRrj6957aDaCf9IEtqsKbgMzXE/F/sjqYOwmrukeORHNLe5glk7Cg=="], 3760 3908 3761 3909 "@cloudflare/vitest-pool-workers/wrangler/workerd/@cloudflare/workerd-darwin-64": ["@cloudflare/workerd-darwin-64@1.20250204.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-HpsgbWEfvdcwuZ8WAZhi1TlSCyyHC3tbghpKsOqGDaQNltyAFAWqa278TPNfcitYf/FmV4961v3eqUE+RFdHNQ=="], ··· 3818 3966 3819 3967 "@storybook/test/@vitest/expect/@vitest/utils/estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="], 3820 3968 3969 + "@tanstack/router-plugin/chokidar/readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], 3970 + 3821 3971 "@vitest/mocker/vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.21.5", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ=="], 3822 3972 3823 3973 "@vitest/mocker/vite/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.21.5", "", { "os": "android", "cpu": "arm" }, "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg=="], ··· 3873 4023 "@vitest/ui/vitest/vite/esbuild": ["esbuild@0.21.5", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.21.5", "@esbuild/android-arm": "0.21.5", "@esbuild/android-arm64": "0.21.5", "@esbuild/android-x64": "0.21.5", "@esbuild/darwin-arm64": "0.21.5", "@esbuild/darwin-x64": "0.21.5", "@esbuild/freebsd-arm64": "0.21.5", "@esbuild/freebsd-x64": "0.21.5", "@esbuild/linux-arm": "0.21.5", "@esbuild/linux-arm64": "0.21.5", "@esbuild/linux-ia32": "0.21.5", "@esbuild/linux-loong64": "0.21.5", "@esbuild/linux-mips64el": "0.21.5", "@esbuild/linux-ppc64": "0.21.5", "@esbuild/linux-riscv64": "0.21.5", "@esbuild/linux-s390x": "0.21.5", "@esbuild/linux-x64": "0.21.5", "@esbuild/netbsd-x64": "0.21.5", "@esbuild/openbsd-x64": "0.21.5", "@esbuild/sunos-x64": "0.21.5", "@esbuild/win32-arm64": "0.21.5", "@esbuild/win32-ia32": "0.21.5", "@esbuild/win32-x64": "0.21.5" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw=="], 3874 4024 3875 4025 "biome/chalk/strip-ansi/ansi-regex": ["ansi-regex@2.1.1", "", {}, "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA=="], 4026 + 4027 + "react-docgen/@babel/core/@babel/generator/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="], 4028 + 4029 + "react-docgen/@babel/traverse/@babel/generator/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="], 3876 4030 3877 4031 "vite-node/vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.21.5", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ=="], 3878 4032