an appview-less Bluesky client using Constellation and PDS Queries reddwarf.app
frontend spa bluesky reddwarf microcosm

Compare changes

Choose any two refs to compare.

+1
.gitignore
··· 7 7 .env 8 8 .nitro 9 9 .tanstack 10 + public/client-metadata.json
+51 -13
README.md
··· 1 - # Initial Red Dwarf Open Source Release 2 - i made red dwarf in three days 1 + # Red Dwarf 2 + Red Dwarf is a Bluesky client that does not use any AppView servers, instead it gathers the data from [Constellation](https://constellation.microcosm.blue/) and each users' PDS. 3 3 4 - it isnt really that well made 5 - (go take a look at `UniversalPostRenderer.tsx`) 4 + ![screenshot of red dwarf](/public/screenshot.jpg) 6 5 7 - further development is pending 8 - (especially around future plans for user-resolved constellation instances) 6 + huge thanks to [Microcosm](https://microcosm.blue/) for making this possible 9 7 10 - huge thanks to Constellation ([Microcosm](https://microcosm.blue/)) for making this possible 8 + ## running dev and build 9 + in the `vite.config.ts` file you should change these values 10 + ```ts 11 + const PROD_URL = "https://reddwarf.app" 12 + const DEV_URL = "https://local3768forumtest.whey.party" 13 + ``` 14 + the PROD_URL is what will compile your oauth client metadata so it is very important to change that. same for DEV_URL if you are using a tunnel for dev work 15 + 16 + run dev with `npm run dev` (port 3768) and build with `npm run build` (the output is the `dist` folder) 17 + 18 + ## useQuery 19 + Red Dwarf has been upgraded from its original bespoke caching system to Tanstack Query (react query). this migration was done to achieve a more robust and maintainable approach to data fetching and caching and state synchronization. ive seen serious performance gains from this switch! 20 + 21 + all core data fetching logic is now centralized in `src/utils/useQuery.ts` and exposed as a collection of custom react hooks. theres two basic types of custom hooks, the use-once, and the inifinite query ones (used for paginated requests like feed skeletons and listrecord) 11 22 12 23 ## UniversalPostRenderer 13 24 its a mega component rooted in my Masonry "[TestFront](https://testfront-87q.pages.dev/)" project. its goal is simple: have one component render everything. it has several shims to normalize different post data formats into a single format the component can handle. unlike TestFront, it has no animations, though some weird component splits might linger from the old version. 14 25 15 26 to adapt TestFront's bsky-api-based `UniversalPostRenderer` to Red Dwarf's model of fetching records directly from each user's PDS and then querying constellation for backlinks, i wrap it in `UniversalPostRendererATURILoader`, which handles raw record and backlink fetching. to bridge the gap between bsky api shapes like `PostView` and the raw record, i use `UniversalPostRendererRawRecordShim`. this way, the core `UniversalPostRenderer` remains the same between TestFront and Red Dwarf (with the only difference being in the red dwarf version the framer motion animations are removed). 16 27 28 + ## Microcosm 29 + ### Constellation 30 + the beating heart of Red Dwarf, the backlink index that provides contextual information not available from direct PDS queries. Every post's likes, replies, and reposts all come from constellation. Unfortunately i wasnt using tanstack query at the time (compared to its intensive use in the old version of ForumTest) so it is not using any caching 17 31 18 - ## PassAuthProvider 19 - a really bad app-password auth provider, inherited from TestFront and used in all my projects from TestFront to ForumTest (im very good at naming things). in ForumTest, its been superseded by the [OAuthProvider](https://tangled.sh/@whey.party/forumtest/blob/main/src/providers/OAuthProvider.tsx). i havent backported it here and maybe soon, although oauth makes it slightly more annoying to do development because it requires a tunnel so maybe someday if i managed to merge the password and oauth logins to provide both options 32 + ### Slingshot 33 + though Red Dwarf was made before Microcosm [Slingshot](https://slingshot.microcosm.blue) existed, it now uses Slingshot to reduce load from each respective PDS server. Slignshot 20 34 21 - ## Constellation 22 - the beating heart of Red Dwarf, the backlink index that provides contextual information not available from direct PDS queries. Every post's likes, replies, and reposts all come from constellation. Unfortunately i wasnt using tanstack query at the time (compared to its intensive use in the old version of ForumTest) so it is not using any caching 35 + ## UnifiedAuthProvider 36 + a merged auth provider with oauth and password based login. oauth makes it slightly more annoying to do development because it requires a tunnel, so so the password auth option is still here if you do prefer password login for whatever reason. 23 37 24 - Red Dwarf was made before Microcosm [Slingshot](https://slingshot.microcosm.blue) existed, and it would be a very good idea to migrate to it in the future maybe (to reduce load from individual PDS servers) 38 + ### Pass Auth 39 + a really bad app-password auth provider, inherited from TestFront and used in all my projects from TestFront to ForumTest (im very good at naming things). 40 + 41 + ### OAuth 42 + taken from ForumTest [OAuthProvider](https://tangled.sh/@whey.party/forumtest/blob/main/src/providers/OAuthProvider.tsx) 25 43 26 44 ## Custom Feeds 27 45 they work, but i havent implemented a simple way of viewing arbitraty feeds. currently it either loads discover (logged out) or your saved feeds (logged in) and its not a technical limitation i just havent implemented it yet ··· 34 52 and for list feeds, you can just use something like graze or skyfeed to input a list of users and output a custom feed 35 53 36 54 ## Tanstack Router 37 - it does the job, nothing very specific was used here 55 + something specific was used here 56 + 57 + so tanstack router is used as the base, but the home route is using tanstack-router-keepalive to preserve the route for better responsiveness, and it also saves scroll position of feeds into jotai (persistent) 58 + 59 + i previously used a tanstack router loader to ensure the tanstack query cache is ready to prevent scroll jumps but it is way too slow so i replaced it with tanstack-router-keepalive 60 + 61 + ## Icons 62 + this project uses Material icons. do not the light variant. sometimes i use `Mdi` if the icon needed doesnt exist in `MaterialSymbols` 63 + 64 + the project uses unplugin icon auto import, so you can just use the component and itll just work! 65 + 66 + the format is: 67 + ```tsx 68 + <IconMaterialSymbols{icon name here} /> 69 + // or 70 + <IconMdi{icon name here} /> 71 + ``` 72 + 73 + you can get the full list of icon names from iconify ([Material Symbols](https://icon-sets.iconify.design/material-symbols/) or [MDI](https://icon-sets.iconify.design/mdi/)) 74 + 75 + while it is nice to keep everything consistent by using material icons, if the icon you need is not provided by either material symbols nor mdi, you are allowed to just grab any icon from any pack (please do prioritize icons that fit in)
+59
eslint.config.ts
··· 1 + import eslintJs from "@eslint/js"; 2 + import eslintReact from "@eslint-react/eslint-plugin"; 3 + import { defineConfig } from "eslint/config"; 4 + import reactHooks from "eslint-plugin-react-hooks"; 5 + import simpleImportSort from "eslint-plugin-simple-import-sort"; 6 + import unusedImports from "eslint-plugin-unused-imports"; 7 + import tseslint from "typescript-eslint"; 8 + 9 + export default defineConfig([ 10 + { 11 + files: ["**/*.ts", "**/*.tsx"], 12 + extends: [ 13 + eslintJs.configs.recommended, 14 + tseslint.configs.recommended, 15 + eslintReact.configs["recommended-typescript"], 16 + reactHooks.configs.flat["recommended-latest"], 17 + ], 18 + plugins: { 19 + "react-hooks": reactHooks, 20 + "simple-import-sort": simpleImportSort, 21 + "unused-imports": unusedImports, 22 + }, 23 + languageOptions: { 24 + parser: tseslint.parser, 25 + parserOptions: { 26 + projectService: true, 27 + tsconfigRootDir: import.meta.dirname, 28 + }, 29 + }, 30 + rules: { 31 + // Unused imports 32 + "unused-imports/no-unused-imports": "error", 33 + "unused-imports/no-unused-vars": [ 34 + "warn", 35 + { 36 + vars: "all", 37 + varsIgnorePattern: "^_", 38 + args: "after-used", 39 + argsIgnorePattern: "^_", 40 + }, 41 + ], 42 + 43 + // Auto sort imports 44 + "simple-import-sort/imports": "error", 45 + "simple-import-sort/exports": "error", 46 + 47 + 48 + "@typescript-eslint/no-unused-vars": [ 49 + "warn", 50 + { 51 + argsIgnorePattern: "^_", 52 + varsIgnorePattern: "^_", 53 + caughtErrorsIgnorePattern: "^_", 54 + }, 55 + ], 56 + "@typescript-eslint/no-explicit-any": "warn", 57 + }, 58 + }, 59 + ]);
+2 -3
index.html
··· 4 4 <meta charset="UTF-8" /> 5 5 <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 6 6 <link rel="icon" href="/favicon.ico" /> 7 - <meta name="theme-color" content="#000000" /> 7 + <meta name="theme-color" content="#180001" /> 8 8 <meta 9 9 name="description" 10 - content="Web site created using create-tsrouter-app" 10 + content="an appview-less Bluesky client using Constellation and PDS Queries" 11 11 /> 12 12 <link rel="apple-touch-icon" href="/redstar.png" /> 13 13 <link rel="manifest" href="/manifest.json" /> 14 - <link rel="stylesheet" href="/src/styles/app.css" /> 15 14 <title>Red Dwarf</title> 16 15 </head> 17 16 <body>
+48
oauthdev.mts
··· 1 + import fs from 'fs'; 2 + import path from 'path'; 3 + //import { generateClientMetadata } from './src/helpers/oauthClient' 4 + export const generateClientMetadata = (appOrigin: string) => { 5 + const callbackPath = '/callback'; 6 + 7 + return { 8 + "client_id": `${appOrigin}/client-metadata.json`, 9 + "client_name": "ForumTest", 10 + "client_uri": appOrigin, 11 + "logo_uri": `${appOrigin}/logo192.png`, 12 + "tos_uri": `${appOrigin}/terms-of-service`, 13 + "policy_uri": `${appOrigin}/privacy-policy`, 14 + "redirect_uris": [`${appOrigin}${callbackPath}`] as [string, ...string[]], 15 + "scope": "atproto transition:generic", 16 + "grant_types": ["authorization_code", "refresh_token"] as ["authorization_code", "refresh_token"], 17 + "response_types": ["code"] as ["code"], 18 + "token_endpoint_auth_method": "none" as "none", 19 + "application_type": "web" as "web", 20 + "dpop_bound_access_tokens": true 21 + }; 22 + } 23 + 24 + 25 + export function generateMetadataPlugin({prod, dev}:{prod: string, dev: string}) { 26 + return { 27 + name: 'vite-plugin-generate-metadata', 28 + config(_config: any, { mode }: any) { 29 + let appOrigin; 30 + if (mode === 'production') { 31 + appOrigin = prod 32 + if (!appOrigin || !appOrigin.startsWith('https://')) { 33 + throw new Error('VITE_APP_ORIGIN environment variable must be set to a valid HTTPS URL for production build.'); 34 + } 35 + } else { 36 + appOrigin = dev; 37 + } 38 + 39 + 40 + const metadata = generateClientMetadata(appOrigin); 41 + const outputPath = path.resolve(process.cwd(), 'public', 'client-metadata.json'); 42 + 43 + fs.writeFileSync(outputPath, JSON.stringify(metadata, null, 2)); 44 + 45 + // /*mass comment*/ console.log(`โœ… Generated client-metadata.json for ${appOrigin}`); 46 + }, 47 + }; 48 + }
+9090 -32
package-lock.json
··· 7 7 "name": "red-dwarf-tanstack", 8 8 "dependencies": { 9 9 "@atproto/api": "^0.16.6", 10 + "@atproto/oauth-client-browser": "^0.3.33", 11 + "@radix-ui/react-dialog": "^1.1.15", 12 + "@radix-ui/react-dropdown-menu": "^2.1.16", 13 + "@radix-ui/react-hover-card": "^1.1.15", 14 + "@radix-ui/react-slider": "^1.3.6", 10 15 "@tailwindcss/vite": "^4.0.6", 16 + "@tanstack/query-sync-storage-persister": "^5.85.6", 11 17 "@tanstack/react-devtools": "^0.2.2", 18 + "@tanstack/react-query": "^5.85.6", 19 + "@tanstack/react-query-persist-client": "^5.85.6", 12 20 "@tanstack/react-router": "^1.130.2", 13 21 "@tanstack/react-router-devtools": "^1.131.5", 14 22 "@tanstack/router-plugin": "^1.121.2", 23 + "dompurify": "^3.3.0", 24 + "i": "^0.3.7", 15 25 "idb-keyval": "^6.2.2", 26 + "jotai": "^2.13.1", 27 + "npm": "^11.6.2", 28 + "radix-ui": "^1.4.3", 16 29 "react": "^19.0.0", 17 30 "react-dom": "^19.0.0", 18 31 "react-player": "^3.3.2", 19 - "tailwindcss": "^4.0.6" 32 + "tailwindcss": "^4.0.6", 33 + "tanstack-router-keepalive": "^1.0.0" 20 34 }, 21 35 "devDependencies": { 36 + "@eslint-react/eslint-plugin": "^2.2.1", 37 + "@iconify-icon/react": "^3.0.1", 38 + "@iconify-json/material-symbols": "^1.2.42", 39 + "@iconify-json/mdi": "^1.2.3", 40 + "@iconify/json": "^2.2.396", 41 + "@svgr/core": "^8.1.0", 42 + "@svgr/plugin-jsx": "^8.1.0", 22 43 "@testing-library/dom": "^10.4.0", 23 44 "@testing-library/react": "^16.2.0", 24 45 "@types/node": "^24.3.0", 25 46 "@types/react": "^19.0.8", 26 47 "@types/react-dom": "^19.0.3", 48 + "@typescript-eslint/eslint-plugin": "^8.46.1", 49 + "@typescript-eslint/parser": "^8.46.1", 27 50 "@vitejs/plugin-react": "^4.3.4", 51 + "babel-plugin-react-compiler": "^1.0.0", 52 + "eslint-plugin-react": "^7.37.5", 53 + "eslint-plugin-react-hooks": "^7.0.0", 54 + "eslint-plugin-simple-import-sort": "^12.1.1", 55 + "eslint-plugin-unused-imports": "^4.2.0", 28 56 "jsdom": "^26.0.0", 29 57 "prettier": "^3.6.2", 30 58 "typescript": "^5.7.2", 59 + "typescript-eslint": "^8.46.1", 60 + "unplugin-auto-import": "^20.2.0", 61 + "unplugin-icons": "^22.4.2", 31 62 "vite": "^6.3.5", 32 63 "vitest": "^3.0.5", 33 64 "web-vitals": "^4.2.4" ··· 46 77 "node": ">=6.0.0" 47 78 } 48 79 }, 80 + "node_modules/@antfu/install-pkg": { 81 + "version": "1.1.0", 82 + "resolved": "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-1.1.0.tgz", 83 + "integrity": "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==", 84 + "dev": true, 85 + "license": "MIT", 86 + "dependencies": { 87 + "package-manager-detector": "^1.3.0", 88 + "tinyexec": "^1.0.1" 89 + }, 90 + "funding": { 91 + "url": "https://github.com/sponsors/antfu" 92 + } 93 + }, 94 + "node_modules/@antfu/install-pkg/node_modules/tinyexec": { 95 + "version": "1.0.1", 96 + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz", 97 + "integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==", 98 + "dev": true, 99 + "license": "MIT" 100 + }, 101 + "node_modules/@antfu/utils": { 102 + "version": "9.3.0", 103 + "resolved": "https://registry.npmjs.org/@antfu/utils/-/utils-9.3.0.tgz", 104 + "integrity": "sha512-9hFT4RauhcUzqOE4f1+frMKLZrgNog5b06I7VmZQV1BkvwvqrbC8EBZf3L1eEL2AKb6rNKjER0sEvJiSP1FXEA==", 105 + "dev": true, 106 + "license": "MIT", 107 + "funding": { 108 + "url": "https://github.com/sponsors/antfu" 109 + } 110 + }, 49 111 "node_modules/@asamuzakjp/css-color": { 50 112 "version": "3.2.0", 51 113 "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.2.0.tgz", ··· 67 129 "dev": true, 68 130 "license": "ISC" 69 131 }, 132 + "node_modules/@atproto-labs/did-resolver": { 133 + "version": "0.2.2", 134 + "resolved": "https://registry.npmjs.org/@atproto-labs/did-resolver/-/did-resolver-0.2.2.tgz", 135 + "integrity": "sha512-ca2B7xR43tVoQ8XxBvha58DXwIH8cIyKQl6lpOKGkPUrJuFoO4iCLlDiSDi2Ueh+yE1rMDPP/qveHdajgDX3WQ==", 136 + "license": "MIT", 137 + "dependencies": { 138 + "@atproto-labs/fetch": "0.2.3", 139 + "@atproto-labs/pipe": "0.1.1", 140 + "@atproto-labs/simple-store": "0.3.0", 141 + "@atproto-labs/simple-store-memory": "0.1.4", 142 + "@atproto/did": "0.2.1", 143 + "zod": "^3.23.8" 144 + } 145 + }, 146 + "node_modules/@atproto-labs/fetch": { 147 + "version": "0.2.3", 148 + "resolved": "https://registry.npmjs.org/@atproto-labs/fetch/-/fetch-0.2.3.tgz", 149 + "integrity": "sha512-NZtbJOCbxKUFRFKMpamT38PUQMY0hX0p7TG5AEYOPhZKZEP7dHZ1K2s1aB8MdVH0qxmqX7nQleNrrvLf09Zfdw==", 150 + "license": "MIT", 151 + "dependencies": { 152 + "@atproto-labs/pipe": "0.1.1" 153 + } 154 + }, 155 + "node_modules/@atproto-labs/handle-resolver": { 156 + "version": "0.3.2", 157 + "resolved": "https://registry.npmjs.org/@atproto-labs/handle-resolver/-/handle-resolver-0.3.2.tgz", 158 + "integrity": "sha512-KIerCzh3qb+zZoqWbIvTlvBY0XPq0r56kwViaJY/LTe/3oPO2JaqlYKS/F4dByWBhHK6YoUOJ0sWrh6PMJl40A==", 159 + "license": "MIT", 160 + "dependencies": { 161 + "@atproto-labs/simple-store": "0.3.0", 162 + "@atproto-labs/simple-store-memory": "0.1.4", 163 + "@atproto/did": "0.2.1", 164 + "zod": "^3.23.8" 165 + } 166 + }, 167 + "node_modules/@atproto-labs/identity-resolver": { 168 + "version": "0.3.2", 169 + "resolved": "https://registry.npmjs.org/@atproto-labs/identity-resolver/-/identity-resolver-0.3.2.tgz", 170 + "integrity": "sha512-MYxO9pe0WsFyi5HFdKAwqIqHfiF2kBPoVhAIuH/4PYHzGr799ED47xLhNMxR3ZUYrJm5+TQzWXypGZ0Btw1Ffw==", 171 + "license": "MIT", 172 + "dependencies": { 173 + "@atproto-labs/did-resolver": "0.2.2", 174 + "@atproto-labs/handle-resolver": "0.3.2" 175 + } 176 + }, 177 + "node_modules/@atproto-labs/pipe": { 178 + "version": "0.1.1", 179 + "resolved": "https://registry.npmjs.org/@atproto-labs/pipe/-/pipe-0.1.1.tgz", 180 + "integrity": "sha512-hdNw2oUs2B6BN1lp+32pF7cp8EMKuIN5Qok2Vvv/aOpG/3tNSJ9YkvfI0k6Zd188LeDDYRUpYpxcoFIcGH/FNg==", 181 + "license": "MIT" 182 + }, 183 + "node_modules/@atproto-labs/simple-store": { 184 + "version": "0.3.0", 185 + "resolved": "https://registry.npmjs.org/@atproto-labs/simple-store/-/simple-store-0.3.0.tgz", 186 + "integrity": "sha512-nOb6ONKBRJHRlukW1sVawUkBqReLlLx6hT35VS3imaNPwiXDxLnTK7lxw3Lrl9k5yugSBDQAkZAq3MPTEFSUBQ==", 187 + "license": "MIT" 188 + }, 189 + "node_modules/@atproto-labs/simple-store-memory": { 190 + "version": "0.1.4", 191 + "resolved": "https://registry.npmjs.org/@atproto-labs/simple-store-memory/-/simple-store-memory-0.1.4.tgz", 192 + "integrity": "sha512-3mKY4dP8I7yKPFj9VKpYyCRzGJOi5CEpOLPlRhoJyLmgs3J4RzDrjn323Oakjz2Aj2JzRU/AIvWRAZVhpYNJHw==", 193 + "license": "MIT", 194 + "dependencies": { 195 + "@atproto-labs/simple-store": "0.3.0", 196 + "lru-cache": "^10.2.0" 197 + } 198 + }, 199 + "node_modules/@atproto-labs/simple-store-memory/node_modules/lru-cache": { 200 + "version": "10.4.3", 201 + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", 202 + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", 203 + "license": "ISC" 204 + }, 70 205 "node_modules/@atproto/api": { 71 206 "version": "0.16.6", 72 207 "resolved": "https://registry.npmjs.org/@atproto/api/-/api-0.16.6.tgz", ··· 84 219 } 85 220 }, 86 221 "node_modules/@atproto/common-web": { 87 - "version": "0.4.2", 88 - "resolved": "https://registry.npmjs.org/@atproto/common-web/-/common-web-0.4.2.tgz", 89 - "integrity": "sha512-vrXwGNoFGogodjQvJDxAeP3QbGtawgZute2ed1XdRO0wMixLk3qewtikZm06H259QDJVu6voKC5mubml+WgQUw==", 222 + "version": "0.4.3", 223 + "resolved": "https://registry.npmjs.org/@atproto/common-web/-/common-web-0.4.3.tgz", 224 + "integrity": "sha512-nRDINmSe4VycJzPo6fP/hEltBcULFxt9Kw7fQk6405FyAWZiTluYHlXOnU7GkQfeUK44OENG1qFTBcmCJ7e8pg==", 90 225 "license": "MIT", 91 226 "dependencies": { 92 227 "graphemer": "^1.4.0", ··· 95 230 "zod": "^3.23.8" 96 231 } 97 232 }, 233 + "node_modules/@atproto/did": { 234 + "version": "0.2.1", 235 + "resolved": "https://registry.npmjs.org/@atproto/did/-/did-0.2.1.tgz", 236 + "integrity": "sha512-1i5BTU2GnBaaeYWhxUOnuEKFVq9euT5+dQPFabHpa927BlJ54PmLGyBBaOI7/NbLmN5HWwBa18SBkMpg3jGZRA==", 237 + "license": "MIT", 238 + "dependencies": { 239 + "zod": "^3.23.8" 240 + } 241 + }, 242 + "node_modules/@atproto/jwk": { 243 + "version": "0.6.0", 244 + "resolved": "https://registry.npmjs.org/@atproto/jwk/-/jwk-0.6.0.tgz", 245 + "integrity": "sha512-bDoJPvt7TrQVi/rBfBrSSpGykhtIriKxeYCYQTiPRKFfyRhbgpElF0wPXADjIswnbzZdOwbY63az4E/CFVT3Tw==", 246 + "license": "MIT", 247 + "dependencies": { 248 + "multiformats": "^9.9.0", 249 + "zod": "^3.23.8" 250 + } 251 + }, 252 + "node_modules/@atproto/jwk-jose": { 253 + "version": "0.1.11", 254 + "resolved": "https://registry.npmjs.org/@atproto/jwk-jose/-/jwk-jose-0.1.11.tgz", 255 + "integrity": "sha512-i4Fnr2sTBYmMmHXl7NJh8GrCH+tDQEVWrcDMDnV5DjJfkgT17wIqvojIw9SNbSL4Uf0OtfEv6AgG0A+mgh8b5Q==", 256 + "license": "MIT", 257 + "dependencies": { 258 + "@atproto/jwk": "0.6.0", 259 + "jose": "^5.2.0" 260 + } 261 + }, 262 + "node_modules/@atproto/jwk-webcrypto": { 263 + "version": "0.2.0", 264 + "resolved": "https://registry.npmjs.org/@atproto/jwk-webcrypto/-/jwk-webcrypto-0.2.0.tgz", 265 + "integrity": "sha512-UmgRrrEAkWvxwhlwe30UmDOdTEFidlIzBC7C3cCbeJMcBN1x8B3KH+crXrsTqfWQBG58mXgt8wgSK3Kxs2LhFg==", 266 + "license": "MIT", 267 + "dependencies": { 268 + "@atproto/jwk": "0.6.0", 269 + "@atproto/jwk-jose": "0.1.11", 270 + "zod": "^3.23.8" 271 + } 272 + }, 98 273 "node_modules/@atproto/lexicon": { 99 - "version": "0.5.0", 100 - "resolved": "https://registry.npmjs.org/@atproto/lexicon/-/lexicon-0.5.0.tgz", 101 - "integrity": "sha512-3aAzEAy9EAPs3CxznzMhEcqDd7m3vz1eze/ya9/ThbB7yleqJIhz5GY2q76tCCwHPhn5qDDMhlA9kKV6fG23gA==", 274 + "version": "0.5.1", 275 + "resolved": "https://registry.npmjs.org/@atproto/lexicon/-/lexicon-0.5.1.tgz", 276 + "integrity": "sha512-y8AEtYmfgVl4fqFxqXAeGvhesiGkxiy3CWoJIfsFDDdTlZUC8DFnZrYhcqkIop3OlCkkljvpSJi1hbeC1tbi8A==", 102 277 "license": "MIT", 103 278 "dependencies": { 104 - "@atproto/common-web": "^0.4.2", 279 + "@atproto/common-web": "^0.4.3", 105 280 "@atproto/syntax": "^0.4.1", 106 281 "iso-datestring-validator": "^2.2.2", 107 282 "multiformats": "^9.9.0", 108 283 "zod": "^3.23.8" 109 284 } 110 285 }, 286 + "node_modules/@atproto/oauth-client": { 287 + "version": "0.5.7", 288 + "resolved": "https://registry.npmjs.org/@atproto/oauth-client/-/oauth-client-0.5.7.tgz", 289 + "integrity": "sha512-pDvbvy9DCxrAJv7bAbBUzWrHZKhFy091HvEMZhr+EyZA6gSCGYmmQJG/coDj0oICSVQeafAZd+IxR0YUCWwmEg==", 290 + "license": "MIT", 291 + "dependencies": { 292 + "@atproto-labs/did-resolver": "0.2.2", 293 + "@atproto-labs/fetch": "0.2.3", 294 + "@atproto-labs/handle-resolver": "0.3.2", 295 + "@atproto-labs/identity-resolver": "0.3.2", 296 + "@atproto-labs/simple-store": "0.3.0", 297 + "@atproto-labs/simple-store-memory": "0.1.4", 298 + "@atproto/did": "0.2.1", 299 + "@atproto/jwk": "0.6.0", 300 + "@atproto/oauth-types": "0.4.2", 301 + "@atproto/xrpc": "0.7.5", 302 + "core-js": "^3", 303 + "multiformats": "^9.9.0", 304 + "zod": "^3.23.8" 305 + } 306 + }, 307 + "node_modules/@atproto/oauth-client-browser": { 308 + "version": "0.3.33", 309 + "resolved": "https://registry.npmjs.org/@atproto/oauth-client-browser/-/oauth-client-browser-0.3.33.tgz", 310 + "integrity": "sha512-IvHn/5W3e9GXFUGXQ4MV19E4HXY4zJFgu+eZRWexIXnZl4GwgTH7op8J1SosczdOK1Ngu+LnHE6npcNhUGGd6Q==", 311 + "license": "MIT", 312 + "dependencies": { 313 + "@atproto-labs/did-resolver": "0.2.2", 314 + "@atproto-labs/handle-resolver": "0.3.2", 315 + "@atproto-labs/simple-store": "0.3.0", 316 + "@atproto/did": "0.2.1", 317 + "@atproto/jwk": "0.6.0", 318 + "@atproto/jwk-webcrypto": "0.2.0", 319 + "@atproto/oauth-client": "0.5.7", 320 + "@atproto/oauth-types": "0.4.2", 321 + "core-js": "^3" 322 + } 323 + }, 324 + "node_modules/@atproto/oauth-types": { 325 + "version": "0.4.2", 326 + "resolved": "https://registry.npmjs.org/@atproto/oauth-types/-/oauth-types-0.4.2.tgz", 327 + "integrity": "sha512-gcfNTyFsPJcYDf79M0iKHykWqzxloscioKoerdIN3MTS3htiNOSgZjm2p8ho7pdrElLzea3qktuhTQI39j1XFQ==", 328 + "license": "MIT", 329 + "dependencies": { 330 + "@atproto/did": "0.2.1", 331 + "@atproto/jwk": "0.6.0", 332 + "zod": "^3.23.8" 333 + } 334 + }, 111 335 "node_modules/@atproto/syntax": { 112 336 "version": "0.4.1", 113 337 "resolved": "https://registry.npmjs.org/@atproto/syntax/-/syntax-0.4.1.tgz", ··· 115 339 "license": "MIT" 116 340 }, 117 341 "node_modules/@atproto/xrpc": { 118 - "version": "0.7.4", 119 - "resolved": "https://registry.npmjs.org/@atproto/xrpc/-/xrpc-0.7.4.tgz", 120 - "integrity": "sha512-sDi68+QE1XHegTaNAndlX41Gp827pouSzSs8CyAwhrqZdsJUxE3P7TMtrA0z+zAjvxVyvzscRc0TsN/fGUGrhw==", 342 + "version": "0.7.5", 343 + "resolved": "https://registry.npmjs.org/@atproto/xrpc/-/xrpc-0.7.5.tgz", 344 + "integrity": "sha512-MUYNn5d2hv8yVegRL0ccHvTHAVj5JSnW07bkbiaz96UH45lvYNRVwt44z+yYVnb0/mvBzyD3/ZQ55TRGt7fHkA==", 121 345 "license": "MIT", 122 346 "dependencies": { 123 - "@atproto/lexicon": "^0.5.0", 347 + "@atproto/lexicon": "^0.5.1", 124 348 "zod": "^3.23.8" 125 349 } 126 350 }, ··· 1102 1326 "node": ">=18" 1103 1327 } 1104 1328 }, 1329 + "node_modules/@eslint-community/eslint-utils": { 1330 + "version": "4.9.0", 1331 + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", 1332 + "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", 1333 + "dev": true, 1334 + "license": "MIT", 1335 + "dependencies": { 1336 + "eslint-visitor-keys": "^3.4.3" 1337 + }, 1338 + "engines": { 1339 + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 1340 + }, 1341 + "funding": { 1342 + "url": "https://opencollective.com/eslint" 1343 + }, 1344 + "peerDependencies": { 1345 + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" 1346 + } 1347 + }, 1348 + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { 1349 + "version": "3.4.3", 1350 + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", 1351 + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", 1352 + "dev": true, 1353 + "license": "Apache-2.0", 1354 + "engines": { 1355 + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 1356 + }, 1357 + "funding": { 1358 + "url": "https://opencollective.com/eslint" 1359 + } 1360 + }, 1361 + "node_modules/@eslint-community/regexpp": { 1362 + "version": "4.12.1", 1363 + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", 1364 + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", 1365 + "dev": true, 1366 + "license": "MIT", 1367 + "engines": { 1368 + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" 1369 + } 1370 + }, 1371 + "node_modules/@eslint-react/ast": { 1372 + "version": "2.2.1", 1373 + "resolved": "https://registry.npmjs.org/@eslint-react/ast/-/ast-2.2.1.tgz", 1374 + "integrity": "sha512-bjzSAdtTT/gIU0/olh8Kki57Mnadl5BIjJxcA3wqxcAvNwYAt3yl0CM4LRqVqW4kJneslCNqB5UriRJJPSKhuA==", 1375 + "dev": true, 1376 + "license": "MIT", 1377 + "dependencies": { 1378 + "@eslint-react/eff": "2.2.1", 1379 + "@typescript-eslint/types": "^8.46.0", 1380 + "@typescript-eslint/typescript-estree": "^8.46.0", 1381 + "@typescript-eslint/utils": "^8.46.0", 1382 + "string-ts": "^2.2.1" 1383 + }, 1384 + "engines": { 1385 + "node": ">=20.19.0" 1386 + } 1387 + }, 1388 + "node_modules/@eslint-react/core": { 1389 + "version": "2.2.1", 1390 + "resolved": "https://registry.npmjs.org/@eslint-react/core/-/core-2.2.1.tgz", 1391 + "integrity": "sha512-slP1G7sReKgijlDx56SDhgkpS6OjoNCEqItuY6Ayo4viIIYMyQ5LkPJ2BJ5xbBxSklyszQ/yP+8UFDK6uzYChQ==", 1392 + "dev": true, 1393 + "license": "MIT", 1394 + "dependencies": { 1395 + "@eslint-react/ast": "2.2.1", 1396 + "@eslint-react/eff": "2.2.1", 1397 + "@eslint-react/shared": "2.2.1", 1398 + "@eslint-react/var": "2.2.1", 1399 + "@typescript-eslint/scope-manager": "^8.46.0", 1400 + "@typescript-eslint/types": "^8.46.0", 1401 + "@typescript-eslint/utils": "^8.46.0", 1402 + "birecord": "^0.1.1", 1403 + "ts-pattern": "^5.8.0" 1404 + }, 1405 + "engines": { 1406 + "node": ">=20.19.0" 1407 + } 1408 + }, 1409 + "node_modules/@eslint-react/eff": { 1410 + "version": "2.2.1", 1411 + "resolved": "https://registry.npmjs.org/@eslint-react/eff/-/eff-2.2.1.tgz", 1412 + "integrity": "sha512-u9IJB9O8Jwo4b40CLIoF1HePsOvFLdbRKdCVUBEv2TPihae/ltYRD45mCI0bHLroYUxevC1nvD/cQRfwJPH0zg==", 1413 + "dev": true, 1414 + "license": "MIT", 1415 + "engines": { 1416 + "node": ">=20.19.0" 1417 + } 1418 + }, 1419 + "node_modules/@eslint-react/eslint-plugin": { 1420 + "version": "2.2.1", 1421 + "resolved": "https://registry.npmjs.org/@eslint-react/eslint-plugin/-/eslint-plugin-2.2.1.tgz", 1422 + "integrity": "sha512-BjIwFBvgo2b8d5KaTm3qkqKHMFT0HJmAYUZ6TT5j+C/2lWQK3mANxoPwD9Kq4tuI/zw5dINyKxQp6Kr8yGybHQ==", 1423 + "dev": true, 1424 + "license": "MIT", 1425 + "dependencies": { 1426 + "@eslint-react/eff": "2.2.1", 1427 + "@eslint-react/shared": "2.2.1", 1428 + "@typescript-eslint/scope-manager": "^8.46.0", 1429 + "@typescript-eslint/type-utils": "^8.46.0", 1430 + "@typescript-eslint/types": "^8.46.0", 1431 + "@typescript-eslint/utils": "^8.46.0", 1432 + "eslint-plugin-react-dom": "2.2.1", 1433 + "eslint-plugin-react-hooks-extra": "2.2.1", 1434 + "eslint-plugin-react-naming-convention": "2.2.1", 1435 + "eslint-plugin-react-web-api": "2.2.1", 1436 + "eslint-plugin-react-x": "2.2.1", 1437 + "ts-api-utils": "^2.1.0" 1438 + }, 1439 + "engines": { 1440 + "node": ">=20.19.0" 1441 + }, 1442 + "peerDependencies": { 1443 + "eslint": "^9.37.0", 1444 + "typescript": "^5.9.3" 1445 + } 1446 + }, 1447 + "node_modules/@eslint-react/shared": { 1448 + "version": "2.2.1", 1449 + "resolved": "https://registry.npmjs.org/@eslint-react/shared/-/shared-2.2.1.tgz", 1450 + "integrity": "sha512-YxYo4Svw2OzV0XDj4HLJKcmB4vtAyQghSE1ZFKN5i90CIbfp/RYBNK6VVrIbxtXu6tAsJ0lSBZiepHfn3i/l8w==", 1451 + "dev": true, 1452 + "license": "MIT", 1453 + "dependencies": { 1454 + "@eslint-react/eff": "2.2.1", 1455 + "@typescript-eslint/utils": "^8.46.0", 1456 + "ts-pattern": "^5.8.0", 1457 + "zod": "^4.1.12" 1458 + }, 1459 + "engines": { 1460 + "node": ">=20.19.0" 1461 + } 1462 + }, 1463 + "node_modules/@eslint-react/shared/node_modules/zod": { 1464 + "version": "4.1.12", 1465 + "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.12.tgz", 1466 + "integrity": "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==", 1467 + "dev": true, 1468 + "license": "MIT", 1469 + "funding": { 1470 + "url": "https://github.com/sponsors/colinhacks" 1471 + } 1472 + }, 1473 + "node_modules/@eslint-react/var": { 1474 + "version": "2.2.1", 1475 + "resolved": "https://registry.npmjs.org/@eslint-react/var/-/var-2.2.1.tgz", 1476 + "integrity": "sha512-u5o1z01mNE0F+6DG1sDPnIGDbTaI3s0IOJnGCU4FfcsH7DOf96F4aB1szdJfznJBgVCrcBbyhO9oKKlYZoW0hQ==", 1477 + "dev": true, 1478 + "license": "MIT", 1479 + "dependencies": { 1480 + "@eslint-react/ast": "2.2.1", 1481 + "@eslint-react/eff": "2.2.1", 1482 + "@typescript-eslint/scope-manager": "^8.46.0", 1483 + "@typescript-eslint/types": "^8.46.0", 1484 + "@typescript-eslint/utils": "^8.46.0", 1485 + "ts-pattern": "^5.8.0" 1486 + }, 1487 + "engines": { 1488 + "node": ">=20.19.0" 1489 + } 1490 + }, 1491 + "node_modules/@eslint/config-array": { 1492 + "version": "0.21.0", 1493 + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", 1494 + "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", 1495 + "dev": true, 1496 + "license": "Apache-2.0", 1497 + "peer": true, 1498 + "dependencies": { 1499 + "@eslint/object-schema": "^2.1.6", 1500 + "debug": "^4.3.1", 1501 + "minimatch": "^3.1.2" 1502 + }, 1503 + "engines": { 1504 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 1505 + } 1506 + }, 1507 + "node_modules/@eslint/config-helpers": { 1508 + "version": "0.4.0", 1509 + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.0.tgz", 1510 + "integrity": "sha512-WUFvV4WoIwW8Bv0KeKCIIEgdSiFOsulyN0xrMu+7z43q/hkOLXjvb5u7UC9jDxvRzcrbEmuZBX5yJZz1741jog==", 1511 + "dev": true, 1512 + "license": "Apache-2.0", 1513 + "peer": true, 1514 + "dependencies": { 1515 + "@eslint/core": "^0.16.0" 1516 + }, 1517 + "engines": { 1518 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 1519 + } 1520 + }, 1521 + "node_modules/@eslint/core": { 1522 + "version": "0.16.0", 1523 + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.16.0.tgz", 1524 + "integrity": "sha512-nmC8/totwobIiFcGkDza3GIKfAw1+hLiYVrh3I1nIomQ8PEr5cxg34jnkmGawul/ep52wGRAcyeDCNtWKSOj4Q==", 1525 + "dev": true, 1526 + "license": "Apache-2.0", 1527 + "peer": true, 1528 + "dependencies": { 1529 + "@types/json-schema": "^7.0.15" 1530 + }, 1531 + "engines": { 1532 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 1533 + } 1534 + }, 1535 + "node_modules/@eslint/eslintrc": { 1536 + "version": "3.3.1", 1537 + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", 1538 + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", 1539 + "dev": true, 1540 + "license": "MIT", 1541 + "peer": true, 1542 + "dependencies": { 1543 + "ajv": "^6.12.4", 1544 + "debug": "^4.3.2", 1545 + "espree": "^10.0.1", 1546 + "globals": "^14.0.0", 1547 + "ignore": "^5.2.0", 1548 + "import-fresh": "^3.2.1", 1549 + "js-yaml": "^4.1.0", 1550 + "minimatch": "^3.1.2", 1551 + "strip-json-comments": "^3.1.1" 1552 + }, 1553 + "engines": { 1554 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 1555 + }, 1556 + "funding": { 1557 + "url": "https://opencollective.com/eslint" 1558 + } 1559 + }, 1560 + "node_modules/@eslint/js": { 1561 + "version": "9.37.0", 1562 + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.37.0.tgz", 1563 + "integrity": "sha512-jaS+NJ+hximswBG6pjNX0uEJZkrT0zwpVi3BA3vX22aFGjJjmgSTSmPpZCRKmoBL5VY/M6p0xsSJx7rk7sy5gg==", 1564 + "dev": true, 1565 + "license": "MIT", 1566 + "peer": true, 1567 + "engines": { 1568 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 1569 + }, 1570 + "funding": { 1571 + "url": "https://eslint.org/donate" 1572 + } 1573 + }, 1574 + "node_modules/@eslint/object-schema": { 1575 + "version": "2.1.6", 1576 + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", 1577 + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", 1578 + "dev": true, 1579 + "license": "Apache-2.0", 1580 + "peer": true, 1581 + "engines": { 1582 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 1583 + } 1584 + }, 1585 + "node_modules/@eslint/plugin-kit": { 1586 + "version": "0.4.0", 1587 + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.0.tgz", 1588 + "integrity": "sha512-sB5uyeq+dwCWyPi31B2gQlVlo+j5brPlWx4yZBrEaRo/nhdDE8Xke1gsGgtiBdaBTxuTkceLVuVt/pclrasb0A==", 1589 + "dev": true, 1590 + "license": "Apache-2.0", 1591 + "peer": true, 1592 + "dependencies": { 1593 + "@eslint/core": "^0.16.0", 1594 + "levn": "^0.4.1" 1595 + }, 1596 + "engines": { 1597 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 1598 + } 1599 + }, 1600 + "node_modules/@floating-ui/core": { 1601 + "version": "1.7.3", 1602 + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", 1603 + "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", 1604 + "dependencies": { 1605 + "@floating-ui/utils": "^0.2.10" 1606 + } 1607 + }, 1608 + "node_modules/@floating-ui/dom": { 1609 + "version": "1.7.4", 1610 + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz", 1611 + "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==", 1612 + "dependencies": { 1613 + "@floating-ui/core": "^1.7.3", 1614 + "@floating-ui/utils": "^0.2.10" 1615 + } 1616 + }, 1617 + "node_modules/@floating-ui/react-dom": { 1618 + "version": "2.1.6", 1619 + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.6.tgz", 1620 + "integrity": "sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==", 1621 + "dependencies": { 1622 + "@floating-ui/dom": "^1.7.4" 1623 + }, 1624 + "peerDependencies": { 1625 + "react": ">=16.8.0", 1626 + "react-dom": ">=16.8.0" 1627 + } 1628 + }, 1629 + "node_modules/@floating-ui/utils": { 1630 + "version": "0.2.10", 1631 + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", 1632 + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==" 1633 + }, 1634 + "node_modules/@humanfs/core": { 1635 + "version": "0.19.1", 1636 + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", 1637 + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", 1638 + "dev": true, 1639 + "license": "Apache-2.0", 1640 + "peer": true, 1641 + "engines": { 1642 + "node": ">=18.18.0" 1643 + } 1644 + }, 1645 + "node_modules/@humanfs/node": { 1646 + "version": "0.16.7", 1647 + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", 1648 + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", 1649 + "dev": true, 1650 + "license": "Apache-2.0", 1651 + "peer": true, 1652 + "dependencies": { 1653 + "@humanfs/core": "^0.19.1", 1654 + "@humanwhocodes/retry": "^0.4.0" 1655 + }, 1656 + "engines": { 1657 + "node": ">=18.18.0" 1658 + } 1659 + }, 1660 + "node_modules/@humanwhocodes/module-importer": { 1661 + "version": "1.0.1", 1662 + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", 1663 + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", 1664 + "dev": true, 1665 + "license": "Apache-2.0", 1666 + "peer": true, 1667 + "engines": { 1668 + "node": ">=12.22" 1669 + }, 1670 + "funding": { 1671 + "type": "github", 1672 + "url": "https://github.com/sponsors/nzakas" 1673 + } 1674 + }, 1675 + "node_modules/@humanwhocodes/retry": { 1676 + "version": "0.4.3", 1677 + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", 1678 + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", 1679 + "dev": true, 1680 + "license": "Apache-2.0", 1681 + "peer": true, 1682 + "engines": { 1683 + "node": ">=18.18" 1684 + }, 1685 + "funding": { 1686 + "type": "github", 1687 + "url": "https://github.com/sponsors/nzakas" 1688 + } 1689 + }, 1690 + "node_modules/@iconify-icon/react": { 1691 + "version": "3.0.1", 1692 + "resolved": "https://registry.npmjs.org/@iconify-icon/react/-/react-3.0.1.tgz", 1693 + "integrity": "sha512-/4CAVpk8HDyKS78r1G0rZhML7hI6jLxb8kAmjEXsCtuVUDwdGqicGCRg0T14mqeHNImrQPR49MhbuSSS++JlUA==", 1694 + "dev": true, 1695 + "license": "MIT", 1696 + "dependencies": { 1697 + "iconify-icon": "^3.0.1" 1698 + }, 1699 + "funding": { 1700 + "url": "https://github.com/sponsors/cyberalien" 1701 + }, 1702 + "peerDependencies": { 1703 + "react": ">=16" 1704 + } 1705 + }, 1706 + "node_modules/@iconify-json/material-symbols": { 1707 + "version": "1.2.42", 1708 + "resolved": "https://registry.npmjs.org/@iconify-json/material-symbols/-/material-symbols-1.2.42.tgz", 1709 + "integrity": "sha512-FDRfnQqy8iXaq/swVPFWaHftqP9tk3qDCRhC30s3UZL2j4mvGZk5gVECRXCkZv5jnsAiTpZxGQM8HrMiwE7GtA==", 1710 + "dev": true, 1711 + "license": "Apache-2.0", 1712 + "dependencies": { 1713 + "@iconify/types": "*" 1714 + } 1715 + }, 1716 + "node_modules/@iconify-json/mdi": { 1717 + "version": "1.2.3", 1718 + "resolved": "https://registry.npmjs.org/@iconify-json/mdi/-/mdi-1.2.3.tgz", 1719 + "integrity": "sha512-O3cLwbDOK7NNDf2ihaQOH5F9JglnulNDFV7WprU2dSoZu3h3cWH//h74uQAB87brHmvFVxIOkuBX2sZSzYhScg==", 1720 + "dev": true, 1721 + "license": "Apache-2.0", 1722 + "dependencies": { 1723 + "@iconify/types": "*" 1724 + } 1725 + }, 1726 + "node_modules/@iconify/json": { 1727 + "version": "2.2.396", 1728 + "resolved": "https://registry.npmjs.org/@iconify/json/-/json-2.2.396.tgz", 1729 + "integrity": "sha512-tijg77JFuYIt32S9N8p7La8C0zp9zKZsX6UP8ip5GVB1F6Mp3pZA5Vc5eAquTY50NoDJX58U6z4Qn3d6Wyossg==", 1730 + "dev": true, 1731 + "license": "MIT", 1732 + "dependencies": { 1733 + "@iconify/types": "*", 1734 + "pathe": "^2.0.0" 1735 + } 1736 + }, 1737 + "node_modules/@iconify/types": { 1738 + "version": "2.0.0", 1739 + "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", 1740 + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", 1741 + "dev": true, 1742 + "license": "MIT" 1743 + }, 1744 + "node_modules/@iconify/utils": { 1745 + "version": "3.0.2", 1746 + "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-3.0.2.tgz", 1747 + "integrity": "sha512-EfJS0rLfVuRuJRn4psJHtK2A9TqVnkxPpHY6lYHiB9+8eSuudsxbwMiavocG45ujOo6FJ+CIRlRnlOGinzkaGQ==", 1748 + "dev": true, 1749 + "license": "MIT", 1750 + "dependencies": { 1751 + "@antfu/install-pkg": "^1.1.0", 1752 + "@antfu/utils": "^9.2.0", 1753 + "@iconify/types": "^2.0.0", 1754 + "debug": "^4.4.1", 1755 + "globals": "^15.15.0", 1756 + "kolorist": "^1.8.0", 1757 + "local-pkg": "^1.1.1", 1758 + "mlly": "^1.7.4" 1759 + } 1760 + }, 1761 + "node_modules/@iconify/utils/node_modules/globals": { 1762 + "version": "15.15.0", 1763 + "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", 1764 + "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", 1765 + "dev": true, 1766 + "license": "MIT", 1767 + "engines": { 1768 + "node": ">=18" 1769 + }, 1770 + "funding": { 1771 + "url": "https://github.com/sponsors/sindresorhus" 1772 + } 1773 + }, 1105 1774 "node_modules/@isaacs/fs-minipass": { 1106 1775 "version": "4.0.1", 1107 1776 "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", ··· 1227 1896 "mux-embed": "^5.8.3" 1228 1897 } 1229 1898 }, 1899 + "node_modules/@nodelib/fs.scandir": { 1900 + "version": "2.1.5", 1901 + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", 1902 + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", 1903 + "dev": true, 1904 + "license": "MIT", 1905 + "dependencies": { 1906 + "@nodelib/fs.stat": "2.0.5", 1907 + "run-parallel": "^1.1.9" 1908 + }, 1909 + "engines": { 1910 + "node": ">= 8" 1911 + } 1912 + }, 1913 + "node_modules/@nodelib/fs.stat": { 1914 + "version": "2.0.5", 1915 + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", 1916 + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", 1917 + "dev": true, 1918 + "license": "MIT", 1919 + "engines": { 1920 + "node": ">= 8" 1921 + } 1922 + }, 1923 + "node_modules/@nodelib/fs.walk": { 1924 + "version": "1.2.8", 1925 + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", 1926 + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", 1927 + "dev": true, 1928 + "license": "MIT", 1929 + "dependencies": { 1930 + "@nodelib/fs.scandir": "2.1.5", 1931 + "fastq": "^1.6.0" 1932 + }, 1933 + "engines": { 1934 + "node": ">= 8" 1935 + } 1936 + }, 1937 + "node_modules/@radix-ui/number": { 1938 + "version": "1.1.1", 1939 + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", 1940 + "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==" 1941 + }, 1942 + "node_modules/@radix-ui/primitive": { 1943 + "version": "1.1.3", 1944 + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", 1945 + "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==" 1946 + }, 1947 + "node_modules/@radix-ui/react-accessible-icon": { 1948 + "version": "1.1.7", 1949 + "resolved": "https://registry.npmjs.org/@radix-ui/react-accessible-icon/-/react-accessible-icon-1.1.7.tgz", 1950 + "integrity": "sha512-XM+E4WXl0OqUJFovy6GjmxxFyx9opfCAIUku4dlKRd5YEPqt4kALOkQOp0Of6reHuUkJuiPBEc5k0o4z4lTC8A==", 1951 + "dependencies": { 1952 + "@radix-ui/react-visually-hidden": "1.2.3" 1953 + }, 1954 + "peerDependencies": { 1955 + "@types/react": "*", 1956 + "@types/react-dom": "*", 1957 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 1958 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 1959 + }, 1960 + "peerDependenciesMeta": { 1961 + "@types/react": { 1962 + "optional": true 1963 + }, 1964 + "@types/react-dom": { 1965 + "optional": true 1966 + } 1967 + } 1968 + }, 1969 + "node_modules/@radix-ui/react-accordion": { 1970 + "version": "1.2.12", 1971 + "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.12.tgz", 1972 + "integrity": "sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA==", 1973 + "dependencies": { 1974 + "@radix-ui/primitive": "1.1.3", 1975 + "@radix-ui/react-collapsible": "1.1.12", 1976 + "@radix-ui/react-collection": "1.1.7", 1977 + "@radix-ui/react-compose-refs": "1.1.2", 1978 + "@radix-ui/react-context": "1.1.2", 1979 + "@radix-ui/react-direction": "1.1.1", 1980 + "@radix-ui/react-id": "1.1.1", 1981 + "@radix-ui/react-primitive": "2.1.3", 1982 + "@radix-ui/react-use-controllable-state": "1.2.2" 1983 + }, 1984 + "peerDependencies": { 1985 + "@types/react": "*", 1986 + "@types/react-dom": "*", 1987 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 1988 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 1989 + }, 1990 + "peerDependenciesMeta": { 1991 + "@types/react": { 1992 + "optional": true 1993 + }, 1994 + "@types/react-dom": { 1995 + "optional": true 1996 + } 1997 + } 1998 + }, 1999 + "node_modules/@radix-ui/react-alert-dialog": { 2000 + "version": "1.1.15", 2001 + "resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.1.15.tgz", 2002 + "integrity": "sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw==", 2003 + "dependencies": { 2004 + "@radix-ui/primitive": "1.1.3", 2005 + "@radix-ui/react-compose-refs": "1.1.2", 2006 + "@radix-ui/react-context": "1.1.2", 2007 + "@radix-ui/react-dialog": "1.1.15", 2008 + "@radix-ui/react-primitive": "2.1.3", 2009 + "@radix-ui/react-slot": "1.2.3" 2010 + }, 2011 + "peerDependencies": { 2012 + "@types/react": "*", 2013 + "@types/react-dom": "*", 2014 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 2015 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 2016 + }, 2017 + "peerDependenciesMeta": { 2018 + "@types/react": { 2019 + "optional": true 2020 + }, 2021 + "@types/react-dom": { 2022 + "optional": true 2023 + } 2024 + } 2025 + }, 2026 + "node_modules/@radix-ui/react-arrow": { 2027 + "version": "1.1.7", 2028 + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", 2029 + "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", 2030 + "dependencies": { 2031 + "@radix-ui/react-primitive": "2.1.3" 2032 + }, 2033 + "peerDependencies": { 2034 + "@types/react": "*", 2035 + "@types/react-dom": "*", 2036 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 2037 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 2038 + }, 2039 + "peerDependenciesMeta": { 2040 + "@types/react": { 2041 + "optional": true 2042 + }, 2043 + "@types/react-dom": { 2044 + "optional": true 2045 + } 2046 + } 2047 + }, 2048 + "node_modules/@radix-ui/react-aspect-ratio": { 2049 + "version": "1.1.7", 2050 + "resolved": "https://registry.npmjs.org/@radix-ui/react-aspect-ratio/-/react-aspect-ratio-1.1.7.tgz", 2051 + "integrity": "sha512-Yq6lvO9HQyPwev1onK1daHCHqXVLzPhSVjmsNjCa2Zcxy2f7uJD2itDtxknv6FzAKCwD1qQkeVDmX/cev13n/g==", 2052 + "dependencies": { 2053 + "@radix-ui/react-primitive": "2.1.3" 2054 + }, 2055 + "peerDependencies": { 2056 + "@types/react": "*", 2057 + "@types/react-dom": "*", 2058 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 2059 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 2060 + }, 2061 + "peerDependenciesMeta": { 2062 + "@types/react": { 2063 + "optional": true 2064 + }, 2065 + "@types/react-dom": { 2066 + "optional": true 2067 + } 2068 + } 2069 + }, 2070 + "node_modules/@radix-ui/react-avatar": { 2071 + "version": "1.1.10", 2072 + "resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.1.10.tgz", 2073 + "integrity": "sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog==", 2074 + "dependencies": { 2075 + "@radix-ui/react-context": "1.1.2", 2076 + "@radix-ui/react-primitive": "2.1.3", 2077 + "@radix-ui/react-use-callback-ref": "1.1.1", 2078 + "@radix-ui/react-use-is-hydrated": "0.1.0", 2079 + "@radix-ui/react-use-layout-effect": "1.1.1" 2080 + }, 2081 + "peerDependencies": { 2082 + "@types/react": "*", 2083 + "@types/react-dom": "*", 2084 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 2085 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 2086 + }, 2087 + "peerDependenciesMeta": { 2088 + "@types/react": { 2089 + "optional": true 2090 + }, 2091 + "@types/react-dom": { 2092 + "optional": true 2093 + } 2094 + } 2095 + }, 2096 + "node_modules/@radix-ui/react-checkbox": { 2097 + "version": "1.3.3", 2098 + "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.3.3.tgz", 2099 + "integrity": "sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==", 2100 + "dependencies": { 2101 + "@radix-ui/primitive": "1.1.3", 2102 + "@radix-ui/react-compose-refs": "1.1.2", 2103 + "@radix-ui/react-context": "1.1.2", 2104 + "@radix-ui/react-presence": "1.1.5", 2105 + "@radix-ui/react-primitive": "2.1.3", 2106 + "@radix-ui/react-use-controllable-state": "1.2.2", 2107 + "@radix-ui/react-use-previous": "1.1.1", 2108 + "@radix-ui/react-use-size": "1.1.1" 2109 + }, 2110 + "peerDependencies": { 2111 + "@types/react": "*", 2112 + "@types/react-dom": "*", 2113 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 2114 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 2115 + }, 2116 + "peerDependenciesMeta": { 2117 + "@types/react": { 2118 + "optional": true 2119 + }, 2120 + "@types/react-dom": { 2121 + "optional": true 2122 + } 2123 + } 2124 + }, 2125 + "node_modules/@radix-ui/react-collapsible": { 2126 + "version": "1.1.12", 2127 + "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.12.tgz", 2128 + "integrity": "sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA==", 2129 + "dependencies": { 2130 + "@radix-ui/primitive": "1.1.3", 2131 + "@radix-ui/react-compose-refs": "1.1.2", 2132 + "@radix-ui/react-context": "1.1.2", 2133 + "@radix-ui/react-id": "1.1.1", 2134 + "@radix-ui/react-presence": "1.1.5", 2135 + "@radix-ui/react-primitive": "2.1.3", 2136 + "@radix-ui/react-use-controllable-state": "1.2.2", 2137 + "@radix-ui/react-use-layout-effect": "1.1.1" 2138 + }, 2139 + "peerDependencies": { 2140 + "@types/react": "*", 2141 + "@types/react-dom": "*", 2142 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 2143 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 2144 + }, 2145 + "peerDependenciesMeta": { 2146 + "@types/react": { 2147 + "optional": true 2148 + }, 2149 + "@types/react-dom": { 2150 + "optional": true 2151 + } 2152 + } 2153 + }, 2154 + "node_modules/@radix-ui/react-collection": { 2155 + "version": "1.1.7", 2156 + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", 2157 + "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", 2158 + "dependencies": { 2159 + "@radix-ui/react-compose-refs": "1.1.2", 2160 + "@radix-ui/react-context": "1.1.2", 2161 + "@radix-ui/react-primitive": "2.1.3", 2162 + "@radix-ui/react-slot": "1.2.3" 2163 + }, 2164 + "peerDependencies": { 2165 + "@types/react": "*", 2166 + "@types/react-dom": "*", 2167 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 2168 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 2169 + }, 2170 + "peerDependenciesMeta": { 2171 + "@types/react": { 2172 + "optional": true 2173 + }, 2174 + "@types/react-dom": { 2175 + "optional": true 2176 + } 2177 + } 2178 + }, 2179 + "node_modules/@radix-ui/react-compose-refs": { 2180 + "version": "1.1.2", 2181 + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", 2182 + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", 2183 + "peerDependencies": { 2184 + "@types/react": "*", 2185 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 2186 + }, 2187 + "peerDependenciesMeta": { 2188 + "@types/react": { 2189 + "optional": true 2190 + } 2191 + } 2192 + }, 2193 + "node_modules/@radix-ui/react-context": { 2194 + "version": "1.1.2", 2195 + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", 2196 + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", 2197 + "peerDependencies": { 2198 + "@types/react": "*", 2199 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 2200 + }, 2201 + "peerDependenciesMeta": { 2202 + "@types/react": { 2203 + "optional": true 2204 + } 2205 + } 2206 + }, 2207 + "node_modules/@radix-ui/react-context-menu": { 2208 + "version": "2.2.16", 2209 + "resolved": "https://registry.npmjs.org/@radix-ui/react-context-menu/-/react-context-menu-2.2.16.tgz", 2210 + "integrity": "sha512-O8morBEW+HsVG28gYDZPTrT9UUovQUlJue5YO836tiTJhuIWBm/zQHc7j388sHWtdH/xUZurK9olD2+pcqx5ww==", 2211 + "dependencies": { 2212 + "@radix-ui/primitive": "1.1.3", 2213 + "@radix-ui/react-context": "1.1.2", 2214 + "@radix-ui/react-menu": "2.1.16", 2215 + "@radix-ui/react-primitive": "2.1.3", 2216 + "@radix-ui/react-use-callback-ref": "1.1.1", 2217 + "@radix-ui/react-use-controllable-state": "1.2.2" 2218 + }, 2219 + "peerDependencies": { 2220 + "@types/react": "*", 2221 + "@types/react-dom": "*", 2222 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 2223 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 2224 + }, 2225 + "peerDependenciesMeta": { 2226 + "@types/react": { 2227 + "optional": true 2228 + }, 2229 + "@types/react-dom": { 2230 + "optional": true 2231 + } 2232 + } 2233 + }, 2234 + "node_modules/@radix-ui/react-dialog": { 2235 + "version": "1.1.15", 2236 + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz", 2237 + "integrity": "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==", 2238 + "dependencies": { 2239 + "@radix-ui/primitive": "1.1.3", 2240 + "@radix-ui/react-compose-refs": "1.1.2", 2241 + "@radix-ui/react-context": "1.1.2", 2242 + "@radix-ui/react-dismissable-layer": "1.1.11", 2243 + "@radix-ui/react-focus-guards": "1.1.3", 2244 + "@radix-ui/react-focus-scope": "1.1.7", 2245 + "@radix-ui/react-id": "1.1.1", 2246 + "@radix-ui/react-portal": "1.1.9", 2247 + "@radix-ui/react-presence": "1.1.5", 2248 + "@radix-ui/react-primitive": "2.1.3", 2249 + "@radix-ui/react-slot": "1.2.3", 2250 + "@radix-ui/react-use-controllable-state": "1.2.2", 2251 + "aria-hidden": "^1.2.4", 2252 + "react-remove-scroll": "^2.6.3" 2253 + }, 2254 + "peerDependencies": { 2255 + "@types/react": "*", 2256 + "@types/react-dom": "*", 2257 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 2258 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 2259 + }, 2260 + "peerDependenciesMeta": { 2261 + "@types/react": { 2262 + "optional": true 2263 + }, 2264 + "@types/react-dom": { 2265 + "optional": true 2266 + } 2267 + } 2268 + }, 2269 + "node_modules/@radix-ui/react-direction": { 2270 + "version": "1.1.1", 2271 + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", 2272 + "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", 2273 + "peerDependencies": { 2274 + "@types/react": "*", 2275 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 2276 + }, 2277 + "peerDependenciesMeta": { 2278 + "@types/react": { 2279 + "optional": true 2280 + } 2281 + } 2282 + }, 2283 + "node_modules/@radix-ui/react-dismissable-layer": { 2284 + "version": "1.1.11", 2285 + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz", 2286 + "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==", 2287 + "dependencies": { 2288 + "@radix-ui/primitive": "1.1.3", 2289 + "@radix-ui/react-compose-refs": "1.1.2", 2290 + "@radix-ui/react-primitive": "2.1.3", 2291 + "@radix-ui/react-use-callback-ref": "1.1.1", 2292 + "@radix-ui/react-use-escape-keydown": "1.1.1" 2293 + }, 2294 + "peerDependencies": { 2295 + "@types/react": "*", 2296 + "@types/react-dom": "*", 2297 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 2298 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 2299 + }, 2300 + "peerDependenciesMeta": { 2301 + "@types/react": { 2302 + "optional": true 2303 + }, 2304 + "@types/react-dom": { 2305 + "optional": true 2306 + } 2307 + } 2308 + }, 2309 + "node_modules/@radix-ui/react-dropdown-menu": { 2310 + "version": "2.1.16", 2311 + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.16.tgz", 2312 + "integrity": "sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==", 2313 + "dependencies": { 2314 + "@radix-ui/primitive": "1.1.3", 2315 + "@radix-ui/react-compose-refs": "1.1.2", 2316 + "@radix-ui/react-context": "1.1.2", 2317 + "@radix-ui/react-id": "1.1.1", 2318 + "@radix-ui/react-menu": "2.1.16", 2319 + "@radix-ui/react-primitive": "2.1.3", 2320 + "@radix-ui/react-use-controllable-state": "1.2.2" 2321 + }, 2322 + "peerDependencies": { 2323 + "@types/react": "*", 2324 + "@types/react-dom": "*", 2325 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 2326 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 2327 + }, 2328 + "peerDependenciesMeta": { 2329 + "@types/react": { 2330 + "optional": true 2331 + }, 2332 + "@types/react-dom": { 2333 + "optional": true 2334 + } 2335 + } 2336 + }, 2337 + "node_modules/@radix-ui/react-focus-guards": { 2338 + "version": "1.1.3", 2339 + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz", 2340 + "integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==", 2341 + "peerDependencies": { 2342 + "@types/react": "*", 2343 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 2344 + }, 2345 + "peerDependenciesMeta": { 2346 + "@types/react": { 2347 + "optional": true 2348 + } 2349 + } 2350 + }, 2351 + "node_modules/@radix-ui/react-focus-scope": { 2352 + "version": "1.1.7", 2353 + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", 2354 + "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", 2355 + "dependencies": { 2356 + "@radix-ui/react-compose-refs": "1.1.2", 2357 + "@radix-ui/react-primitive": "2.1.3", 2358 + "@radix-ui/react-use-callback-ref": "1.1.1" 2359 + }, 2360 + "peerDependencies": { 2361 + "@types/react": "*", 2362 + "@types/react-dom": "*", 2363 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 2364 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 2365 + }, 2366 + "peerDependenciesMeta": { 2367 + "@types/react": { 2368 + "optional": true 2369 + }, 2370 + "@types/react-dom": { 2371 + "optional": true 2372 + } 2373 + } 2374 + }, 2375 + "node_modules/@radix-ui/react-form": { 2376 + "version": "0.1.8", 2377 + "resolved": "https://registry.npmjs.org/@radix-ui/react-form/-/react-form-0.1.8.tgz", 2378 + "integrity": "sha512-QM70k4Zwjttifr5a4sZFts9fn8FzHYvQ5PiB19O2HsYibaHSVt9fH9rzB0XZo/YcM+b7t/p7lYCT/F5eOeF5yQ==", 2379 + "dependencies": { 2380 + "@radix-ui/primitive": "1.1.3", 2381 + "@radix-ui/react-compose-refs": "1.1.2", 2382 + "@radix-ui/react-context": "1.1.2", 2383 + "@radix-ui/react-id": "1.1.1", 2384 + "@radix-ui/react-label": "2.1.7", 2385 + "@radix-ui/react-primitive": "2.1.3" 2386 + }, 2387 + "peerDependencies": { 2388 + "@types/react": "*", 2389 + "@types/react-dom": "*", 2390 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 2391 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 2392 + }, 2393 + "peerDependenciesMeta": { 2394 + "@types/react": { 2395 + "optional": true 2396 + }, 2397 + "@types/react-dom": { 2398 + "optional": true 2399 + } 2400 + } 2401 + }, 2402 + "node_modules/@radix-ui/react-hover-card": { 2403 + "version": "1.1.15", 2404 + "resolved": "https://registry.npmjs.org/@radix-ui/react-hover-card/-/react-hover-card-1.1.15.tgz", 2405 + "integrity": "sha512-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg==", 2406 + "license": "MIT", 2407 + "dependencies": { 2408 + "@radix-ui/primitive": "1.1.3", 2409 + "@radix-ui/react-compose-refs": "1.1.2", 2410 + "@radix-ui/react-context": "1.1.2", 2411 + "@radix-ui/react-dismissable-layer": "1.1.11", 2412 + "@radix-ui/react-popper": "1.2.8", 2413 + "@radix-ui/react-portal": "1.1.9", 2414 + "@radix-ui/react-presence": "1.1.5", 2415 + "@radix-ui/react-primitive": "2.1.3", 2416 + "@radix-ui/react-use-controllable-state": "1.2.2" 2417 + }, 2418 + "peerDependencies": { 2419 + "@types/react": "*", 2420 + "@types/react-dom": "*", 2421 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 2422 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 2423 + }, 2424 + "peerDependenciesMeta": { 2425 + "@types/react": { 2426 + "optional": true 2427 + }, 2428 + "@types/react-dom": { 2429 + "optional": true 2430 + } 2431 + } 2432 + }, 2433 + "node_modules/@radix-ui/react-id": { 2434 + "version": "1.1.1", 2435 + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", 2436 + "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", 2437 + "dependencies": { 2438 + "@radix-ui/react-use-layout-effect": "1.1.1" 2439 + }, 2440 + "peerDependencies": { 2441 + "@types/react": "*", 2442 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 2443 + }, 2444 + "peerDependenciesMeta": { 2445 + "@types/react": { 2446 + "optional": true 2447 + } 2448 + } 2449 + }, 2450 + "node_modules/@radix-ui/react-label": { 2451 + "version": "2.1.7", 2452 + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.7.tgz", 2453 + "integrity": "sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ==", 2454 + "dependencies": { 2455 + "@radix-ui/react-primitive": "2.1.3" 2456 + }, 2457 + "peerDependencies": { 2458 + "@types/react": "*", 2459 + "@types/react-dom": "*", 2460 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 2461 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 2462 + }, 2463 + "peerDependenciesMeta": { 2464 + "@types/react": { 2465 + "optional": true 2466 + }, 2467 + "@types/react-dom": { 2468 + "optional": true 2469 + } 2470 + } 2471 + }, 2472 + "node_modules/@radix-ui/react-menu": { 2473 + "version": "2.1.16", 2474 + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.16.tgz", 2475 + "integrity": "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==", 2476 + "dependencies": { 2477 + "@radix-ui/primitive": "1.1.3", 2478 + "@radix-ui/react-collection": "1.1.7", 2479 + "@radix-ui/react-compose-refs": "1.1.2", 2480 + "@radix-ui/react-context": "1.1.2", 2481 + "@radix-ui/react-direction": "1.1.1", 2482 + "@radix-ui/react-dismissable-layer": "1.1.11", 2483 + "@radix-ui/react-focus-guards": "1.1.3", 2484 + "@radix-ui/react-focus-scope": "1.1.7", 2485 + "@radix-ui/react-id": "1.1.1", 2486 + "@radix-ui/react-popper": "1.2.8", 2487 + "@radix-ui/react-portal": "1.1.9", 2488 + "@radix-ui/react-presence": "1.1.5", 2489 + "@radix-ui/react-primitive": "2.1.3", 2490 + "@radix-ui/react-roving-focus": "1.1.11", 2491 + "@radix-ui/react-slot": "1.2.3", 2492 + "@radix-ui/react-use-callback-ref": "1.1.1", 2493 + "aria-hidden": "^1.2.4", 2494 + "react-remove-scroll": "^2.6.3" 2495 + }, 2496 + "peerDependencies": { 2497 + "@types/react": "*", 2498 + "@types/react-dom": "*", 2499 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 2500 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 2501 + }, 2502 + "peerDependenciesMeta": { 2503 + "@types/react": { 2504 + "optional": true 2505 + }, 2506 + "@types/react-dom": { 2507 + "optional": true 2508 + } 2509 + } 2510 + }, 2511 + "node_modules/@radix-ui/react-menubar": { 2512 + "version": "1.1.16", 2513 + "resolved": "https://registry.npmjs.org/@radix-ui/react-menubar/-/react-menubar-1.1.16.tgz", 2514 + "integrity": "sha512-EB1FktTz5xRRi2Er974AUQZWg2yVBb1yjip38/lgwtCVRd3a+maUoGHN/xs9Yv8SY8QwbSEb+YrxGadVWbEutA==", 2515 + "dependencies": { 2516 + "@radix-ui/primitive": "1.1.3", 2517 + "@radix-ui/react-collection": "1.1.7", 2518 + "@radix-ui/react-compose-refs": "1.1.2", 2519 + "@radix-ui/react-context": "1.1.2", 2520 + "@radix-ui/react-direction": "1.1.1", 2521 + "@radix-ui/react-id": "1.1.1", 2522 + "@radix-ui/react-menu": "2.1.16", 2523 + "@radix-ui/react-primitive": "2.1.3", 2524 + "@radix-ui/react-roving-focus": "1.1.11", 2525 + "@radix-ui/react-use-controllable-state": "1.2.2" 2526 + }, 2527 + "peerDependencies": { 2528 + "@types/react": "*", 2529 + "@types/react-dom": "*", 2530 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 2531 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 2532 + }, 2533 + "peerDependenciesMeta": { 2534 + "@types/react": { 2535 + "optional": true 2536 + }, 2537 + "@types/react-dom": { 2538 + "optional": true 2539 + } 2540 + } 2541 + }, 2542 + "node_modules/@radix-ui/react-navigation-menu": { 2543 + "version": "1.2.14", 2544 + "resolved": "https://registry.npmjs.org/@radix-ui/react-navigation-menu/-/react-navigation-menu-1.2.14.tgz", 2545 + "integrity": "sha512-YB9mTFQvCOAQMHU+C/jVl96WmuWeltyUEpRJJky51huhds5W2FQr1J8D/16sQlf0ozxkPK8uF3niQMdUwZPv5w==", 2546 + "dependencies": { 2547 + "@radix-ui/primitive": "1.1.3", 2548 + "@radix-ui/react-collection": "1.1.7", 2549 + "@radix-ui/react-compose-refs": "1.1.2", 2550 + "@radix-ui/react-context": "1.1.2", 2551 + "@radix-ui/react-direction": "1.1.1", 2552 + "@radix-ui/react-dismissable-layer": "1.1.11", 2553 + "@radix-ui/react-id": "1.1.1", 2554 + "@radix-ui/react-presence": "1.1.5", 2555 + "@radix-ui/react-primitive": "2.1.3", 2556 + "@radix-ui/react-use-callback-ref": "1.1.1", 2557 + "@radix-ui/react-use-controllable-state": "1.2.2", 2558 + "@radix-ui/react-use-layout-effect": "1.1.1", 2559 + "@radix-ui/react-use-previous": "1.1.1", 2560 + "@radix-ui/react-visually-hidden": "1.2.3" 2561 + }, 2562 + "peerDependencies": { 2563 + "@types/react": "*", 2564 + "@types/react-dom": "*", 2565 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 2566 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 2567 + }, 2568 + "peerDependenciesMeta": { 2569 + "@types/react": { 2570 + "optional": true 2571 + }, 2572 + "@types/react-dom": { 2573 + "optional": true 2574 + } 2575 + } 2576 + }, 2577 + "node_modules/@radix-ui/react-one-time-password-field": { 2578 + "version": "0.1.8", 2579 + "resolved": "https://registry.npmjs.org/@radix-ui/react-one-time-password-field/-/react-one-time-password-field-0.1.8.tgz", 2580 + "integrity": "sha512-ycS4rbwURavDPVjCb5iS3aG4lURFDILi6sKI/WITUMZ13gMmn/xGjpLoqBAalhJaDk8I3UbCM5GzKHrnzwHbvg==", 2581 + "dependencies": { 2582 + "@radix-ui/number": "1.1.1", 2583 + "@radix-ui/primitive": "1.1.3", 2584 + "@radix-ui/react-collection": "1.1.7", 2585 + "@radix-ui/react-compose-refs": "1.1.2", 2586 + "@radix-ui/react-context": "1.1.2", 2587 + "@radix-ui/react-direction": "1.1.1", 2588 + "@radix-ui/react-primitive": "2.1.3", 2589 + "@radix-ui/react-roving-focus": "1.1.11", 2590 + "@radix-ui/react-use-controllable-state": "1.2.2", 2591 + "@radix-ui/react-use-effect-event": "0.0.2", 2592 + "@radix-ui/react-use-is-hydrated": "0.1.0", 2593 + "@radix-ui/react-use-layout-effect": "1.1.1" 2594 + }, 2595 + "peerDependencies": { 2596 + "@types/react": "*", 2597 + "@types/react-dom": "*", 2598 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 2599 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 2600 + }, 2601 + "peerDependenciesMeta": { 2602 + "@types/react": { 2603 + "optional": true 2604 + }, 2605 + "@types/react-dom": { 2606 + "optional": true 2607 + } 2608 + } 2609 + }, 2610 + "node_modules/@radix-ui/react-password-toggle-field": { 2611 + "version": "0.1.3", 2612 + "resolved": "https://registry.npmjs.org/@radix-ui/react-password-toggle-field/-/react-password-toggle-field-0.1.3.tgz", 2613 + "integrity": "sha512-/UuCrDBWravcaMix4TdT+qlNdVwOM1Nck9kWx/vafXsdfj1ChfhOdfi3cy9SGBpWgTXwYCuboT/oYpJy3clqfw==", 2614 + "dependencies": { 2615 + "@radix-ui/primitive": "1.1.3", 2616 + "@radix-ui/react-compose-refs": "1.1.2", 2617 + "@radix-ui/react-context": "1.1.2", 2618 + "@radix-ui/react-id": "1.1.1", 2619 + "@radix-ui/react-primitive": "2.1.3", 2620 + "@radix-ui/react-use-controllable-state": "1.2.2", 2621 + "@radix-ui/react-use-effect-event": "0.0.2", 2622 + "@radix-ui/react-use-is-hydrated": "0.1.0" 2623 + }, 2624 + "peerDependencies": { 2625 + "@types/react": "*", 2626 + "@types/react-dom": "*", 2627 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 2628 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 2629 + }, 2630 + "peerDependenciesMeta": { 2631 + "@types/react": { 2632 + "optional": true 2633 + }, 2634 + "@types/react-dom": { 2635 + "optional": true 2636 + } 2637 + } 2638 + }, 2639 + "node_modules/@radix-ui/react-popover": { 2640 + "version": "1.1.15", 2641 + "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.15.tgz", 2642 + "integrity": "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==", 2643 + "dependencies": { 2644 + "@radix-ui/primitive": "1.1.3", 2645 + "@radix-ui/react-compose-refs": "1.1.2", 2646 + "@radix-ui/react-context": "1.1.2", 2647 + "@radix-ui/react-dismissable-layer": "1.1.11", 2648 + "@radix-ui/react-focus-guards": "1.1.3", 2649 + "@radix-ui/react-focus-scope": "1.1.7", 2650 + "@radix-ui/react-id": "1.1.1", 2651 + "@radix-ui/react-popper": "1.2.8", 2652 + "@radix-ui/react-portal": "1.1.9", 2653 + "@radix-ui/react-presence": "1.1.5", 2654 + "@radix-ui/react-primitive": "2.1.3", 2655 + "@radix-ui/react-slot": "1.2.3", 2656 + "@radix-ui/react-use-controllable-state": "1.2.2", 2657 + "aria-hidden": "^1.2.4", 2658 + "react-remove-scroll": "^2.6.3" 2659 + }, 2660 + "peerDependencies": { 2661 + "@types/react": "*", 2662 + "@types/react-dom": "*", 2663 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 2664 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 2665 + }, 2666 + "peerDependenciesMeta": { 2667 + "@types/react": { 2668 + "optional": true 2669 + }, 2670 + "@types/react-dom": { 2671 + "optional": true 2672 + } 2673 + } 2674 + }, 2675 + "node_modules/@radix-ui/react-popper": { 2676 + "version": "1.2.8", 2677 + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz", 2678 + "integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==", 2679 + "dependencies": { 2680 + "@floating-ui/react-dom": "^2.0.0", 2681 + "@radix-ui/react-arrow": "1.1.7", 2682 + "@radix-ui/react-compose-refs": "1.1.2", 2683 + "@radix-ui/react-context": "1.1.2", 2684 + "@radix-ui/react-primitive": "2.1.3", 2685 + "@radix-ui/react-use-callback-ref": "1.1.1", 2686 + "@radix-ui/react-use-layout-effect": "1.1.1", 2687 + "@radix-ui/react-use-rect": "1.1.1", 2688 + "@radix-ui/react-use-size": "1.1.1", 2689 + "@radix-ui/rect": "1.1.1" 2690 + }, 2691 + "peerDependencies": { 2692 + "@types/react": "*", 2693 + "@types/react-dom": "*", 2694 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 2695 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 2696 + }, 2697 + "peerDependenciesMeta": { 2698 + "@types/react": { 2699 + "optional": true 2700 + }, 2701 + "@types/react-dom": { 2702 + "optional": true 2703 + } 2704 + } 2705 + }, 2706 + "node_modules/@radix-ui/react-portal": { 2707 + "version": "1.1.9", 2708 + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", 2709 + "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", 2710 + "dependencies": { 2711 + "@radix-ui/react-primitive": "2.1.3", 2712 + "@radix-ui/react-use-layout-effect": "1.1.1" 2713 + }, 2714 + "peerDependencies": { 2715 + "@types/react": "*", 2716 + "@types/react-dom": "*", 2717 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 2718 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 2719 + }, 2720 + "peerDependenciesMeta": { 2721 + "@types/react": { 2722 + "optional": true 2723 + }, 2724 + "@types/react-dom": { 2725 + "optional": true 2726 + } 2727 + } 2728 + }, 2729 + "node_modules/@radix-ui/react-presence": { 2730 + "version": "1.1.5", 2731 + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", 2732 + "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", 2733 + "dependencies": { 2734 + "@radix-ui/react-compose-refs": "1.1.2", 2735 + "@radix-ui/react-use-layout-effect": "1.1.1" 2736 + }, 2737 + "peerDependencies": { 2738 + "@types/react": "*", 2739 + "@types/react-dom": "*", 2740 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 2741 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 2742 + }, 2743 + "peerDependenciesMeta": { 2744 + "@types/react": { 2745 + "optional": true 2746 + }, 2747 + "@types/react-dom": { 2748 + "optional": true 2749 + } 2750 + } 2751 + }, 2752 + "node_modules/@radix-ui/react-primitive": { 2753 + "version": "2.1.3", 2754 + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", 2755 + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", 2756 + "dependencies": { 2757 + "@radix-ui/react-slot": "1.2.3" 2758 + }, 2759 + "peerDependencies": { 2760 + "@types/react": "*", 2761 + "@types/react-dom": "*", 2762 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 2763 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 2764 + }, 2765 + "peerDependenciesMeta": { 2766 + "@types/react": { 2767 + "optional": true 2768 + }, 2769 + "@types/react-dom": { 2770 + "optional": true 2771 + } 2772 + } 2773 + }, 2774 + "node_modules/@radix-ui/react-progress": { 2775 + "version": "1.1.7", 2776 + "resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.7.tgz", 2777 + "integrity": "sha512-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg==", 2778 + "dependencies": { 2779 + "@radix-ui/react-context": "1.1.2", 2780 + "@radix-ui/react-primitive": "2.1.3" 2781 + }, 2782 + "peerDependencies": { 2783 + "@types/react": "*", 2784 + "@types/react-dom": "*", 2785 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 2786 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 2787 + }, 2788 + "peerDependenciesMeta": { 2789 + "@types/react": { 2790 + "optional": true 2791 + }, 2792 + "@types/react-dom": { 2793 + "optional": true 2794 + } 2795 + } 2796 + }, 2797 + "node_modules/@radix-ui/react-radio-group": { 2798 + "version": "1.3.8", 2799 + "resolved": "https://registry.npmjs.org/@radix-ui/react-radio-group/-/react-radio-group-1.3.8.tgz", 2800 + "integrity": "sha512-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ==", 2801 + "dependencies": { 2802 + "@radix-ui/primitive": "1.1.3", 2803 + "@radix-ui/react-compose-refs": "1.1.2", 2804 + "@radix-ui/react-context": "1.1.2", 2805 + "@radix-ui/react-direction": "1.1.1", 2806 + "@radix-ui/react-presence": "1.1.5", 2807 + "@radix-ui/react-primitive": "2.1.3", 2808 + "@radix-ui/react-roving-focus": "1.1.11", 2809 + "@radix-ui/react-use-controllable-state": "1.2.2", 2810 + "@radix-ui/react-use-previous": "1.1.1", 2811 + "@radix-ui/react-use-size": "1.1.1" 2812 + }, 2813 + "peerDependencies": { 2814 + "@types/react": "*", 2815 + "@types/react-dom": "*", 2816 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 2817 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 2818 + }, 2819 + "peerDependenciesMeta": { 2820 + "@types/react": { 2821 + "optional": true 2822 + }, 2823 + "@types/react-dom": { 2824 + "optional": true 2825 + } 2826 + } 2827 + }, 2828 + "node_modules/@radix-ui/react-roving-focus": { 2829 + "version": "1.1.11", 2830 + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz", 2831 + "integrity": "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==", 2832 + "dependencies": { 2833 + "@radix-ui/primitive": "1.1.3", 2834 + "@radix-ui/react-collection": "1.1.7", 2835 + "@radix-ui/react-compose-refs": "1.1.2", 2836 + "@radix-ui/react-context": "1.1.2", 2837 + "@radix-ui/react-direction": "1.1.1", 2838 + "@radix-ui/react-id": "1.1.1", 2839 + "@radix-ui/react-primitive": "2.1.3", 2840 + "@radix-ui/react-use-callback-ref": "1.1.1", 2841 + "@radix-ui/react-use-controllable-state": "1.2.2" 2842 + }, 2843 + "peerDependencies": { 2844 + "@types/react": "*", 2845 + "@types/react-dom": "*", 2846 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 2847 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 2848 + }, 2849 + "peerDependenciesMeta": { 2850 + "@types/react": { 2851 + "optional": true 2852 + }, 2853 + "@types/react-dom": { 2854 + "optional": true 2855 + } 2856 + } 2857 + }, 2858 + "node_modules/@radix-ui/react-scroll-area": { 2859 + "version": "1.2.10", 2860 + "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.10.tgz", 2861 + "integrity": "sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A==", 2862 + "dependencies": { 2863 + "@radix-ui/number": "1.1.1", 2864 + "@radix-ui/primitive": "1.1.3", 2865 + "@radix-ui/react-compose-refs": "1.1.2", 2866 + "@radix-ui/react-context": "1.1.2", 2867 + "@radix-ui/react-direction": "1.1.1", 2868 + "@radix-ui/react-presence": "1.1.5", 2869 + "@radix-ui/react-primitive": "2.1.3", 2870 + "@radix-ui/react-use-callback-ref": "1.1.1", 2871 + "@radix-ui/react-use-layout-effect": "1.1.1" 2872 + }, 2873 + "peerDependencies": { 2874 + "@types/react": "*", 2875 + "@types/react-dom": "*", 2876 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 2877 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 2878 + }, 2879 + "peerDependenciesMeta": { 2880 + "@types/react": { 2881 + "optional": true 2882 + }, 2883 + "@types/react-dom": { 2884 + "optional": true 2885 + } 2886 + } 2887 + }, 2888 + "node_modules/@radix-ui/react-select": { 2889 + "version": "2.2.6", 2890 + "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.6.tgz", 2891 + "integrity": "sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==", 2892 + "dependencies": { 2893 + "@radix-ui/number": "1.1.1", 2894 + "@radix-ui/primitive": "1.1.3", 2895 + "@radix-ui/react-collection": "1.1.7", 2896 + "@radix-ui/react-compose-refs": "1.1.2", 2897 + "@radix-ui/react-context": "1.1.2", 2898 + "@radix-ui/react-direction": "1.1.1", 2899 + "@radix-ui/react-dismissable-layer": "1.1.11", 2900 + "@radix-ui/react-focus-guards": "1.1.3", 2901 + "@radix-ui/react-focus-scope": "1.1.7", 2902 + "@radix-ui/react-id": "1.1.1", 2903 + "@radix-ui/react-popper": "1.2.8", 2904 + "@radix-ui/react-portal": "1.1.9", 2905 + "@radix-ui/react-primitive": "2.1.3", 2906 + "@radix-ui/react-slot": "1.2.3", 2907 + "@radix-ui/react-use-callback-ref": "1.1.1", 2908 + "@radix-ui/react-use-controllable-state": "1.2.2", 2909 + "@radix-ui/react-use-layout-effect": "1.1.1", 2910 + "@radix-ui/react-use-previous": "1.1.1", 2911 + "@radix-ui/react-visually-hidden": "1.2.3", 2912 + "aria-hidden": "^1.2.4", 2913 + "react-remove-scroll": "^2.6.3" 2914 + }, 2915 + "peerDependencies": { 2916 + "@types/react": "*", 2917 + "@types/react-dom": "*", 2918 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 2919 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 2920 + }, 2921 + "peerDependenciesMeta": { 2922 + "@types/react": { 2923 + "optional": true 2924 + }, 2925 + "@types/react-dom": { 2926 + "optional": true 2927 + } 2928 + } 2929 + }, 2930 + "node_modules/@radix-ui/react-separator": { 2931 + "version": "1.1.7", 2932 + "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.7.tgz", 2933 + "integrity": "sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA==", 2934 + "dependencies": { 2935 + "@radix-ui/react-primitive": "2.1.3" 2936 + }, 2937 + "peerDependencies": { 2938 + "@types/react": "*", 2939 + "@types/react-dom": "*", 2940 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 2941 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 2942 + }, 2943 + "peerDependenciesMeta": { 2944 + "@types/react": { 2945 + "optional": true 2946 + }, 2947 + "@types/react-dom": { 2948 + "optional": true 2949 + } 2950 + } 2951 + }, 2952 + "node_modules/@radix-ui/react-slider": { 2953 + "version": "1.3.6", 2954 + "resolved": "https://registry.npmjs.org/@radix-ui/react-slider/-/react-slider-1.3.6.tgz", 2955 + "integrity": "sha512-JPYb1GuM1bxfjMRlNLE+BcmBC8onfCi60Blk7OBqi2MLTFdS+8401U4uFjnwkOr49BLmXxLC6JHkvAsx5OJvHw==", 2956 + "dependencies": { 2957 + "@radix-ui/number": "1.1.1", 2958 + "@radix-ui/primitive": "1.1.3", 2959 + "@radix-ui/react-collection": "1.1.7", 2960 + "@radix-ui/react-compose-refs": "1.1.2", 2961 + "@radix-ui/react-context": "1.1.2", 2962 + "@radix-ui/react-direction": "1.1.1", 2963 + "@radix-ui/react-primitive": "2.1.3", 2964 + "@radix-ui/react-use-controllable-state": "1.2.2", 2965 + "@radix-ui/react-use-layout-effect": "1.1.1", 2966 + "@radix-ui/react-use-previous": "1.1.1", 2967 + "@radix-ui/react-use-size": "1.1.1" 2968 + }, 2969 + "peerDependencies": { 2970 + "@types/react": "*", 2971 + "@types/react-dom": "*", 2972 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 2973 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 2974 + }, 2975 + "peerDependenciesMeta": { 2976 + "@types/react": { 2977 + "optional": true 2978 + }, 2979 + "@types/react-dom": { 2980 + "optional": true 2981 + } 2982 + } 2983 + }, 2984 + "node_modules/@radix-ui/react-slot": { 2985 + "version": "1.2.3", 2986 + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", 2987 + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", 2988 + "dependencies": { 2989 + "@radix-ui/react-compose-refs": "1.1.2" 2990 + }, 2991 + "peerDependencies": { 2992 + "@types/react": "*", 2993 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 2994 + }, 2995 + "peerDependenciesMeta": { 2996 + "@types/react": { 2997 + "optional": true 2998 + } 2999 + } 3000 + }, 3001 + "node_modules/@radix-ui/react-switch": { 3002 + "version": "1.2.6", 3003 + "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.2.6.tgz", 3004 + "integrity": "sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==", 3005 + "dependencies": { 3006 + "@radix-ui/primitive": "1.1.3", 3007 + "@radix-ui/react-compose-refs": "1.1.2", 3008 + "@radix-ui/react-context": "1.1.2", 3009 + "@radix-ui/react-primitive": "2.1.3", 3010 + "@radix-ui/react-use-controllable-state": "1.2.2", 3011 + "@radix-ui/react-use-previous": "1.1.1", 3012 + "@radix-ui/react-use-size": "1.1.1" 3013 + }, 3014 + "peerDependencies": { 3015 + "@types/react": "*", 3016 + "@types/react-dom": "*", 3017 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 3018 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 3019 + }, 3020 + "peerDependenciesMeta": { 3021 + "@types/react": { 3022 + "optional": true 3023 + }, 3024 + "@types/react-dom": { 3025 + "optional": true 3026 + } 3027 + } 3028 + }, 3029 + "node_modules/@radix-ui/react-tabs": { 3030 + "version": "1.1.13", 3031 + "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.13.tgz", 3032 + "integrity": "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==", 3033 + "dependencies": { 3034 + "@radix-ui/primitive": "1.1.3", 3035 + "@radix-ui/react-context": "1.1.2", 3036 + "@radix-ui/react-direction": "1.1.1", 3037 + "@radix-ui/react-id": "1.1.1", 3038 + "@radix-ui/react-presence": "1.1.5", 3039 + "@radix-ui/react-primitive": "2.1.3", 3040 + "@radix-ui/react-roving-focus": "1.1.11", 3041 + "@radix-ui/react-use-controllable-state": "1.2.2" 3042 + }, 3043 + "peerDependencies": { 3044 + "@types/react": "*", 3045 + "@types/react-dom": "*", 3046 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 3047 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 3048 + }, 3049 + "peerDependenciesMeta": { 3050 + "@types/react": { 3051 + "optional": true 3052 + }, 3053 + "@types/react-dom": { 3054 + "optional": true 3055 + } 3056 + } 3057 + }, 3058 + "node_modules/@radix-ui/react-toast": { 3059 + "version": "1.2.15", 3060 + "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.2.15.tgz", 3061 + "integrity": "sha512-3OSz3TacUWy4WtOXV38DggwxoqJK4+eDkNMl5Z/MJZaoUPaP4/9lf81xXMe1I2ReTAptverZUpbPY4wWwWyL5g==", 3062 + "dependencies": { 3063 + "@radix-ui/primitive": "1.1.3", 3064 + "@radix-ui/react-collection": "1.1.7", 3065 + "@radix-ui/react-compose-refs": "1.1.2", 3066 + "@radix-ui/react-context": "1.1.2", 3067 + "@radix-ui/react-dismissable-layer": "1.1.11", 3068 + "@radix-ui/react-portal": "1.1.9", 3069 + "@radix-ui/react-presence": "1.1.5", 3070 + "@radix-ui/react-primitive": "2.1.3", 3071 + "@radix-ui/react-use-callback-ref": "1.1.1", 3072 + "@radix-ui/react-use-controllable-state": "1.2.2", 3073 + "@radix-ui/react-use-layout-effect": "1.1.1", 3074 + "@radix-ui/react-visually-hidden": "1.2.3" 3075 + }, 3076 + "peerDependencies": { 3077 + "@types/react": "*", 3078 + "@types/react-dom": "*", 3079 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 3080 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 3081 + }, 3082 + "peerDependenciesMeta": { 3083 + "@types/react": { 3084 + "optional": true 3085 + }, 3086 + "@types/react-dom": { 3087 + "optional": true 3088 + } 3089 + } 3090 + }, 3091 + "node_modules/@radix-ui/react-toggle": { 3092 + "version": "1.1.10", 3093 + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.1.10.tgz", 3094 + "integrity": "sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ==", 3095 + "dependencies": { 3096 + "@radix-ui/primitive": "1.1.3", 3097 + "@radix-ui/react-primitive": "2.1.3", 3098 + "@radix-ui/react-use-controllable-state": "1.2.2" 3099 + }, 3100 + "peerDependencies": { 3101 + "@types/react": "*", 3102 + "@types/react-dom": "*", 3103 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 3104 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 3105 + }, 3106 + "peerDependenciesMeta": { 3107 + "@types/react": { 3108 + "optional": true 3109 + }, 3110 + "@types/react-dom": { 3111 + "optional": true 3112 + } 3113 + } 3114 + }, 3115 + "node_modules/@radix-ui/react-toggle-group": { 3116 + "version": "1.1.11", 3117 + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle-group/-/react-toggle-group-1.1.11.tgz", 3118 + "integrity": "sha512-5umnS0T8JQzQT6HbPyO7Hh9dgd82NmS36DQr+X/YJ9ctFNCiiQd6IJAYYZ33LUwm8M+taCz5t2ui29fHZc4Y6Q==", 3119 + "dependencies": { 3120 + "@radix-ui/primitive": "1.1.3", 3121 + "@radix-ui/react-context": "1.1.2", 3122 + "@radix-ui/react-direction": "1.1.1", 3123 + "@radix-ui/react-primitive": "2.1.3", 3124 + "@radix-ui/react-roving-focus": "1.1.11", 3125 + "@radix-ui/react-toggle": "1.1.10", 3126 + "@radix-ui/react-use-controllable-state": "1.2.2" 3127 + }, 3128 + "peerDependencies": { 3129 + "@types/react": "*", 3130 + "@types/react-dom": "*", 3131 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 3132 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 3133 + }, 3134 + "peerDependenciesMeta": { 3135 + "@types/react": { 3136 + "optional": true 3137 + }, 3138 + "@types/react-dom": { 3139 + "optional": true 3140 + } 3141 + } 3142 + }, 3143 + "node_modules/@radix-ui/react-toolbar": { 3144 + "version": "1.1.11", 3145 + "resolved": "https://registry.npmjs.org/@radix-ui/react-toolbar/-/react-toolbar-1.1.11.tgz", 3146 + "integrity": "sha512-4ol06/1bLoFu1nwUqzdD4Y5RZ9oDdKeiHIsntug54Hcr1pgaHiPqHFEaXI1IFP/EsOfROQZ8Mig9VTIRza6Tjg==", 3147 + "dependencies": { 3148 + "@radix-ui/primitive": "1.1.3", 3149 + "@radix-ui/react-context": "1.1.2", 3150 + "@radix-ui/react-direction": "1.1.1", 3151 + "@radix-ui/react-primitive": "2.1.3", 3152 + "@radix-ui/react-roving-focus": "1.1.11", 3153 + "@radix-ui/react-separator": "1.1.7", 3154 + "@radix-ui/react-toggle-group": "1.1.11" 3155 + }, 3156 + "peerDependencies": { 3157 + "@types/react": "*", 3158 + "@types/react-dom": "*", 3159 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 3160 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 3161 + }, 3162 + "peerDependenciesMeta": { 3163 + "@types/react": { 3164 + "optional": true 3165 + }, 3166 + "@types/react-dom": { 3167 + "optional": true 3168 + } 3169 + } 3170 + }, 3171 + "node_modules/@radix-ui/react-tooltip": { 3172 + "version": "1.2.8", 3173 + "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.8.tgz", 3174 + "integrity": "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==", 3175 + "dependencies": { 3176 + "@radix-ui/primitive": "1.1.3", 3177 + "@radix-ui/react-compose-refs": "1.1.2", 3178 + "@radix-ui/react-context": "1.1.2", 3179 + "@radix-ui/react-dismissable-layer": "1.1.11", 3180 + "@radix-ui/react-id": "1.1.1", 3181 + "@radix-ui/react-popper": "1.2.8", 3182 + "@radix-ui/react-portal": "1.1.9", 3183 + "@radix-ui/react-presence": "1.1.5", 3184 + "@radix-ui/react-primitive": "2.1.3", 3185 + "@radix-ui/react-slot": "1.2.3", 3186 + "@radix-ui/react-use-controllable-state": "1.2.2", 3187 + "@radix-ui/react-visually-hidden": "1.2.3" 3188 + }, 3189 + "peerDependencies": { 3190 + "@types/react": "*", 3191 + "@types/react-dom": "*", 3192 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 3193 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 3194 + }, 3195 + "peerDependenciesMeta": { 3196 + "@types/react": { 3197 + "optional": true 3198 + }, 3199 + "@types/react-dom": { 3200 + "optional": true 3201 + } 3202 + } 3203 + }, 3204 + "node_modules/@radix-ui/react-use-callback-ref": { 3205 + "version": "1.1.1", 3206 + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", 3207 + "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", 3208 + "peerDependencies": { 3209 + "@types/react": "*", 3210 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 3211 + }, 3212 + "peerDependenciesMeta": { 3213 + "@types/react": { 3214 + "optional": true 3215 + } 3216 + } 3217 + }, 3218 + "node_modules/@radix-ui/react-use-controllable-state": { 3219 + "version": "1.2.2", 3220 + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", 3221 + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", 3222 + "dependencies": { 3223 + "@radix-ui/react-use-effect-event": "0.0.2", 3224 + "@radix-ui/react-use-layout-effect": "1.1.1" 3225 + }, 3226 + "peerDependencies": { 3227 + "@types/react": "*", 3228 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 3229 + }, 3230 + "peerDependenciesMeta": { 3231 + "@types/react": { 3232 + "optional": true 3233 + } 3234 + } 3235 + }, 3236 + "node_modules/@radix-ui/react-use-effect-event": { 3237 + "version": "0.0.2", 3238 + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", 3239 + "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", 3240 + "dependencies": { 3241 + "@radix-ui/react-use-layout-effect": "1.1.1" 3242 + }, 3243 + "peerDependencies": { 3244 + "@types/react": "*", 3245 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 3246 + }, 3247 + "peerDependenciesMeta": { 3248 + "@types/react": { 3249 + "optional": true 3250 + } 3251 + } 3252 + }, 3253 + "node_modules/@radix-ui/react-use-escape-keydown": { 3254 + "version": "1.1.1", 3255 + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz", 3256 + "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==", 3257 + "dependencies": { 3258 + "@radix-ui/react-use-callback-ref": "1.1.1" 3259 + }, 3260 + "peerDependencies": { 3261 + "@types/react": "*", 3262 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 3263 + }, 3264 + "peerDependenciesMeta": { 3265 + "@types/react": { 3266 + "optional": true 3267 + } 3268 + } 3269 + }, 3270 + "node_modules/@radix-ui/react-use-is-hydrated": { 3271 + "version": "0.1.0", 3272 + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.0.tgz", 3273 + "integrity": "sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==", 3274 + "dependencies": { 3275 + "use-sync-external-store": "^1.5.0" 3276 + }, 3277 + "peerDependencies": { 3278 + "@types/react": "*", 3279 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 3280 + }, 3281 + "peerDependenciesMeta": { 3282 + "@types/react": { 3283 + "optional": true 3284 + } 3285 + } 3286 + }, 3287 + "node_modules/@radix-ui/react-use-layout-effect": { 3288 + "version": "1.1.1", 3289 + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", 3290 + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", 3291 + "peerDependencies": { 3292 + "@types/react": "*", 3293 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 3294 + }, 3295 + "peerDependenciesMeta": { 3296 + "@types/react": { 3297 + "optional": true 3298 + } 3299 + } 3300 + }, 3301 + "node_modules/@radix-ui/react-use-previous": { 3302 + "version": "1.1.1", 3303 + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz", 3304 + "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==", 3305 + "peerDependencies": { 3306 + "@types/react": "*", 3307 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 3308 + }, 3309 + "peerDependenciesMeta": { 3310 + "@types/react": { 3311 + "optional": true 3312 + } 3313 + } 3314 + }, 3315 + "node_modules/@radix-ui/react-use-rect": { 3316 + "version": "1.1.1", 3317 + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz", 3318 + "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==", 3319 + "dependencies": { 3320 + "@radix-ui/rect": "1.1.1" 3321 + }, 3322 + "peerDependencies": { 3323 + "@types/react": "*", 3324 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 3325 + }, 3326 + "peerDependenciesMeta": { 3327 + "@types/react": { 3328 + "optional": true 3329 + } 3330 + } 3331 + }, 3332 + "node_modules/@radix-ui/react-use-size": { 3333 + "version": "1.1.1", 3334 + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz", 3335 + "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==", 3336 + "dependencies": { 3337 + "@radix-ui/react-use-layout-effect": "1.1.1" 3338 + }, 3339 + "peerDependencies": { 3340 + "@types/react": "*", 3341 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 3342 + }, 3343 + "peerDependenciesMeta": { 3344 + "@types/react": { 3345 + "optional": true 3346 + } 3347 + } 3348 + }, 3349 + "node_modules/@radix-ui/react-visually-hidden": { 3350 + "version": "1.2.3", 3351 + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", 3352 + "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", 3353 + "dependencies": { 3354 + "@radix-ui/react-primitive": "2.1.3" 3355 + }, 3356 + "peerDependencies": { 3357 + "@types/react": "*", 3358 + "@types/react-dom": "*", 3359 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 3360 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 3361 + }, 3362 + "peerDependenciesMeta": { 3363 + "@types/react": { 3364 + "optional": true 3365 + }, 3366 + "@types/react-dom": { 3367 + "optional": true 3368 + } 3369 + } 3370 + }, 3371 + "node_modules/@radix-ui/rect": { 3372 + "version": "1.1.1", 3373 + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz", 3374 + "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==" 3375 + }, 1230 3376 "node_modules/@rolldown/pluginutils": { 1231 3377 "version": "1.0.0-beta.27", 1232 3378 "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", ··· 1541 3687 "solid-js": "^1.6.12" 1542 3688 } 1543 3689 }, 3690 + "node_modules/@svgr/babel-plugin-add-jsx-attribute": { 3691 + "version": "8.0.0", 3692 + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz", 3693 + "integrity": "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==", 3694 + "dev": true, 3695 + "license": "MIT", 3696 + "engines": { 3697 + "node": ">=14" 3698 + }, 3699 + "funding": { 3700 + "type": "github", 3701 + "url": "https://github.com/sponsors/gregberge" 3702 + }, 3703 + "peerDependencies": { 3704 + "@babel/core": "^7.0.0-0" 3705 + } 3706 + }, 3707 + "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { 3708 + "version": "8.0.0", 3709 + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz", 3710 + "integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==", 3711 + "dev": true, 3712 + "license": "MIT", 3713 + "engines": { 3714 + "node": ">=14" 3715 + }, 3716 + "funding": { 3717 + "type": "github", 3718 + "url": "https://github.com/sponsors/gregberge" 3719 + }, 3720 + "peerDependencies": { 3721 + "@babel/core": "^7.0.0-0" 3722 + } 3723 + }, 3724 + "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { 3725 + "version": "8.0.0", 3726 + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz", 3727 + "integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==", 3728 + "dev": true, 3729 + "license": "MIT", 3730 + "engines": { 3731 + "node": ">=14" 3732 + }, 3733 + "funding": { 3734 + "type": "github", 3735 + "url": "https://github.com/sponsors/gregberge" 3736 + }, 3737 + "peerDependencies": { 3738 + "@babel/core": "^7.0.0-0" 3739 + } 3740 + }, 3741 + "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { 3742 + "version": "8.0.0", 3743 + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz", 3744 + "integrity": "sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==", 3745 + "dev": true, 3746 + "license": "MIT", 3747 + "engines": { 3748 + "node": ">=14" 3749 + }, 3750 + "funding": { 3751 + "type": "github", 3752 + "url": "https://github.com/sponsors/gregberge" 3753 + }, 3754 + "peerDependencies": { 3755 + "@babel/core": "^7.0.0-0" 3756 + } 3757 + }, 3758 + "node_modules/@svgr/babel-plugin-svg-dynamic-title": { 3759 + "version": "8.0.0", 3760 + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz", 3761 + "integrity": "sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==", 3762 + "dev": true, 3763 + "license": "MIT", 3764 + "engines": { 3765 + "node": ">=14" 3766 + }, 3767 + "funding": { 3768 + "type": "github", 3769 + "url": "https://github.com/sponsors/gregberge" 3770 + }, 3771 + "peerDependencies": { 3772 + "@babel/core": "^7.0.0-0" 3773 + } 3774 + }, 3775 + "node_modules/@svgr/babel-plugin-svg-em-dimensions": { 3776 + "version": "8.0.0", 3777 + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz", 3778 + "integrity": "sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==", 3779 + "dev": true, 3780 + "license": "MIT", 3781 + "engines": { 3782 + "node": ">=14" 3783 + }, 3784 + "funding": { 3785 + "type": "github", 3786 + "url": "https://github.com/sponsors/gregberge" 3787 + }, 3788 + "peerDependencies": { 3789 + "@babel/core": "^7.0.0-0" 3790 + } 3791 + }, 3792 + "node_modules/@svgr/babel-plugin-transform-react-native-svg": { 3793 + "version": "8.1.0", 3794 + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.1.0.tgz", 3795 + "integrity": "sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==", 3796 + "dev": true, 3797 + "license": "MIT", 3798 + "engines": { 3799 + "node": ">=14" 3800 + }, 3801 + "funding": { 3802 + "type": "github", 3803 + "url": "https://github.com/sponsors/gregberge" 3804 + }, 3805 + "peerDependencies": { 3806 + "@babel/core": "^7.0.0-0" 3807 + } 3808 + }, 3809 + "node_modules/@svgr/babel-plugin-transform-svg-component": { 3810 + "version": "8.0.0", 3811 + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz", 3812 + "integrity": "sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==", 3813 + "dev": true, 3814 + "license": "MIT", 3815 + "engines": { 3816 + "node": ">=12" 3817 + }, 3818 + "funding": { 3819 + "type": "github", 3820 + "url": "https://github.com/sponsors/gregberge" 3821 + }, 3822 + "peerDependencies": { 3823 + "@babel/core": "^7.0.0-0" 3824 + } 3825 + }, 3826 + "node_modules/@svgr/babel-preset": { 3827 + "version": "8.1.0", 3828 + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-8.1.0.tgz", 3829 + "integrity": "sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==", 3830 + "dev": true, 3831 + "license": "MIT", 3832 + "dependencies": { 3833 + "@svgr/babel-plugin-add-jsx-attribute": "8.0.0", 3834 + "@svgr/babel-plugin-remove-jsx-attribute": "8.0.0", 3835 + "@svgr/babel-plugin-remove-jsx-empty-expression": "8.0.0", 3836 + "@svgr/babel-plugin-replace-jsx-attribute-value": "8.0.0", 3837 + "@svgr/babel-plugin-svg-dynamic-title": "8.0.0", 3838 + "@svgr/babel-plugin-svg-em-dimensions": "8.0.0", 3839 + "@svgr/babel-plugin-transform-react-native-svg": "8.1.0", 3840 + "@svgr/babel-plugin-transform-svg-component": "8.0.0" 3841 + }, 3842 + "engines": { 3843 + "node": ">=14" 3844 + }, 3845 + "funding": { 3846 + "type": "github", 3847 + "url": "https://github.com/sponsors/gregberge" 3848 + }, 3849 + "peerDependencies": { 3850 + "@babel/core": "^7.0.0-0" 3851 + } 3852 + }, 3853 + "node_modules/@svgr/core": { 3854 + "version": "8.1.0", 3855 + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", 3856 + "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", 3857 + "dev": true, 3858 + "license": "MIT", 3859 + "dependencies": { 3860 + "@babel/core": "^7.21.3", 3861 + "@svgr/babel-preset": "8.1.0", 3862 + "camelcase": "^6.2.0", 3863 + "cosmiconfig": "^8.1.3", 3864 + "snake-case": "^3.0.4" 3865 + }, 3866 + "engines": { 3867 + "node": ">=14" 3868 + }, 3869 + "funding": { 3870 + "type": "github", 3871 + "url": "https://github.com/sponsors/gregberge" 3872 + } 3873 + }, 3874 + "node_modules/@svgr/hast-util-to-babel-ast": { 3875 + "version": "8.0.0", 3876 + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz", 3877 + "integrity": "sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==", 3878 + "dev": true, 3879 + "license": "MIT", 3880 + "dependencies": { 3881 + "@babel/types": "^7.21.3", 3882 + "entities": "^4.4.0" 3883 + }, 3884 + "engines": { 3885 + "node": ">=14" 3886 + }, 3887 + "funding": { 3888 + "type": "github", 3889 + "url": "https://github.com/sponsors/gregberge" 3890 + } 3891 + }, 3892 + "node_modules/@svgr/hast-util-to-babel-ast/node_modules/entities": { 3893 + "version": "4.5.0", 3894 + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", 3895 + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", 3896 + "dev": true, 3897 + "license": "BSD-2-Clause", 3898 + "engines": { 3899 + "node": ">=0.12" 3900 + }, 3901 + "funding": { 3902 + "url": "https://github.com/fb55/entities?sponsor=1" 3903 + } 3904 + }, 3905 + "node_modules/@svgr/plugin-jsx": { 3906 + "version": "8.1.0", 3907 + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz", 3908 + "integrity": "sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==", 3909 + "dev": true, 3910 + "license": "MIT", 3911 + "dependencies": { 3912 + "@babel/core": "^7.21.3", 3913 + "@svgr/babel-preset": "8.1.0", 3914 + "@svgr/hast-util-to-babel-ast": "8.0.0", 3915 + "svg-parser": "^2.0.4" 3916 + }, 3917 + "engines": { 3918 + "node": ">=14" 3919 + }, 3920 + "funding": { 3921 + "type": "github", 3922 + "url": "https://github.com/sponsors/gregberge" 3923 + }, 3924 + "peerDependencies": { 3925 + "@svgr/core": "*" 3926 + } 3927 + }, 1544 3928 "node_modules/@svta/common-media-library": { 1545 3929 "version": "0.12.4", 1546 3930 "resolved": "https://registry.npmjs.org/@svta/common-media-library/-/common-media-library-0.12.4.tgz", ··· 1882 4266 "url": "https://github.com/sponsors/tannerlinsley" 1883 4267 } 1884 4268 }, 4269 + "node_modules/@tanstack/query-core": { 4270 + "version": "5.85.6", 4271 + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.85.6.tgz", 4272 + "integrity": "sha512-hCj0TktzdCv2bCepIdfwqVwUVWb+GSHm1Jnn8w+40lfhQ3m7lCO7ADRUJy+2unxQ/nzjh2ipC6ye69NDW3l73g==", 4273 + "license": "MIT", 4274 + "funding": { 4275 + "type": "github", 4276 + "url": "https://github.com/sponsors/tannerlinsley" 4277 + } 4278 + }, 4279 + "node_modules/@tanstack/query-persist-client-core": { 4280 + "version": "5.85.6", 4281 + "resolved": "https://registry.npmjs.org/@tanstack/query-persist-client-core/-/query-persist-client-core-5.85.6.tgz", 4282 + "integrity": "sha512-wUdoEurIC0YCNZzR020Xcg3OsJeF4SXmEPqlNwZ6EaGKgWeNjU17hVdK+X4ZeirUm+h0muiEQx+aIQU1lk7roQ==", 4283 + "license": "MIT", 4284 + "dependencies": { 4285 + "@tanstack/query-core": "5.85.6" 4286 + }, 4287 + "funding": { 4288 + "type": "github", 4289 + "url": "https://github.com/sponsors/tannerlinsley" 4290 + } 4291 + }, 4292 + "node_modules/@tanstack/query-sync-storage-persister": { 4293 + "version": "5.85.6", 4294 + "resolved": "https://registry.npmjs.org/@tanstack/query-sync-storage-persister/-/query-sync-storage-persister-5.85.6.tgz", 4295 + "integrity": "sha512-Gj/p0paYsdzj3IbRn6SjMMNdjZ0nVQWszn17qbHLiu3Mt6H0b/YbLL3g9uRWcoyYcaB004RawgM0MuA+xJt5iw==", 4296 + "license": "MIT", 4297 + "dependencies": { 4298 + "@tanstack/query-core": "5.85.6", 4299 + "@tanstack/query-persist-client-core": "5.85.6" 4300 + }, 4301 + "funding": { 4302 + "type": "github", 4303 + "url": "https://github.com/sponsors/tannerlinsley" 4304 + } 4305 + }, 1885 4306 "node_modules/@tanstack/react-devtools": { 1886 4307 "version": "0.2.2", 1887 4308 "resolved": "https://registry.npmjs.org/@tanstack/react-devtools/-/react-devtools-0.2.2.tgz", ··· 1902 4323 "@types/react-dom": ">=16.8", 1903 4324 "react": ">=16.8", 1904 4325 "react-dom": ">=16.8" 4326 + } 4327 + }, 4328 + "node_modules/@tanstack/react-query": { 4329 + "version": "5.85.6", 4330 + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.85.6.tgz", 4331 + "integrity": "sha512-VUAag4ERjh+qlmg0wNivQIVCZUrYndqYu3/wPCVZd4r0E+1IqotbeyGTc+ICroL/PqbpSaGZg02zSWYfcvxbdA==", 4332 + "license": "MIT", 4333 + "dependencies": { 4334 + "@tanstack/query-core": "5.85.6" 4335 + }, 4336 + "funding": { 4337 + "type": "github", 4338 + "url": "https://github.com/sponsors/tannerlinsley" 4339 + }, 4340 + "peerDependencies": { 4341 + "react": "^18 || ^19" 4342 + } 4343 + }, 4344 + "node_modules/@tanstack/react-query-persist-client": { 4345 + "version": "5.85.6", 4346 + "resolved": "https://registry.npmjs.org/@tanstack/react-query-persist-client/-/react-query-persist-client-5.85.6.tgz", 4347 + "integrity": "sha512-zLUfm8JlI6/s0AqvX5l5CcazdHwj5gwcv0mWYOaJJvADyFzl2wwQKqB/H4nYSeygUtrepBgPwVQKNqH9ZwlZpQ==", 4348 + "license": "MIT", 4349 + "dependencies": { 4350 + "@tanstack/query-persist-client-core": "5.85.6" 4351 + }, 4352 + "funding": { 4353 + "type": "github", 4354 + "url": "https://github.com/sponsors/tannerlinsley" 4355 + }, 4356 + "peerDependencies": { 4357 + "@tanstack/react-query": "^5.85.6", 4358 + "react": "^18 || ^19" 1905 4359 } 1906 4360 }, 1907 4361 "node_modules/@tanstack/react-router": { ··· 2262 4716 "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", 2263 4717 "license": "MIT" 2264 4718 }, 4719 + "node_modules/@types/json-schema": { 4720 + "version": "7.0.15", 4721 + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", 4722 + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", 4723 + "dev": true, 4724 + "license": "MIT", 4725 + "peer": true 4726 + }, 2265 4727 "node_modules/@types/node": { 2266 4728 "version": "24.3.0", 2267 4729 "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.0.tgz", ··· 2290 4752 "@types/react": "^19.0.0" 2291 4753 } 2292 4754 }, 4755 + "node_modules/@types/trusted-types": { 4756 + "version": "2.0.7", 4757 + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", 4758 + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", 4759 + "license": "MIT", 4760 + "optional": true 4761 + }, 4762 + "node_modules/@typescript-eslint/eslint-plugin": { 4763 + "version": "8.46.1", 4764 + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.1.tgz", 4765 + "integrity": "sha512-rUsLh8PXmBjdiPY+Emjz9NX2yHvhS11v0SR6xNJkm5GM1MO9ea/1GoDKlHHZGrOJclL/cZ2i/vRUYVtjRhrHVQ==", 4766 + "dev": true, 4767 + "license": "MIT", 4768 + "dependencies": { 4769 + "@eslint-community/regexpp": "^4.10.0", 4770 + "@typescript-eslint/scope-manager": "8.46.1", 4771 + "@typescript-eslint/type-utils": "8.46.1", 4772 + "@typescript-eslint/utils": "8.46.1", 4773 + "@typescript-eslint/visitor-keys": "8.46.1", 4774 + "graphemer": "^1.4.0", 4775 + "ignore": "^7.0.0", 4776 + "natural-compare": "^1.4.0", 4777 + "ts-api-utils": "^2.1.0" 4778 + }, 4779 + "engines": { 4780 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 4781 + }, 4782 + "funding": { 4783 + "type": "opencollective", 4784 + "url": "https://opencollective.com/typescript-eslint" 4785 + }, 4786 + "peerDependencies": { 4787 + "@typescript-eslint/parser": "^8.46.1", 4788 + "eslint": "^8.57.0 || ^9.0.0", 4789 + "typescript": ">=4.8.4 <6.0.0" 4790 + } 4791 + }, 4792 + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { 4793 + "version": "7.0.5", 4794 + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", 4795 + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", 4796 + "dev": true, 4797 + "license": "MIT", 4798 + "engines": { 4799 + "node": ">= 4" 4800 + } 4801 + }, 4802 + "node_modules/@typescript-eslint/parser": { 4803 + "version": "8.46.1", 4804 + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.46.1.tgz", 4805 + "integrity": "sha512-6JSSaBZmsKvEkbRUkf7Zj7dru/8ZCrJxAqArcLaVMee5907JdtEbKGsZ7zNiIm/UAkpGUkaSMZEXShnN2D1HZA==", 4806 + "dev": true, 4807 + "license": "MIT", 4808 + "dependencies": { 4809 + "@typescript-eslint/scope-manager": "8.46.1", 4810 + "@typescript-eslint/types": "8.46.1", 4811 + "@typescript-eslint/typescript-estree": "8.46.1", 4812 + "@typescript-eslint/visitor-keys": "8.46.1", 4813 + "debug": "^4.3.4" 4814 + }, 4815 + "engines": { 4816 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 4817 + }, 4818 + "funding": { 4819 + "type": "opencollective", 4820 + "url": "https://opencollective.com/typescript-eslint" 4821 + }, 4822 + "peerDependencies": { 4823 + "eslint": "^8.57.0 || ^9.0.0", 4824 + "typescript": ">=4.8.4 <6.0.0" 4825 + } 4826 + }, 4827 + "node_modules/@typescript-eslint/project-service": { 4828 + "version": "8.46.1", 4829 + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.46.1.tgz", 4830 + "integrity": "sha512-FOIaFVMHzRskXr5J4Jp8lFVV0gz5ngv3RHmn+E4HYxSJ3DgDzU7fVI1/M7Ijh1zf6S7HIoaIOtln1H5y8V+9Zg==", 4831 + "dev": true, 4832 + "license": "MIT", 4833 + "dependencies": { 4834 + "@typescript-eslint/tsconfig-utils": "^8.46.1", 4835 + "@typescript-eslint/types": "^8.46.1", 4836 + "debug": "^4.3.4" 4837 + }, 4838 + "engines": { 4839 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 4840 + }, 4841 + "funding": { 4842 + "type": "opencollective", 4843 + "url": "https://opencollective.com/typescript-eslint" 4844 + }, 4845 + "peerDependencies": { 4846 + "typescript": ">=4.8.4 <6.0.0" 4847 + } 4848 + }, 4849 + "node_modules/@typescript-eslint/scope-manager": { 4850 + "version": "8.46.1", 4851 + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.46.1.tgz", 4852 + "integrity": "sha512-weL9Gg3/5F0pVQKiF8eOXFZp8emqWzZsOJuWRUNtHT+UNV2xSJegmpCNQHy37aEQIbToTq7RHKhWvOsmbM680A==", 4853 + "dev": true, 4854 + "license": "MIT", 4855 + "dependencies": { 4856 + "@typescript-eslint/types": "8.46.1", 4857 + "@typescript-eslint/visitor-keys": "8.46.1" 4858 + }, 4859 + "engines": { 4860 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 4861 + }, 4862 + "funding": { 4863 + "type": "opencollective", 4864 + "url": "https://opencollective.com/typescript-eslint" 4865 + } 4866 + }, 4867 + "node_modules/@typescript-eslint/tsconfig-utils": { 4868 + "version": "8.46.1", 4869 + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.46.1.tgz", 4870 + "integrity": "sha512-X88+J/CwFvlJB+mK09VFqx5FE4H5cXD+H/Bdza2aEWkSb8hnWIQorNcscRl4IEo1Cz9VI/+/r/jnGWkbWPx54g==", 4871 + "dev": true, 4872 + "license": "MIT", 4873 + "engines": { 4874 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 4875 + }, 4876 + "funding": { 4877 + "type": "opencollective", 4878 + "url": "https://opencollective.com/typescript-eslint" 4879 + }, 4880 + "peerDependencies": { 4881 + "typescript": ">=4.8.4 <6.0.0" 4882 + } 4883 + }, 4884 + "node_modules/@typescript-eslint/type-utils": { 4885 + "version": "8.46.1", 4886 + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.46.1.tgz", 4887 + "integrity": "sha512-+BlmiHIiqufBxkVnOtFwjah/vrkF4MtKKvpXrKSPLCkCtAp8H01/VV43sfqA98Od7nJpDcFnkwgyfQbOG0AMvw==", 4888 + "dev": true, 4889 + "license": "MIT", 4890 + "dependencies": { 4891 + "@typescript-eslint/types": "8.46.1", 4892 + "@typescript-eslint/typescript-estree": "8.46.1", 4893 + "@typescript-eslint/utils": "8.46.1", 4894 + "debug": "^4.3.4", 4895 + "ts-api-utils": "^2.1.0" 4896 + }, 4897 + "engines": { 4898 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 4899 + }, 4900 + "funding": { 4901 + "type": "opencollective", 4902 + "url": "https://opencollective.com/typescript-eslint" 4903 + }, 4904 + "peerDependencies": { 4905 + "eslint": "^8.57.0 || ^9.0.0", 4906 + "typescript": ">=4.8.4 <6.0.0" 4907 + } 4908 + }, 4909 + "node_modules/@typescript-eslint/types": { 4910 + "version": "8.46.1", 4911 + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.46.1.tgz", 4912 + "integrity": "sha512-C+soprGBHwWBdkDpbaRC4paGBrkIXxVlNohadL5o0kfhsXqOC6GYH2S/Obmig+I0HTDl8wMaRySwrfrXVP8/pQ==", 4913 + "dev": true, 4914 + "license": "MIT", 4915 + "engines": { 4916 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 4917 + }, 4918 + "funding": { 4919 + "type": "opencollective", 4920 + "url": "https://opencollective.com/typescript-eslint" 4921 + } 4922 + }, 4923 + "node_modules/@typescript-eslint/typescript-estree": { 4924 + "version": "8.46.1", 4925 + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.46.1.tgz", 4926 + "integrity": "sha512-uIifjT4s8cQKFQ8ZBXXyoUODtRoAd7F7+G8MKmtzj17+1UbdzFl52AzRyZRyKqPHhgzvXunnSckVu36flGy8cg==", 4927 + "dev": true, 4928 + "license": "MIT", 4929 + "dependencies": { 4930 + "@typescript-eslint/project-service": "8.46.1", 4931 + "@typescript-eslint/tsconfig-utils": "8.46.1", 4932 + "@typescript-eslint/types": "8.46.1", 4933 + "@typescript-eslint/visitor-keys": "8.46.1", 4934 + "debug": "^4.3.4", 4935 + "fast-glob": "^3.3.2", 4936 + "is-glob": "^4.0.3", 4937 + "minimatch": "^9.0.4", 4938 + "semver": "^7.6.0", 4939 + "ts-api-utils": "^2.1.0" 4940 + }, 4941 + "engines": { 4942 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 4943 + }, 4944 + "funding": { 4945 + "type": "opencollective", 4946 + "url": "https://opencollective.com/typescript-eslint" 4947 + }, 4948 + "peerDependencies": { 4949 + "typescript": ">=4.8.4 <6.0.0" 4950 + } 4951 + }, 4952 + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { 4953 + "version": "2.0.2", 4954 + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", 4955 + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", 4956 + "dev": true, 4957 + "license": "MIT", 4958 + "dependencies": { 4959 + "balanced-match": "^1.0.0" 4960 + } 4961 + }, 4962 + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { 4963 + "version": "9.0.5", 4964 + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", 4965 + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", 4966 + "dev": true, 4967 + "license": "ISC", 4968 + "dependencies": { 4969 + "brace-expansion": "^2.0.1" 4970 + }, 4971 + "engines": { 4972 + "node": ">=16 || 14 >=14.17" 4973 + }, 4974 + "funding": { 4975 + "url": "https://github.com/sponsors/isaacs" 4976 + } 4977 + }, 4978 + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { 4979 + "version": "7.7.3", 4980 + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", 4981 + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", 4982 + "dev": true, 4983 + "license": "ISC", 4984 + "bin": { 4985 + "semver": "bin/semver.js" 4986 + }, 4987 + "engines": { 4988 + "node": ">=10" 4989 + } 4990 + }, 4991 + "node_modules/@typescript-eslint/utils": { 4992 + "version": "8.46.1", 4993 + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.46.1.tgz", 4994 + "integrity": "sha512-vkYUy6LdZS7q1v/Gxb2Zs7zziuXN0wxqsetJdeZdRe/f5dwJFglmuvZBfTUivCtjH725C1jWCDfpadadD95EDQ==", 4995 + "dev": true, 4996 + "license": "MIT", 4997 + "dependencies": { 4998 + "@eslint-community/eslint-utils": "^4.7.0", 4999 + "@typescript-eslint/scope-manager": "8.46.1", 5000 + "@typescript-eslint/types": "8.46.1", 5001 + "@typescript-eslint/typescript-estree": "8.46.1" 5002 + }, 5003 + "engines": { 5004 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 5005 + }, 5006 + "funding": { 5007 + "type": "opencollective", 5008 + "url": "https://opencollective.com/typescript-eslint" 5009 + }, 5010 + "peerDependencies": { 5011 + "eslint": "^8.57.0 || ^9.0.0", 5012 + "typescript": ">=4.8.4 <6.0.0" 5013 + } 5014 + }, 5015 + "node_modules/@typescript-eslint/visitor-keys": { 5016 + "version": "8.46.1", 5017 + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.46.1.tgz", 5018 + "integrity": "sha512-ptkmIf2iDkNUjdeu2bQqhFPV1m6qTnFFjg7PPDjxKWaMaP0Z6I9l30Jr3g5QqbZGdw8YdYvLp+XnqnWWZOg/NA==", 5019 + "dev": true, 5020 + "license": "MIT", 5021 + "dependencies": { 5022 + "@typescript-eslint/types": "8.46.1", 5023 + "eslint-visitor-keys": "^4.2.1" 5024 + }, 5025 + "engines": { 5026 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 5027 + }, 5028 + "funding": { 5029 + "type": "opencollective", 5030 + "url": "https://opencollective.com/typescript-eslint" 5031 + } 5032 + }, 2293 5033 "node_modules/@vercel/edge": { 2294 5034 "version": "1.2.2", 2295 5035 "resolved": "https://registry.npmjs.org/@vercel/edge/-/edge-1.2.2.tgz", ··· 2454 5194 "node": ">=0.4.0" 2455 5195 } 2456 5196 }, 5197 + "node_modules/acorn-jsx": { 5198 + "version": "5.3.2", 5199 + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", 5200 + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", 5201 + "dev": true, 5202 + "license": "MIT", 5203 + "peer": true, 5204 + "peerDependencies": { 5205 + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" 5206 + } 5207 + }, 2457 5208 "node_modules/agent-base": { 2458 5209 "version": "7.1.4", 2459 5210 "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", ··· 2464 5215 "node": ">= 14" 2465 5216 } 2466 5217 }, 5218 + "node_modules/ajv": { 5219 + "version": "6.12.6", 5220 + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", 5221 + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", 5222 + "dev": true, 5223 + "license": "MIT", 5224 + "peer": true, 5225 + "dependencies": { 5226 + "fast-deep-equal": "^3.1.1", 5227 + "fast-json-stable-stringify": "^2.0.0", 5228 + "json-schema-traverse": "^0.4.1", 5229 + "uri-js": "^4.2.2" 5230 + }, 5231 + "funding": { 5232 + "type": "github", 5233 + "url": "https://github.com/sponsors/epoberezkin" 5234 + } 5235 + }, 2467 5236 "node_modules/ansi-regex": { 2468 5237 "version": "5.0.1", 2469 5238 "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", ··· 2509 5278 "node": ">= 8" 2510 5279 } 2511 5280 }, 5281 + "node_modules/argparse": { 5282 + "version": "2.0.1", 5283 + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", 5284 + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", 5285 + "dev": true, 5286 + "license": "Python-2.0" 5287 + }, 5288 + "node_modules/aria-hidden": { 5289 + "version": "1.2.6", 5290 + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", 5291 + "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", 5292 + "dependencies": { 5293 + "tslib": "^2.0.0" 5294 + }, 5295 + "engines": { 5296 + "node": ">=10" 5297 + } 5298 + }, 2512 5299 "node_modules/aria-query": { 2513 5300 "version": "5.3.0", 2514 5301 "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", ··· 2519 5306 "dequal": "^2.0.3" 2520 5307 } 2521 5308 }, 5309 + "node_modules/array-buffer-byte-length": { 5310 + "version": "1.0.2", 5311 + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", 5312 + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", 5313 + "dev": true, 5314 + "license": "MIT", 5315 + "dependencies": { 5316 + "call-bound": "^1.0.3", 5317 + "is-array-buffer": "^3.0.5" 5318 + }, 5319 + "engines": { 5320 + "node": ">= 0.4" 5321 + }, 5322 + "funding": { 5323 + "url": "https://github.com/sponsors/ljharb" 5324 + } 5325 + }, 5326 + "node_modules/array-includes": { 5327 + "version": "3.1.9", 5328 + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", 5329 + "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", 5330 + "dev": true, 5331 + "license": "MIT", 5332 + "dependencies": { 5333 + "call-bind": "^1.0.8", 5334 + "call-bound": "^1.0.4", 5335 + "define-properties": "^1.2.1", 5336 + "es-abstract": "^1.24.0", 5337 + "es-object-atoms": "^1.1.1", 5338 + "get-intrinsic": "^1.3.0", 5339 + "is-string": "^1.1.1", 5340 + "math-intrinsics": "^1.1.0" 5341 + }, 5342 + "engines": { 5343 + "node": ">= 0.4" 5344 + }, 5345 + "funding": { 5346 + "url": "https://github.com/sponsors/ljharb" 5347 + } 5348 + }, 5349 + "node_modules/array.prototype.findlast": { 5350 + "version": "1.2.5", 5351 + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", 5352 + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", 5353 + "dev": true, 5354 + "license": "MIT", 5355 + "dependencies": { 5356 + "call-bind": "^1.0.7", 5357 + "define-properties": "^1.2.1", 5358 + "es-abstract": "^1.23.2", 5359 + "es-errors": "^1.3.0", 5360 + "es-object-atoms": "^1.0.0", 5361 + "es-shim-unscopables": "^1.0.2" 5362 + }, 5363 + "engines": { 5364 + "node": ">= 0.4" 5365 + }, 5366 + "funding": { 5367 + "url": "https://github.com/sponsors/ljharb" 5368 + } 5369 + }, 5370 + "node_modules/array.prototype.flat": { 5371 + "version": "1.3.3", 5372 + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", 5373 + "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", 5374 + "dev": true, 5375 + "license": "MIT", 5376 + "dependencies": { 5377 + "call-bind": "^1.0.8", 5378 + "define-properties": "^1.2.1", 5379 + "es-abstract": "^1.23.5", 5380 + "es-shim-unscopables": "^1.0.2" 5381 + }, 5382 + "engines": { 5383 + "node": ">= 0.4" 5384 + }, 5385 + "funding": { 5386 + "url": "https://github.com/sponsors/ljharb" 5387 + } 5388 + }, 5389 + "node_modules/array.prototype.flatmap": { 5390 + "version": "1.3.3", 5391 + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", 5392 + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", 5393 + "dev": true, 5394 + "license": "MIT", 5395 + "dependencies": { 5396 + "call-bind": "^1.0.8", 5397 + "define-properties": "^1.2.1", 5398 + "es-abstract": "^1.23.5", 5399 + "es-shim-unscopables": "^1.0.2" 5400 + }, 5401 + "engines": { 5402 + "node": ">= 0.4" 5403 + }, 5404 + "funding": { 5405 + "url": "https://github.com/sponsors/ljharb" 5406 + } 5407 + }, 5408 + "node_modules/array.prototype.tosorted": { 5409 + "version": "1.1.4", 5410 + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", 5411 + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", 5412 + "dev": true, 5413 + "license": "MIT", 5414 + "dependencies": { 5415 + "call-bind": "^1.0.7", 5416 + "define-properties": "^1.2.1", 5417 + "es-abstract": "^1.23.3", 5418 + "es-errors": "^1.3.0", 5419 + "es-shim-unscopables": "^1.0.2" 5420 + }, 5421 + "engines": { 5422 + "node": ">= 0.4" 5423 + } 5424 + }, 5425 + "node_modules/arraybuffer.prototype.slice": { 5426 + "version": "1.0.4", 5427 + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", 5428 + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", 5429 + "dev": true, 5430 + "license": "MIT", 5431 + "dependencies": { 5432 + "array-buffer-byte-length": "^1.0.1", 5433 + "call-bind": "^1.0.8", 5434 + "define-properties": "^1.2.1", 5435 + "es-abstract": "^1.23.5", 5436 + "es-errors": "^1.3.0", 5437 + "get-intrinsic": "^1.2.6", 5438 + "is-array-buffer": "^3.0.4" 5439 + }, 5440 + "engines": { 5441 + "node": ">= 0.4" 5442 + }, 5443 + "funding": { 5444 + "url": "https://github.com/sponsors/ljharb" 5445 + } 5446 + }, 2522 5447 "node_modules/assertion-error": { 2523 5448 "version": "2.0.1", 2524 5449 "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", ··· 2541 5466 "node": ">=4" 2542 5467 } 2543 5468 }, 5469 + "node_modules/async-function": { 5470 + "version": "1.0.0", 5471 + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", 5472 + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", 5473 + "dev": true, 5474 + "license": "MIT", 5475 + "engines": { 5476 + "node": ">= 0.4" 5477 + } 5478 + }, 5479 + "node_modules/available-typed-arrays": { 5480 + "version": "1.0.7", 5481 + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", 5482 + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", 5483 + "dev": true, 5484 + "license": "MIT", 5485 + "dependencies": { 5486 + "possible-typed-array-names": "^1.0.0" 5487 + }, 5488 + "engines": { 5489 + "node": ">= 0.4" 5490 + }, 5491 + "funding": { 5492 + "url": "https://github.com/sponsors/ljharb" 5493 + } 5494 + }, 2544 5495 "node_modules/await-lock": { 2545 5496 "version": "2.2.2", 2546 5497 "resolved": "https://registry.npmjs.org/await-lock/-/await-lock-2.2.2.tgz", ··· 2558 5509 "@babel/traverse": "^7.23.7", 2559 5510 "@babel/types": "^7.23.6" 2560 5511 } 5512 + }, 5513 + "node_modules/babel-plugin-react-compiler": { 5514 + "version": "1.0.0", 5515 + "resolved": "https://registry.npmjs.org/babel-plugin-react-compiler/-/babel-plugin-react-compiler-1.0.0.tgz", 5516 + "integrity": "sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==", 5517 + "dev": true, 5518 + "license": "MIT", 5519 + "dependencies": { 5520 + "@babel/types": "^7.26.0" 5521 + } 5522 + }, 5523 + "node_modules/balanced-match": { 5524 + "version": "1.0.2", 5525 + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 5526 + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 5527 + "dev": true, 5528 + "license": "MIT" 2561 5529 }, 2562 5530 "node_modules/bcp-47": { 2563 5531 "version": "2.1.0", ··· 2610 5578 "url": "https://github.com/sponsors/sindresorhus" 2611 5579 } 2612 5580 }, 5581 + "node_modules/birecord": { 5582 + "version": "0.1.1", 5583 + "resolved": "https://registry.npmjs.org/birecord/-/birecord-0.1.1.tgz", 5584 + "integrity": "sha512-VUpsf/qykW0heRlC8LooCq28Kxn3mAqKohhDG/49rrsQ1dT1CXyj/pgXS+5BSRzFTR/3DyIBOqQOrGyZOh71Aw==", 5585 + "dev": true, 5586 + "license": "(MIT OR Apache-2.0)" 5587 + }, 5588 + "node_modules/brace-expansion": { 5589 + "version": "1.1.12", 5590 + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", 5591 + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", 5592 + "dev": true, 5593 + "license": "MIT", 5594 + "dependencies": { 5595 + "balanced-match": "^1.0.0", 5596 + "concat-map": "0.0.1" 5597 + } 5598 + }, 2613 5599 "node_modules/braces": { 2614 5600 "version": "3.0.3", 2615 5601 "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", ··· 2664 5650 "node": ">=8" 2665 5651 } 2666 5652 }, 5653 + "node_modules/call-bind": { 5654 + "version": "1.0.8", 5655 + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", 5656 + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", 5657 + "dev": true, 5658 + "license": "MIT", 5659 + "dependencies": { 5660 + "call-bind-apply-helpers": "^1.0.0", 5661 + "es-define-property": "^1.0.0", 5662 + "get-intrinsic": "^1.2.4", 5663 + "set-function-length": "^1.2.2" 5664 + }, 5665 + "engines": { 5666 + "node": ">= 0.4" 5667 + }, 5668 + "funding": { 5669 + "url": "https://github.com/sponsors/ljharb" 5670 + } 5671 + }, 5672 + "node_modules/call-bind-apply-helpers": { 5673 + "version": "1.0.2", 5674 + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", 5675 + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", 5676 + "dev": true, 5677 + "license": "MIT", 5678 + "dependencies": { 5679 + "es-errors": "^1.3.0", 5680 + "function-bind": "^1.1.2" 5681 + }, 5682 + "engines": { 5683 + "node": ">= 0.4" 5684 + } 5685 + }, 5686 + "node_modules/call-bound": { 5687 + "version": "1.0.4", 5688 + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", 5689 + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", 5690 + "dev": true, 5691 + "license": "MIT", 5692 + "dependencies": { 5693 + "call-bind-apply-helpers": "^1.0.2", 5694 + "get-intrinsic": "^1.3.0" 5695 + }, 5696 + "engines": { 5697 + "node": ">= 0.4" 5698 + }, 5699 + "funding": { 5700 + "url": "https://github.com/sponsors/ljharb" 5701 + } 5702 + }, 5703 + "node_modules/callsites": { 5704 + "version": "3.1.0", 5705 + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", 5706 + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", 5707 + "dev": true, 5708 + "license": "MIT", 5709 + "engines": { 5710 + "node": ">=6" 5711 + } 5712 + }, 5713 + "node_modules/camelcase": { 5714 + "version": "6.3.0", 5715 + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", 5716 + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", 5717 + "dev": true, 5718 + "license": "MIT", 5719 + "engines": { 5720 + "node": ">=10" 5721 + }, 5722 + "funding": { 5723 + "url": "https://github.com/sponsors/sindresorhus" 5724 + } 5725 + }, 2667 5726 "node_modules/caniuse-lite": { 2668 5727 "version": "1.0.30001737", 2669 5728 "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001737.tgz", ··· 2719 5778 "node": ">=18" 2720 5779 } 2721 5780 }, 5781 + "node_modules/chalk": { 5782 + "version": "4.1.2", 5783 + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", 5784 + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", 5785 + "dev": true, 5786 + "license": "MIT", 5787 + "peer": true, 5788 + "dependencies": { 5789 + "ansi-styles": "^4.1.0", 5790 + "supports-color": "^7.1.0" 5791 + }, 5792 + "engines": { 5793 + "node": ">=10" 5794 + }, 5795 + "funding": { 5796 + "url": "https://github.com/chalk/chalk?sponsor=1" 5797 + } 5798 + }, 5799 + "node_modules/chalk/node_modules/ansi-styles": { 5800 + "version": "4.3.0", 5801 + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 5802 + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 5803 + "dev": true, 5804 + "license": "MIT", 5805 + "peer": true, 5806 + "dependencies": { 5807 + "color-convert": "^2.0.1" 5808 + }, 5809 + "engines": { 5810 + "node": ">=8" 5811 + }, 5812 + "funding": { 5813 + "url": "https://github.com/chalk/ansi-styles?sponsor=1" 5814 + } 5815 + }, 2722 5816 "node_modules/check-error": { 2723 5817 "version": "2.1.1", 2724 5818 "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", ··· 2783 5877 "integrity": "sha512-eNk3TRV+xQMJ1PEj0FQGY8KD4m0GPxT487XJ+Iftm7mVa9WpPFDMWqPt+46buiP5j5Wzqe5oMIhqBcAeKfygSA==", 2784 5878 "license": "MIT" 2785 5879 }, 5880 + "node_modules/color-convert": { 5881 + "version": "2.0.1", 5882 + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 5883 + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 5884 + "dev": true, 5885 + "license": "MIT", 5886 + "peer": true, 5887 + "dependencies": { 5888 + "color-name": "~1.1.4" 5889 + }, 5890 + "engines": { 5891 + "node": ">=7.0.0" 5892 + } 5893 + }, 5894 + "node_modules/color-name": { 5895 + "version": "1.1.4", 5896 + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 5897 + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 5898 + "dev": true, 5899 + "license": "MIT", 5900 + "peer": true 5901 + }, 5902 + "node_modules/compare-versions": { 5903 + "version": "6.1.1", 5904 + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.1.tgz", 5905 + "integrity": "sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==", 5906 + "dev": true, 5907 + "license": "MIT" 5908 + }, 5909 + "node_modules/concat-map": { 5910 + "version": "0.0.1", 5911 + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 5912 + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", 5913 + "dev": true, 5914 + "license": "MIT" 5915 + }, 5916 + "node_modules/confbox": { 5917 + "version": "0.2.2", 5918 + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", 5919 + "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", 5920 + "dev": true, 5921 + "license": "MIT" 5922 + }, 2786 5923 "node_modules/convert-source-map": { 2787 5924 "version": "2.0.0", 2788 5925 "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", ··· 2795 5932 "integrity": "sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==", 2796 5933 "license": "MIT" 2797 5934 }, 5935 + "node_modules/core-js": { 5936 + "version": "3.46.0", 5937 + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.46.0.tgz", 5938 + "integrity": "sha512-vDMm9B0xnqqZ8uSBpZ8sNtRtOdmfShrvT6h2TuQGLs0Is+cR0DYbj/KWP6ALVNbWPpqA/qPLoOuppJN07humpA==", 5939 + "hasInstallScript": true, 5940 + "license": "MIT", 5941 + "funding": { 5942 + "type": "opencollective", 5943 + "url": "https://opencollective.com/core-js" 5944 + } 5945 + }, 5946 + "node_modules/cosmiconfig": { 5947 + "version": "8.3.6", 5948 + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", 5949 + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", 5950 + "dev": true, 5951 + "license": "MIT", 5952 + "dependencies": { 5953 + "import-fresh": "^3.3.0", 5954 + "js-yaml": "^4.1.0", 5955 + "parse-json": "^5.2.0", 5956 + "path-type": "^4.0.0" 5957 + }, 5958 + "engines": { 5959 + "node": ">=14" 5960 + }, 5961 + "funding": { 5962 + "url": "https://github.com/sponsors/d-fischer" 5963 + }, 5964 + "peerDependencies": { 5965 + "typescript": ">=4.9.5" 5966 + }, 5967 + "peerDependenciesMeta": { 5968 + "typescript": { 5969 + "optional": true 5970 + } 5971 + } 5972 + }, 5973 + "node_modules/cross-spawn": { 5974 + "version": "7.0.6", 5975 + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", 5976 + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", 5977 + "dev": true, 5978 + "license": "MIT", 5979 + "peer": true, 5980 + "dependencies": { 5981 + "path-key": "^3.1.0", 5982 + "shebang-command": "^2.0.0", 5983 + "which": "^2.0.1" 5984 + }, 5985 + "engines": { 5986 + "node": ">= 8" 5987 + } 5988 + }, 2798 5989 "node_modules/cssstyle": { 2799 5990 "version": "4.6.0", 2800 5991 "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.6.0.tgz", ··· 2863 6054 "node": ">=18" 2864 6055 } 2865 6056 }, 6057 + "node_modules/data-view-buffer": { 6058 + "version": "1.0.2", 6059 + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", 6060 + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", 6061 + "dev": true, 6062 + "license": "MIT", 6063 + "dependencies": { 6064 + "call-bound": "^1.0.3", 6065 + "es-errors": "^1.3.0", 6066 + "is-data-view": "^1.0.2" 6067 + }, 6068 + "engines": { 6069 + "node": ">= 0.4" 6070 + }, 6071 + "funding": { 6072 + "url": "https://github.com/sponsors/ljharb" 6073 + } 6074 + }, 6075 + "node_modules/data-view-byte-length": { 6076 + "version": "1.0.2", 6077 + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", 6078 + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", 6079 + "dev": true, 6080 + "license": "MIT", 6081 + "dependencies": { 6082 + "call-bound": "^1.0.3", 6083 + "es-errors": "^1.3.0", 6084 + "is-data-view": "^1.0.2" 6085 + }, 6086 + "engines": { 6087 + "node": ">= 0.4" 6088 + }, 6089 + "funding": { 6090 + "url": "https://github.com/sponsors/inspect-js" 6091 + } 6092 + }, 6093 + "node_modules/data-view-byte-offset": { 6094 + "version": "1.0.1", 6095 + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", 6096 + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", 6097 + "dev": true, 6098 + "license": "MIT", 6099 + "dependencies": { 6100 + "call-bound": "^1.0.2", 6101 + "es-errors": "^1.3.0", 6102 + "is-data-view": "^1.0.1" 6103 + }, 6104 + "engines": { 6105 + "node": ">= 0.4" 6106 + }, 6107 + "funding": { 6108 + "url": "https://github.com/sponsors/ljharb" 6109 + } 6110 + }, 2866 6111 "node_modules/debug": { 2867 - "version": "4.4.1", 2868 - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", 2869 - "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", 6112 + "version": "4.4.3", 6113 + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", 6114 + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", 2870 6115 "license": "MIT", 2871 6116 "dependencies": { 2872 6117 "ms": "^2.1.3" ··· 2897 6142 "node": ">=6" 2898 6143 } 2899 6144 }, 6145 + "node_modules/deep-is": { 6146 + "version": "0.1.4", 6147 + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", 6148 + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", 6149 + "dev": true, 6150 + "license": "MIT", 6151 + "peer": true 6152 + }, 6153 + "node_modules/define-data-property": { 6154 + "version": "1.1.4", 6155 + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", 6156 + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", 6157 + "dev": true, 6158 + "license": "MIT", 6159 + "dependencies": { 6160 + "es-define-property": "^1.0.0", 6161 + "es-errors": "^1.3.0", 6162 + "gopd": "^1.0.1" 6163 + }, 6164 + "engines": { 6165 + "node": ">= 0.4" 6166 + }, 6167 + "funding": { 6168 + "url": "https://github.com/sponsors/ljharb" 6169 + } 6170 + }, 6171 + "node_modules/define-properties": { 6172 + "version": "1.2.1", 6173 + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", 6174 + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", 6175 + "dev": true, 6176 + "license": "MIT", 6177 + "dependencies": { 6178 + "define-data-property": "^1.0.1", 6179 + "has-property-descriptors": "^1.0.0", 6180 + "object-keys": "^1.1.1" 6181 + }, 6182 + "engines": { 6183 + "node": ">= 0.4" 6184 + }, 6185 + "funding": { 6186 + "url": "https://github.com/sponsors/ljharb" 6187 + } 6188 + }, 2900 6189 "node_modules/dequal": { 2901 6190 "version": "2.0.3", 2902 6191 "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", ··· 2915 6204 "engines": { 2916 6205 "node": ">=8" 2917 6206 } 6207 + }, 6208 + "node_modules/detect-node-es": { 6209 + "version": "1.1.0", 6210 + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", 6211 + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==" 2918 6212 }, 2919 6213 "node_modules/diff": { 2920 6214 "version": "8.0.2", ··· 2925 6219 "node": ">=0.3.1" 2926 6220 } 2927 6221 }, 6222 + "node_modules/doctrine": { 6223 + "version": "2.1.0", 6224 + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", 6225 + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", 6226 + "dev": true, 6227 + "license": "Apache-2.0", 6228 + "dependencies": { 6229 + "esutils": "^2.0.2" 6230 + }, 6231 + "engines": { 6232 + "node": ">=0.10.0" 6233 + } 6234 + }, 2928 6235 "node_modules/dom-accessibility-api": { 2929 6236 "version": "0.5.16", 2930 6237 "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", ··· 2932 6239 "dev": true, 2933 6240 "license": "MIT" 2934 6241 }, 6242 + "node_modules/dompurify": { 6243 + "version": "3.3.0", 6244 + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.0.tgz", 6245 + "integrity": "sha512-r+f6MYR1gGN1eJv0TVQbhA7if/U7P87cdPl3HN5rikqaBSBxLiCb/b9O+2eG0cxz0ghyU+mU1QkbsOwERMYlWQ==", 6246 + "license": "(MPL-2.0 OR Apache-2.0)", 6247 + "optionalDependencies": { 6248 + "@types/trusted-types": "^2.0.7" 6249 + } 6250 + }, 6251 + "node_modules/dot-case": { 6252 + "version": "3.0.4", 6253 + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", 6254 + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", 6255 + "dev": true, 6256 + "license": "MIT", 6257 + "dependencies": { 6258 + "no-case": "^3.0.4", 6259 + "tslib": "^2.0.3" 6260 + } 6261 + }, 6262 + "node_modules/dunder-proto": { 6263 + "version": "1.0.1", 6264 + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", 6265 + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", 6266 + "dev": true, 6267 + "license": "MIT", 6268 + "dependencies": { 6269 + "call-bind-apply-helpers": "^1.0.1", 6270 + "es-errors": "^1.3.0", 6271 + "gopd": "^1.2.0" 6272 + }, 6273 + "engines": { 6274 + "node": ">= 0.4" 6275 + } 6276 + }, 2935 6277 "node_modules/electron-to-chromium": { 2936 6278 "version": "1.5.211", 2937 6279 "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.211.tgz", ··· 2964 6306 "url": "https://github.com/fb55/entities?sponsor=1" 2965 6307 } 2966 6308 }, 6309 + "node_modules/error-ex": { 6310 + "version": "1.3.4", 6311 + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", 6312 + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", 6313 + "dev": true, 6314 + "license": "MIT", 6315 + "dependencies": { 6316 + "is-arrayish": "^0.2.1" 6317 + } 6318 + }, 6319 + "node_modules/es-abstract": { 6320 + "version": "1.24.0", 6321 + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", 6322 + "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", 6323 + "dev": true, 6324 + "license": "MIT", 6325 + "dependencies": { 6326 + "array-buffer-byte-length": "^1.0.2", 6327 + "arraybuffer.prototype.slice": "^1.0.4", 6328 + "available-typed-arrays": "^1.0.7", 6329 + "call-bind": "^1.0.8", 6330 + "call-bound": "^1.0.4", 6331 + "data-view-buffer": "^1.0.2", 6332 + "data-view-byte-length": "^1.0.2", 6333 + "data-view-byte-offset": "^1.0.1", 6334 + "es-define-property": "^1.0.1", 6335 + "es-errors": "^1.3.0", 6336 + "es-object-atoms": "^1.1.1", 6337 + "es-set-tostringtag": "^2.1.0", 6338 + "es-to-primitive": "^1.3.0", 6339 + "function.prototype.name": "^1.1.8", 6340 + "get-intrinsic": "^1.3.0", 6341 + "get-proto": "^1.0.1", 6342 + "get-symbol-description": "^1.1.0", 6343 + "globalthis": "^1.0.4", 6344 + "gopd": "^1.2.0", 6345 + "has-property-descriptors": "^1.0.2", 6346 + "has-proto": "^1.2.0", 6347 + "has-symbols": "^1.1.0", 6348 + "hasown": "^2.0.2", 6349 + "internal-slot": "^1.1.0", 6350 + "is-array-buffer": "^3.0.5", 6351 + "is-callable": "^1.2.7", 6352 + "is-data-view": "^1.0.2", 6353 + "is-negative-zero": "^2.0.3", 6354 + "is-regex": "^1.2.1", 6355 + "is-set": "^2.0.3", 6356 + "is-shared-array-buffer": "^1.0.4", 6357 + "is-string": "^1.1.1", 6358 + "is-typed-array": "^1.1.15", 6359 + "is-weakref": "^1.1.1", 6360 + "math-intrinsics": "^1.1.0", 6361 + "object-inspect": "^1.13.4", 6362 + "object-keys": "^1.1.1", 6363 + "object.assign": "^4.1.7", 6364 + "own-keys": "^1.0.1", 6365 + "regexp.prototype.flags": "^1.5.4", 6366 + "safe-array-concat": "^1.1.3", 6367 + "safe-push-apply": "^1.0.0", 6368 + "safe-regex-test": "^1.1.0", 6369 + "set-proto": "^1.0.0", 6370 + "stop-iteration-iterator": "^1.1.0", 6371 + "string.prototype.trim": "^1.2.10", 6372 + "string.prototype.trimend": "^1.0.9", 6373 + "string.prototype.trimstart": "^1.0.8", 6374 + "typed-array-buffer": "^1.0.3", 6375 + "typed-array-byte-length": "^1.0.3", 6376 + "typed-array-byte-offset": "^1.0.4", 6377 + "typed-array-length": "^1.0.7", 6378 + "unbox-primitive": "^1.1.0", 6379 + "which-typed-array": "^1.1.19" 6380 + }, 6381 + "engines": { 6382 + "node": ">= 0.4" 6383 + }, 6384 + "funding": { 6385 + "url": "https://github.com/sponsors/ljharb" 6386 + } 6387 + }, 6388 + "node_modules/es-define-property": { 6389 + "version": "1.0.1", 6390 + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", 6391 + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", 6392 + "dev": true, 6393 + "license": "MIT", 6394 + "engines": { 6395 + "node": ">= 0.4" 6396 + } 6397 + }, 6398 + "node_modules/es-errors": { 6399 + "version": "1.3.0", 6400 + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", 6401 + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", 6402 + "dev": true, 6403 + "license": "MIT", 6404 + "engines": { 6405 + "node": ">= 0.4" 6406 + } 6407 + }, 6408 + "node_modules/es-iterator-helpers": { 6409 + "version": "1.2.1", 6410 + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.1.tgz", 6411 + "integrity": "sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==", 6412 + "dev": true, 6413 + "license": "MIT", 6414 + "dependencies": { 6415 + "call-bind": "^1.0.8", 6416 + "call-bound": "^1.0.3", 6417 + "define-properties": "^1.2.1", 6418 + "es-abstract": "^1.23.6", 6419 + "es-errors": "^1.3.0", 6420 + "es-set-tostringtag": "^2.0.3", 6421 + "function-bind": "^1.1.2", 6422 + "get-intrinsic": "^1.2.6", 6423 + "globalthis": "^1.0.4", 6424 + "gopd": "^1.2.0", 6425 + "has-property-descriptors": "^1.0.2", 6426 + "has-proto": "^1.2.0", 6427 + "has-symbols": "^1.1.0", 6428 + "internal-slot": "^1.1.0", 6429 + "iterator.prototype": "^1.1.4", 6430 + "safe-array-concat": "^1.1.3" 6431 + }, 6432 + "engines": { 6433 + "node": ">= 0.4" 6434 + } 6435 + }, 2967 6436 "node_modules/es-module-lexer": { 2968 6437 "version": "1.7.0", 2969 6438 "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", ··· 2971 6440 "dev": true, 2972 6441 "license": "MIT" 2973 6442 }, 6443 + "node_modules/es-object-atoms": { 6444 + "version": "1.1.1", 6445 + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", 6446 + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", 6447 + "dev": true, 6448 + "license": "MIT", 6449 + "dependencies": { 6450 + "es-errors": "^1.3.0" 6451 + }, 6452 + "engines": { 6453 + "node": ">= 0.4" 6454 + } 6455 + }, 6456 + "node_modules/es-set-tostringtag": { 6457 + "version": "2.1.0", 6458 + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", 6459 + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", 6460 + "dev": true, 6461 + "license": "MIT", 6462 + "dependencies": { 6463 + "es-errors": "^1.3.0", 6464 + "get-intrinsic": "^1.2.6", 6465 + "has-tostringtag": "^1.0.2", 6466 + "hasown": "^2.0.2" 6467 + }, 6468 + "engines": { 6469 + "node": ">= 0.4" 6470 + } 6471 + }, 6472 + "node_modules/es-shim-unscopables": { 6473 + "version": "1.1.0", 6474 + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", 6475 + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", 6476 + "dev": true, 6477 + "license": "MIT", 6478 + "dependencies": { 6479 + "hasown": "^2.0.2" 6480 + }, 6481 + "engines": { 6482 + "node": ">= 0.4" 6483 + } 6484 + }, 6485 + "node_modules/es-to-primitive": { 6486 + "version": "1.3.0", 6487 + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", 6488 + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", 6489 + "dev": true, 6490 + "license": "MIT", 6491 + "dependencies": { 6492 + "is-callable": "^1.2.7", 6493 + "is-date-object": "^1.0.5", 6494 + "is-symbol": "^1.0.4" 6495 + }, 6496 + "engines": { 6497 + "node": ">= 0.4" 6498 + }, 6499 + "funding": { 6500 + "url": "https://github.com/sponsors/ljharb" 6501 + } 6502 + }, 2974 6503 "node_modules/esbuild": { 2975 6504 "version": "0.25.9", 2976 6505 "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz", ··· 3021 6550 "node": ">=6" 3022 6551 } 3023 6552 }, 6553 + "node_modules/escape-string-regexp": { 6554 + "version": "4.0.0", 6555 + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", 6556 + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", 6557 + "dev": true, 6558 + "license": "MIT", 6559 + "peer": true, 6560 + "engines": { 6561 + "node": ">=10" 6562 + }, 6563 + "funding": { 6564 + "url": "https://github.com/sponsors/sindresorhus" 6565 + } 6566 + }, 6567 + "node_modules/eslint": { 6568 + "version": "9.37.0", 6569 + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.37.0.tgz", 6570 + "integrity": "sha512-XyLmROnACWqSxiGYArdef1fItQd47weqB7iwtfr9JHwRrqIXZdcFMvvEcL9xHCmL0SNsOvF0c42lWyM1U5dgig==", 6571 + "dev": true, 6572 + "license": "MIT", 6573 + "peer": true, 6574 + "dependencies": { 6575 + "@eslint-community/eslint-utils": "^4.8.0", 6576 + "@eslint-community/regexpp": "^4.12.1", 6577 + "@eslint/config-array": "^0.21.0", 6578 + "@eslint/config-helpers": "^0.4.0", 6579 + "@eslint/core": "^0.16.0", 6580 + "@eslint/eslintrc": "^3.3.1", 6581 + "@eslint/js": "9.37.0", 6582 + "@eslint/plugin-kit": "^0.4.0", 6583 + "@humanfs/node": "^0.16.6", 6584 + "@humanwhocodes/module-importer": "^1.0.1", 6585 + "@humanwhocodes/retry": "^0.4.2", 6586 + "@types/estree": "^1.0.6", 6587 + "@types/json-schema": "^7.0.15", 6588 + "ajv": "^6.12.4", 6589 + "chalk": "^4.0.0", 6590 + "cross-spawn": "^7.0.6", 6591 + "debug": "^4.3.2", 6592 + "escape-string-regexp": "^4.0.0", 6593 + "eslint-scope": "^8.4.0", 6594 + "eslint-visitor-keys": "^4.2.1", 6595 + "espree": "^10.4.0", 6596 + "esquery": "^1.5.0", 6597 + "esutils": "^2.0.2", 6598 + "fast-deep-equal": "^3.1.3", 6599 + "file-entry-cache": "^8.0.0", 6600 + "find-up": "^5.0.0", 6601 + "glob-parent": "^6.0.2", 6602 + "ignore": "^5.2.0", 6603 + "imurmurhash": "^0.1.4", 6604 + "is-glob": "^4.0.0", 6605 + "json-stable-stringify-without-jsonify": "^1.0.1", 6606 + "lodash.merge": "^4.6.2", 6607 + "minimatch": "^3.1.2", 6608 + "natural-compare": "^1.4.0", 6609 + "optionator": "^0.9.3" 6610 + }, 6611 + "bin": { 6612 + "eslint": "bin/eslint.js" 6613 + }, 6614 + "engines": { 6615 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 6616 + }, 6617 + "funding": { 6618 + "url": "https://eslint.org/donate" 6619 + }, 6620 + "peerDependencies": { 6621 + "jiti": "*" 6622 + }, 6623 + "peerDependenciesMeta": { 6624 + "jiti": { 6625 + "optional": true 6626 + } 6627 + } 6628 + }, 6629 + "node_modules/eslint-plugin-react": { 6630 + "version": "7.37.5", 6631 + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", 6632 + "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", 6633 + "dev": true, 6634 + "license": "MIT", 6635 + "dependencies": { 6636 + "array-includes": "^3.1.8", 6637 + "array.prototype.findlast": "^1.2.5", 6638 + "array.prototype.flatmap": "^1.3.3", 6639 + "array.prototype.tosorted": "^1.1.4", 6640 + "doctrine": "^2.1.0", 6641 + "es-iterator-helpers": "^1.2.1", 6642 + "estraverse": "^5.3.0", 6643 + "hasown": "^2.0.2", 6644 + "jsx-ast-utils": "^2.4.1 || ^3.0.0", 6645 + "minimatch": "^3.1.2", 6646 + "object.entries": "^1.1.9", 6647 + "object.fromentries": "^2.0.8", 6648 + "object.values": "^1.2.1", 6649 + "prop-types": "^15.8.1", 6650 + "resolve": "^2.0.0-next.5", 6651 + "semver": "^6.3.1", 6652 + "string.prototype.matchall": "^4.0.12", 6653 + "string.prototype.repeat": "^1.0.0" 6654 + }, 6655 + "engines": { 6656 + "node": ">=4" 6657 + }, 6658 + "peerDependencies": { 6659 + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" 6660 + } 6661 + }, 6662 + "node_modules/eslint-plugin-react-dom": { 6663 + "version": "2.2.1", 6664 + "resolved": "https://registry.npmjs.org/eslint-plugin-react-dom/-/eslint-plugin-react-dom-2.2.1.tgz", 6665 + "integrity": "sha512-g6B4yTLHWhgqu3mN0kUJvrQp285uFMQYXzWVAIBqziV6n93sgPH8Eb8ht3gTzRUfA9Rt3JQr8QaxBxpfSkp67w==", 6666 + "dev": true, 6667 + "license": "MIT", 6668 + "dependencies": { 6669 + "@eslint-react/ast": "2.2.1", 6670 + "@eslint-react/core": "2.2.1", 6671 + "@eslint-react/eff": "2.2.1", 6672 + "@eslint-react/shared": "2.2.1", 6673 + "@eslint-react/var": "2.2.1", 6674 + "@typescript-eslint/scope-manager": "^8.46.0", 6675 + "@typescript-eslint/types": "^8.46.0", 6676 + "@typescript-eslint/utils": "^8.46.0", 6677 + "compare-versions": "^6.1.1", 6678 + "string-ts": "^2.2.1", 6679 + "ts-pattern": "^5.8.0" 6680 + }, 6681 + "engines": { 6682 + "node": ">=20.19.0" 6683 + }, 6684 + "peerDependencies": { 6685 + "eslint": "^9.37.0", 6686 + "typescript": "^5.9.3" 6687 + } 6688 + }, 6689 + "node_modules/eslint-plugin-react-hooks": { 6690 + "version": "7.0.0", 6691 + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.0.0.tgz", 6692 + "integrity": "sha512-fNXaOwvKwq2+pXiRpXc825Vd63+KM4DLL40Rtlycb8m7fYpp6efrTp1sa6ZbP/Ap58K2bEKFXRmhURE+CJAQWw==", 6693 + "dev": true, 6694 + "license": "MIT", 6695 + "dependencies": { 6696 + "@babel/core": "^7.24.4", 6697 + "@babel/parser": "^7.24.4", 6698 + "hermes-parser": "^0.25.1", 6699 + "zod": "^3.22.4 || ^4.0.0", 6700 + "zod-validation-error": "^3.0.3 || ^4.0.0" 6701 + }, 6702 + "engines": { 6703 + "node": ">=18" 6704 + }, 6705 + "peerDependencies": { 6706 + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" 6707 + } 6708 + }, 6709 + "node_modules/eslint-plugin-react-hooks-extra": { 6710 + "version": "2.2.1", 6711 + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks-extra/-/eslint-plugin-react-hooks-extra-2.2.1.tgz", 6712 + "integrity": "sha512-MfUbjKIEhF0qEpfXIPgcmmteCx5h9lMuuMGLaau4KmOKh3vewj6DW/JubVuhQ+7eaHqpuCz8/0uBH0k2lfavjg==", 6713 + "dev": true, 6714 + "license": "MIT", 6715 + "dependencies": { 6716 + "@eslint-react/ast": "2.2.1", 6717 + "@eslint-react/core": "2.2.1", 6718 + "@eslint-react/eff": "2.2.1", 6719 + "@eslint-react/shared": "2.2.1", 6720 + "@eslint-react/var": "2.2.1", 6721 + "@typescript-eslint/scope-manager": "^8.46.0", 6722 + "@typescript-eslint/type-utils": "^8.46.0", 6723 + "@typescript-eslint/types": "^8.46.0", 6724 + "@typescript-eslint/utils": "^8.46.0", 6725 + "string-ts": "^2.2.1", 6726 + "ts-pattern": "^5.8.0" 6727 + }, 6728 + "engines": { 6729 + "node": ">=20.0.0" 6730 + }, 6731 + "peerDependencies": { 6732 + "eslint": "^9.37.0", 6733 + "typescript": "^5.9.3" 6734 + } 6735 + }, 6736 + "node_modules/eslint-plugin-react-naming-convention": { 6737 + "version": "2.2.1", 6738 + "resolved": "https://registry.npmjs.org/eslint-plugin-react-naming-convention/-/eslint-plugin-react-naming-convention-2.2.1.tgz", 6739 + "integrity": "sha512-yjNfzPmYAJDFp7yZ4BkmwBRmK3mAGYGXFDyb5Ws2vZBj6R8BKbh5Ao/Chmemo/LmW7a2IoySICuBp6wxuBC9Yg==", 6740 + "dev": true, 6741 + "license": "MIT", 6742 + "dependencies": { 6743 + "@eslint-react/ast": "2.2.1", 6744 + "@eslint-react/core": "2.2.1", 6745 + "@eslint-react/eff": "2.2.1", 6746 + "@eslint-react/shared": "2.2.1", 6747 + "@eslint-react/var": "2.2.1", 6748 + "@typescript-eslint/scope-manager": "^8.46.0", 6749 + "@typescript-eslint/type-utils": "^8.46.0", 6750 + "@typescript-eslint/types": "^8.46.0", 6751 + "@typescript-eslint/utils": "^8.46.0", 6752 + "string-ts": "^2.2.1", 6753 + "ts-pattern": "^5.8.0" 6754 + }, 6755 + "engines": { 6756 + "node": ">=20.19.0" 6757 + }, 6758 + "peerDependencies": { 6759 + "eslint": "^9.37.0", 6760 + "typescript": "^5.9.3" 6761 + } 6762 + }, 6763 + "node_modules/eslint-plugin-react-web-api": { 6764 + "version": "2.2.1", 6765 + "resolved": "https://registry.npmjs.org/eslint-plugin-react-web-api/-/eslint-plugin-react-web-api-2.2.1.tgz", 6766 + "integrity": "sha512-JGRufRDJ8rmckQ82R+3kKhl9ybVeCjRt8fo8/IvxCQJukyyL4Y5b+mOwnPTRDJLQMeDzql4VDeeLegcjweTmAw==", 6767 + "dev": true, 6768 + "license": "MIT", 6769 + "dependencies": { 6770 + "@eslint-react/ast": "2.2.1", 6771 + "@eslint-react/core": "2.2.1", 6772 + "@eslint-react/eff": "2.2.1", 6773 + "@eslint-react/shared": "2.2.1", 6774 + "@eslint-react/var": "2.2.1", 6775 + "@typescript-eslint/scope-manager": "^8.46.0", 6776 + "@typescript-eslint/types": "^8.46.0", 6777 + "@typescript-eslint/utils": "^8.46.0", 6778 + "string-ts": "^2.2.1", 6779 + "ts-pattern": "^5.8.0" 6780 + }, 6781 + "engines": { 6782 + "node": ">=20.19.0" 6783 + }, 6784 + "peerDependencies": { 6785 + "eslint": "^9.37.0", 6786 + "typescript": "^5.9.3" 6787 + } 6788 + }, 6789 + "node_modules/eslint-plugin-react-x": { 6790 + "version": "2.2.1", 6791 + "resolved": "https://registry.npmjs.org/eslint-plugin-react-x/-/eslint-plugin-react-x-2.2.1.tgz", 6792 + "integrity": "sha512-Bz5MoLgimALqiJ5O7/KQ/JhZ7AC24qILvA7KHsjT5n0XEQKrktGKGZEm4AKiKsTmboAitpVbHDB9kGpwXIrFXw==", 6793 + "dev": true, 6794 + "license": "MIT", 6795 + "dependencies": { 6796 + "@eslint-react/ast": "2.2.1", 6797 + "@eslint-react/core": "2.2.1", 6798 + "@eslint-react/eff": "2.2.1", 6799 + "@eslint-react/shared": "2.2.1", 6800 + "@eslint-react/var": "2.2.1", 6801 + "@typescript-eslint/scope-manager": "^8.46.0", 6802 + "@typescript-eslint/type-utils": "^8.46.0", 6803 + "@typescript-eslint/types": "^8.46.0", 6804 + "@typescript-eslint/utils": "^8.46.0", 6805 + "compare-versions": "^6.1.1", 6806 + "is-immutable-type": "^5.0.1", 6807 + "string-ts": "^2.2.1", 6808 + "ts-api-utils": "^2.1.0", 6809 + "ts-pattern": "^5.8.0" 6810 + }, 6811 + "engines": { 6812 + "node": ">=20.19.0" 6813 + }, 6814 + "peerDependencies": { 6815 + "eslint": "^9.37.0", 6816 + "typescript": "^5.9.3" 6817 + } 6818 + }, 6819 + "node_modules/eslint-plugin-simple-import-sort": { 6820 + "version": "12.1.1", 6821 + "resolved": "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-12.1.1.tgz", 6822 + "integrity": "sha512-6nuzu4xwQtE3332Uz0to+TxDQYRLTKRESSc2hefVT48Zc8JthmN23Gx9lnYhu0FtkRSL1oxny3kJ2aveVhmOVA==", 6823 + "dev": true, 6824 + "license": "MIT", 6825 + "peerDependencies": { 6826 + "eslint": ">=5.0.0" 6827 + } 6828 + }, 6829 + "node_modules/eslint-plugin-unused-imports": { 6830 + "version": "4.2.0", 6831 + "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-4.2.0.tgz", 6832 + "integrity": "sha512-hLbJ2/wnjKq4kGA9AUaExVFIbNzyxYdVo49QZmKCnhk5pc9wcYRbfgLHvWJ8tnsdcseGhoUAddm9gn/lt+d74w==", 6833 + "dev": true, 6834 + "license": "MIT", 6835 + "peerDependencies": { 6836 + "@typescript-eslint/eslint-plugin": "^8.0.0-0 || ^7.0.0 || ^6.0.0 || ^5.0.0", 6837 + "eslint": "^9.0.0 || ^8.0.0" 6838 + }, 6839 + "peerDependenciesMeta": { 6840 + "@typescript-eslint/eslint-plugin": { 6841 + "optional": true 6842 + } 6843 + } 6844 + }, 6845 + "node_modules/eslint-scope": { 6846 + "version": "8.4.0", 6847 + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", 6848 + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", 6849 + "dev": true, 6850 + "license": "BSD-2-Clause", 6851 + "peer": true, 6852 + "dependencies": { 6853 + "esrecurse": "^4.3.0", 6854 + "estraverse": "^5.2.0" 6855 + }, 6856 + "engines": { 6857 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 6858 + }, 6859 + "funding": { 6860 + "url": "https://opencollective.com/eslint" 6861 + } 6862 + }, 6863 + "node_modules/eslint-visitor-keys": { 6864 + "version": "4.2.1", 6865 + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", 6866 + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", 6867 + "dev": true, 6868 + "license": "Apache-2.0", 6869 + "engines": { 6870 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 6871 + }, 6872 + "funding": { 6873 + "url": "https://opencollective.com/eslint" 6874 + } 6875 + }, 6876 + "node_modules/eslint/node_modules/glob-parent": { 6877 + "version": "6.0.2", 6878 + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", 6879 + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", 6880 + "dev": true, 6881 + "license": "ISC", 6882 + "peer": true, 6883 + "dependencies": { 6884 + "is-glob": "^4.0.3" 6885 + }, 6886 + "engines": { 6887 + "node": ">=10.13.0" 6888 + } 6889 + }, 6890 + "node_modules/espree": { 6891 + "version": "10.4.0", 6892 + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", 6893 + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", 6894 + "dev": true, 6895 + "license": "BSD-2-Clause", 6896 + "peer": true, 6897 + "dependencies": { 6898 + "acorn": "^8.15.0", 6899 + "acorn-jsx": "^5.3.2", 6900 + "eslint-visitor-keys": "^4.2.1" 6901 + }, 6902 + "engines": { 6903 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 6904 + }, 6905 + "funding": { 6906 + "url": "https://opencollective.com/eslint" 6907 + } 6908 + }, 3024 6909 "node_modules/esprima": { 3025 6910 "version": "4.0.1", 3026 6911 "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", ··· 3034 6919 "node": ">=4" 3035 6920 } 3036 6921 }, 6922 + "node_modules/esquery": { 6923 + "version": "1.6.0", 6924 + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", 6925 + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", 6926 + "dev": true, 6927 + "license": "BSD-3-Clause", 6928 + "peer": true, 6929 + "dependencies": { 6930 + "estraverse": "^5.1.0" 6931 + }, 6932 + "engines": { 6933 + "node": ">=0.10" 6934 + } 6935 + }, 6936 + "node_modules/esrecurse": { 6937 + "version": "4.3.0", 6938 + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", 6939 + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", 6940 + "dev": true, 6941 + "license": "BSD-2-Clause", 6942 + "peer": true, 6943 + "dependencies": { 6944 + "estraverse": "^5.2.0" 6945 + }, 6946 + "engines": { 6947 + "node": ">=4.0" 6948 + } 6949 + }, 6950 + "node_modules/estraverse": { 6951 + "version": "5.3.0", 6952 + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", 6953 + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", 6954 + "dev": true, 6955 + "license": "BSD-2-Clause", 6956 + "engines": { 6957 + "node": ">=4.0" 6958 + } 6959 + }, 3037 6960 "node_modules/estree-walker": { 3038 6961 "version": "3.0.3", 3039 6962 "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", ··· 3044 6967 "@types/estree": "^1.0.0" 3045 6968 } 3046 6969 }, 6970 + "node_modules/esutils": { 6971 + "version": "2.0.3", 6972 + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", 6973 + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", 6974 + "dev": true, 6975 + "license": "BSD-2-Clause", 6976 + "engines": { 6977 + "node": ">=0.10.0" 6978 + } 6979 + }, 6980 + "node_modules/eventemitter3": { 6981 + "version": "5.0.1", 6982 + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", 6983 + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", 6984 + "license": "MIT" 6985 + }, 3047 6986 "node_modules/expect-type": { 3048 6987 "version": "1.2.2", 3049 6988 "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz", ··· 3054 6993 "node": ">=12.0.0" 3055 6994 } 3056 6995 }, 6996 + "node_modules/exsolve": { 6997 + "version": "1.0.7", 6998 + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.7.tgz", 6999 + "integrity": "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==", 7000 + "dev": true, 7001 + "license": "MIT" 7002 + }, 3057 7003 "node_modules/fast-deep-equal": { 3058 7004 "version": "3.1.3", 3059 7005 "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", 3060 7006 "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", 3061 7007 "license": "MIT" 3062 7008 }, 7009 + "node_modules/fast-glob": { 7010 + "version": "3.3.3", 7011 + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", 7012 + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", 7013 + "dev": true, 7014 + "license": "MIT", 7015 + "dependencies": { 7016 + "@nodelib/fs.stat": "^2.0.2", 7017 + "@nodelib/fs.walk": "^1.2.3", 7018 + "glob-parent": "^5.1.2", 7019 + "merge2": "^1.3.0", 7020 + "micromatch": "^4.0.8" 7021 + }, 7022 + "engines": { 7023 + "node": ">=8.6.0" 7024 + } 7025 + }, 7026 + "node_modules/fast-json-stable-stringify": { 7027 + "version": "2.1.0", 7028 + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", 7029 + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", 7030 + "dev": true, 7031 + "license": "MIT", 7032 + "peer": true 7033 + }, 7034 + "node_modules/fast-levenshtein": { 7035 + "version": "2.0.6", 7036 + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", 7037 + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", 7038 + "dev": true, 7039 + "license": "MIT", 7040 + "peer": true 7041 + }, 7042 + "node_modules/fastq": { 7043 + "version": "1.19.1", 7044 + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", 7045 + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", 7046 + "dev": true, 7047 + "license": "ISC", 7048 + "dependencies": { 7049 + "reusify": "^1.0.4" 7050 + } 7051 + }, 7052 + "node_modules/file-entry-cache": { 7053 + "version": "8.0.0", 7054 + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", 7055 + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", 7056 + "dev": true, 7057 + "license": "MIT", 7058 + "peer": true, 7059 + "dependencies": { 7060 + "flat-cache": "^4.0.0" 7061 + }, 7062 + "engines": { 7063 + "node": ">=16.0.0" 7064 + } 7065 + }, 3063 7066 "node_modules/fill-range": { 3064 7067 "version": "7.1.1", 3065 7068 "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", ··· 3072 7075 "node": ">=8" 3073 7076 } 3074 7077 }, 7078 + "node_modules/find-up": { 7079 + "version": "5.0.0", 7080 + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", 7081 + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", 7082 + "dev": true, 7083 + "license": "MIT", 7084 + "peer": true, 7085 + "dependencies": { 7086 + "locate-path": "^6.0.0", 7087 + "path-exists": "^4.0.0" 7088 + }, 7089 + "engines": { 7090 + "node": ">=10" 7091 + }, 7092 + "funding": { 7093 + "url": "https://github.com/sponsors/sindresorhus" 7094 + } 7095 + }, 7096 + "node_modules/flat-cache": { 7097 + "version": "4.0.1", 7098 + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", 7099 + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", 7100 + "dev": true, 7101 + "license": "MIT", 7102 + "peer": true, 7103 + "dependencies": { 7104 + "flatted": "^3.2.9", 7105 + "keyv": "^4.5.4" 7106 + }, 7107 + "engines": { 7108 + "node": ">=16" 7109 + } 7110 + }, 7111 + "node_modules/flatted": { 7112 + "version": "3.3.3", 7113 + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", 7114 + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", 7115 + "dev": true, 7116 + "license": "ISC", 7117 + "peer": true 7118 + }, 7119 + "node_modules/for-each": { 7120 + "version": "0.3.5", 7121 + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", 7122 + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", 7123 + "dev": true, 7124 + "license": "MIT", 7125 + "dependencies": { 7126 + "is-callable": "^1.2.7" 7127 + }, 7128 + "engines": { 7129 + "node": ">= 0.4" 7130 + }, 7131 + "funding": { 7132 + "url": "https://github.com/sponsors/ljharb" 7133 + } 7134 + }, 3075 7135 "node_modules/fsevents": { 3076 7136 "version": "2.3.3", 3077 7137 "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", ··· 3086 7146 "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 3087 7147 } 3088 7148 }, 7149 + "node_modules/function-bind": { 7150 + "version": "1.1.2", 7151 + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", 7152 + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", 7153 + "dev": true, 7154 + "license": "MIT", 7155 + "funding": { 7156 + "url": "https://github.com/sponsors/ljharb" 7157 + } 7158 + }, 7159 + "node_modules/function.prototype.name": { 7160 + "version": "1.1.8", 7161 + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", 7162 + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", 7163 + "dev": true, 7164 + "license": "MIT", 7165 + "dependencies": { 7166 + "call-bind": "^1.0.8", 7167 + "call-bound": "^1.0.3", 7168 + "define-properties": "^1.2.1", 7169 + "functions-have-names": "^1.2.3", 7170 + "hasown": "^2.0.2", 7171 + "is-callable": "^1.2.7" 7172 + }, 7173 + "engines": { 7174 + "node": ">= 0.4" 7175 + }, 7176 + "funding": { 7177 + "url": "https://github.com/sponsors/ljharb" 7178 + } 7179 + }, 7180 + "node_modules/functions-have-names": { 7181 + "version": "1.2.3", 7182 + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", 7183 + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", 7184 + "dev": true, 7185 + "license": "MIT", 7186 + "funding": { 7187 + "url": "https://github.com/sponsors/ljharb" 7188 + } 7189 + }, 7190 + "node_modules/generator-function": { 7191 + "version": "2.0.1", 7192 + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", 7193 + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", 7194 + "dev": true, 7195 + "license": "MIT", 7196 + "engines": { 7197 + "node": ">= 0.4" 7198 + } 7199 + }, 3089 7200 "node_modules/gensync": { 3090 7201 "version": "1.0.0-beta.2", 3091 7202 "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", ··· 3095 7206 "node": ">=6.9.0" 3096 7207 } 3097 7208 }, 7209 + "node_modules/get-intrinsic": { 7210 + "version": "1.3.0", 7211 + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", 7212 + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", 7213 + "dev": true, 7214 + "license": "MIT", 7215 + "dependencies": { 7216 + "call-bind-apply-helpers": "^1.0.2", 7217 + "es-define-property": "^1.0.1", 7218 + "es-errors": "^1.3.0", 7219 + "es-object-atoms": "^1.1.1", 7220 + "function-bind": "^1.1.2", 7221 + "get-proto": "^1.0.1", 7222 + "gopd": "^1.2.0", 7223 + "has-symbols": "^1.1.0", 7224 + "hasown": "^2.0.2", 7225 + "math-intrinsics": "^1.1.0" 7226 + }, 7227 + "engines": { 7228 + "node": ">= 0.4" 7229 + }, 7230 + "funding": { 7231 + "url": "https://github.com/sponsors/ljharb" 7232 + } 7233 + }, 7234 + "node_modules/get-nonce": { 7235 + "version": "1.0.1", 7236 + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", 7237 + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", 7238 + "engines": { 7239 + "node": ">=6" 7240 + } 7241 + }, 7242 + "node_modules/get-proto": { 7243 + "version": "1.0.1", 7244 + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", 7245 + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", 7246 + "dev": true, 7247 + "license": "MIT", 7248 + "dependencies": { 7249 + "dunder-proto": "^1.0.1", 7250 + "es-object-atoms": "^1.0.0" 7251 + }, 7252 + "engines": { 7253 + "node": ">= 0.4" 7254 + } 7255 + }, 7256 + "node_modules/get-symbol-description": { 7257 + "version": "1.1.0", 7258 + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", 7259 + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", 7260 + "dev": true, 7261 + "license": "MIT", 7262 + "dependencies": { 7263 + "call-bound": "^1.0.3", 7264 + "es-errors": "^1.3.0", 7265 + "get-intrinsic": "^1.2.6" 7266 + }, 7267 + "engines": { 7268 + "node": ">= 0.4" 7269 + }, 7270 + "funding": { 7271 + "url": "https://github.com/sponsors/ljharb" 7272 + } 7273 + }, 3098 7274 "node_modules/get-tsconfig": { 3099 7275 "version": "4.10.1", 3100 7276 "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz", ··· 3119 7295 "node": ">= 6" 3120 7296 } 3121 7297 }, 7298 + "node_modules/globals": { 7299 + "version": "14.0.0", 7300 + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", 7301 + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", 7302 + "dev": true, 7303 + "license": "MIT", 7304 + "peer": true, 7305 + "engines": { 7306 + "node": ">=18" 7307 + }, 7308 + "funding": { 7309 + "url": "https://github.com/sponsors/sindresorhus" 7310 + } 7311 + }, 7312 + "node_modules/globalthis": { 7313 + "version": "1.0.4", 7314 + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", 7315 + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", 7316 + "dev": true, 7317 + "license": "MIT", 7318 + "dependencies": { 7319 + "define-properties": "^1.2.1", 7320 + "gopd": "^1.0.1" 7321 + }, 7322 + "engines": { 7323 + "node": ">= 0.4" 7324 + }, 7325 + "funding": { 7326 + "url": "https://github.com/sponsors/ljharb" 7327 + } 7328 + }, 3122 7329 "node_modules/goober": { 3123 7330 "version": "2.1.16", 3124 7331 "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.16.tgz", ··· 3128 7335 "csstype": "^3.0.10" 3129 7336 } 3130 7337 }, 7338 + "node_modules/gopd": { 7339 + "version": "1.2.0", 7340 + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", 7341 + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", 7342 + "dev": true, 7343 + "license": "MIT", 7344 + "engines": { 7345 + "node": ">= 0.4" 7346 + }, 7347 + "funding": { 7348 + "url": "https://github.com/sponsors/ljharb" 7349 + } 7350 + }, 3131 7351 "node_modules/graceful-fs": { 3132 7352 "version": "4.2.11", 3133 7353 "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", ··· 3140 7360 "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", 3141 7361 "license": "MIT" 3142 7362 }, 7363 + "node_modules/has-bigints": { 7364 + "version": "1.1.0", 7365 + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", 7366 + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", 7367 + "dev": true, 7368 + "license": "MIT", 7369 + "engines": { 7370 + "node": ">= 0.4" 7371 + }, 7372 + "funding": { 7373 + "url": "https://github.com/sponsors/ljharb" 7374 + } 7375 + }, 7376 + "node_modules/has-flag": { 7377 + "version": "4.0.0", 7378 + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 7379 + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 7380 + "dev": true, 7381 + "license": "MIT", 7382 + "peer": true, 7383 + "engines": { 7384 + "node": ">=8" 7385 + } 7386 + }, 7387 + "node_modules/has-property-descriptors": { 7388 + "version": "1.0.2", 7389 + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", 7390 + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", 7391 + "dev": true, 7392 + "license": "MIT", 7393 + "dependencies": { 7394 + "es-define-property": "^1.0.0" 7395 + }, 7396 + "funding": { 7397 + "url": "https://github.com/sponsors/ljharb" 7398 + } 7399 + }, 7400 + "node_modules/has-proto": { 7401 + "version": "1.2.0", 7402 + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", 7403 + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", 7404 + "dev": true, 7405 + "license": "MIT", 7406 + "dependencies": { 7407 + "dunder-proto": "^1.0.0" 7408 + }, 7409 + "engines": { 7410 + "node": ">= 0.4" 7411 + }, 7412 + "funding": { 7413 + "url": "https://github.com/sponsors/ljharb" 7414 + } 7415 + }, 7416 + "node_modules/has-symbols": { 7417 + "version": "1.1.0", 7418 + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", 7419 + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", 7420 + "dev": true, 7421 + "license": "MIT", 7422 + "engines": { 7423 + "node": ">= 0.4" 7424 + }, 7425 + "funding": { 7426 + "url": "https://github.com/sponsors/ljharb" 7427 + } 7428 + }, 7429 + "node_modules/has-tostringtag": { 7430 + "version": "1.0.2", 7431 + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", 7432 + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", 7433 + "dev": true, 7434 + "license": "MIT", 7435 + "dependencies": { 7436 + "has-symbols": "^1.0.3" 7437 + }, 7438 + "engines": { 7439 + "node": ">= 0.4" 7440 + }, 7441 + "funding": { 7442 + "url": "https://github.com/sponsors/ljharb" 7443 + } 7444 + }, 7445 + "node_modules/hasown": { 7446 + "version": "2.0.2", 7447 + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", 7448 + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", 7449 + "dev": true, 7450 + "license": "MIT", 7451 + "dependencies": { 7452 + "function-bind": "^1.1.2" 7453 + }, 7454 + "engines": { 7455 + "node": ">= 0.4" 7456 + } 7457 + }, 7458 + "node_modules/hermes-estree": { 7459 + "version": "0.25.1", 7460 + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", 7461 + "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", 7462 + "dev": true, 7463 + "license": "MIT" 7464 + }, 7465 + "node_modules/hermes-parser": { 7466 + "version": "0.25.1", 7467 + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", 7468 + "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", 7469 + "dev": true, 7470 + "license": "MIT", 7471 + "dependencies": { 7472 + "hermes-estree": "0.25.1" 7473 + } 7474 + }, 3143 7475 "node_modules/hls-video-element": { 3144 7476 "version": "1.5.7", 3145 7477 "resolved": "https://registry.npmjs.org/hls-video-element/-/hls-video-element-1.5.7.tgz", ··· 3214 7546 "node": ">= 14" 3215 7547 } 3216 7548 }, 7549 + "node_modules/i": { 7550 + "version": "0.3.7", 7551 + "resolved": "https://registry.npmjs.org/i/-/i-0.3.7.tgz", 7552 + "integrity": "sha512-FYz4wlXgkQwIPqhzC5TdNMLSE5+GS1IIDJZY/1ZiEPCT2S3COUVZeT5OW4BmW4r5LHLQuOosSwsvnroG9GR59Q==", 7553 + "engines": { 7554 + "node": ">=0.4" 7555 + } 7556 + }, 7557 + "node_modules/iconify-icon": { 7558 + "version": "3.0.1", 7559 + "resolved": "https://registry.npmjs.org/iconify-icon/-/iconify-icon-3.0.1.tgz", 7560 + "integrity": "sha512-M3/kH3C+e/ufhmQuOSYSb1Ri1ImJ+ZEQYcVRMKnlSc8Nrdoy+iY9YvFnplX8t/3aCRuo5wN4RVPtCSHGnbt8dg==", 7561 + "dev": true, 7562 + "license": "MIT", 7563 + "dependencies": { 7564 + "@iconify/types": "^2.0.0" 7565 + }, 7566 + "funding": { 7567 + "url": "https://github.com/sponsors/cyberalien" 7568 + } 7569 + }, 3217 7570 "node_modules/iconv-lite": { 3218 7571 "version": "0.6.3", 3219 7572 "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", ··· 3233 7586 "integrity": "sha512-yjD9nARJ/jb1g+CvD0tlhUHOrJ9Sy0P8T9MF3YaLlHnSRpwPfpTX0XIvpmw3gAJUmEu3FiICLBDPXVwyEvrleg==", 3234 7587 "license": "Apache-2.0" 3235 7588 }, 7589 + "node_modules/ignore": { 7590 + "version": "5.3.2", 7591 + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", 7592 + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", 7593 + "dev": true, 7594 + "license": "MIT", 7595 + "peer": true, 7596 + "engines": { 7597 + "node": ">= 4" 7598 + } 7599 + }, 3236 7600 "node_modules/immediate": { 3237 7601 "version": "3.0.6", 3238 7602 "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", 3239 7603 "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", 3240 7604 "license": "MIT" 3241 7605 }, 7606 + "node_modules/import-fresh": { 7607 + "version": "3.3.1", 7608 + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", 7609 + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", 7610 + "dev": true, 7611 + "license": "MIT", 7612 + "dependencies": { 7613 + "parent-module": "^1.0.0", 7614 + "resolve-from": "^4.0.0" 7615 + }, 7616 + "engines": { 7617 + "node": ">=6" 7618 + }, 7619 + "funding": { 7620 + "url": "https://github.com/sponsors/sindresorhus" 7621 + } 7622 + }, 3242 7623 "node_modules/imsc": { 3243 7624 "version": "1.1.5", 3244 7625 "resolved": "https://registry.npmjs.org/imsc/-/imsc-1.1.5.tgz", ··· 3248 7629 "sax": "1.2.1" 3249 7630 } 3250 7631 }, 7632 + "node_modules/imurmurhash": { 7633 + "version": "0.1.4", 7634 + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", 7635 + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", 7636 + "dev": true, 7637 + "license": "MIT", 7638 + "peer": true, 7639 + "engines": { 7640 + "node": ">=0.8.19" 7641 + } 7642 + }, 7643 + "node_modules/internal-slot": { 7644 + "version": "1.1.0", 7645 + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", 7646 + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", 7647 + "dev": true, 7648 + "license": "MIT", 7649 + "dependencies": { 7650 + "es-errors": "^1.3.0", 7651 + "hasown": "^2.0.2", 7652 + "side-channel": "^1.1.0" 7653 + }, 7654 + "engines": { 7655 + "node": ">= 0.4" 7656 + } 7657 + }, 3251 7658 "node_modules/is-alphabetical": { 3252 7659 "version": "2.0.1", 3253 7660 "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", ··· 3272 7679 "url": "https://github.com/sponsors/wooorm" 3273 7680 } 3274 7681 }, 7682 + "node_modules/is-array-buffer": { 7683 + "version": "3.0.5", 7684 + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", 7685 + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", 7686 + "dev": true, 7687 + "license": "MIT", 7688 + "dependencies": { 7689 + "call-bind": "^1.0.8", 7690 + "call-bound": "^1.0.3", 7691 + "get-intrinsic": "^1.2.6" 7692 + }, 7693 + "engines": { 7694 + "node": ">= 0.4" 7695 + }, 7696 + "funding": { 7697 + "url": "https://github.com/sponsors/ljharb" 7698 + } 7699 + }, 7700 + "node_modules/is-arrayish": { 7701 + "version": "0.2.1", 7702 + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", 7703 + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", 7704 + "dev": true, 7705 + "license": "MIT" 7706 + }, 7707 + "node_modules/is-async-function": { 7708 + "version": "2.1.1", 7709 + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", 7710 + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", 7711 + "dev": true, 7712 + "license": "MIT", 7713 + "dependencies": { 7714 + "async-function": "^1.0.0", 7715 + "call-bound": "^1.0.3", 7716 + "get-proto": "^1.0.1", 7717 + "has-tostringtag": "^1.0.2", 7718 + "safe-regex-test": "^1.1.0" 7719 + }, 7720 + "engines": { 7721 + "node": ">= 0.4" 7722 + }, 7723 + "funding": { 7724 + "url": "https://github.com/sponsors/ljharb" 7725 + } 7726 + }, 7727 + "node_modules/is-bigint": { 7728 + "version": "1.1.0", 7729 + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", 7730 + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", 7731 + "dev": true, 7732 + "license": "MIT", 7733 + "dependencies": { 7734 + "has-bigints": "^1.0.2" 7735 + }, 7736 + "engines": { 7737 + "node": ">= 0.4" 7738 + }, 7739 + "funding": { 7740 + "url": "https://github.com/sponsors/ljharb" 7741 + } 7742 + }, 3275 7743 "node_modules/is-binary-path": { 3276 7744 "version": "2.1.0", 3277 7745 "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", ··· 3284 7752 "node": ">=8" 3285 7753 } 3286 7754 }, 7755 + "node_modules/is-boolean-object": { 7756 + "version": "1.2.2", 7757 + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", 7758 + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", 7759 + "dev": true, 7760 + "license": "MIT", 7761 + "dependencies": { 7762 + "call-bound": "^1.0.3", 7763 + "has-tostringtag": "^1.0.2" 7764 + }, 7765 + "engines": { 7766 + "node": ">= 0.4" 7767 + }, 7768 + "funding": { 7769 + "url": "https://github.com/sponsors/ljharb" 7770 + } 7771 + }, 7772 + "node_modules/is-callable": { 7773 + "version": "1.2.7", 7774 + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", 7775 + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", 7776 + "dev": true, 7777 + "license": "MIT", 7778 + "engines": { 7779 + "node": ">= 0.4" 7780 + }, 7781 + "funding": { 7782 + "url": "https://github.com/sponsors/ljharb" 7783 + } 7784 + }, 7785 + "node_modules/is-core-module": { 7786 + "version": "2.16.1", 7787 + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", 7788 + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", 7789 + "dev": true, 7790 + "license": "MIT", 7791 + "dependencies": { 7792 + "hasown": "^2.0.2" 7793 + }, 7794 + "engines": { 7795 + "node": ">= 0.4" 7796 + }, 7797 + "funding": { 7798 + "url": "https://github.com/sponsors/ljharb" 7799 + } 7800 + }, 7801 + "node_modules/is-data-view": { 7802 + "version": "1.0.2", 7803 + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", 7804 + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", 7805 + "dev": true, 7806 + "license": "MIT", 7807 + "dependencies": { 7808 + "call-bound": "^1.0.2", 7809 + "get-intrinsic": "^1.2.6", 7810 + "is-typed-array": "^1.1.13" 7811 + }, 7812 + "engines": { 7813 + "node": ">= 0.4" 7814 + }, 7815 + "funding": { 7816 + "url": "https://github.com/sponsors/ljharb" 7817 + } 7818 + }, 7819 + "node_modules/is-date-object": { 7820 + "version": "1.1.0", 7821 + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", 7822 + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", 7823 + "dev": true, 7824 + "license": "MIT", 7825 + "dependencies": { 7826 + "call-bound": "^1.0.2", 7827 + "has-tostringtag": "^1.0.2" 7828 + }, 7829 + "engines": { 7830 + "node": ">= 0.4" 7831 + }, 7832 + "funding": { 7833 + "url": "https://github.com/sponsors/ljharb" 7834 + } 7835 + }, 3287 7836 "node_modules/is-decimal": { 3288 7837 "version": "2.0.1", 3289 7838 "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", ··· 3303 7852 "node": ">=0.10.0" 3304 7853 } 3305 7854 }, 7855 + "node_modules/is-finalizationregistry": { 7856 + "version": "1.1.1", 7857 + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", 7858 + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", 7859 + "dev": true, 7860 + "license": "MIT", 7861 + "dependencies": { 7862 + "call-bound": "^1.0.3" 7863 + }, 7864 + "engines": { 7865 + "node": ">= 0.4" 7866 + }, 7867 + "funding": { 7868 + "url": "https://github.com/sponsors/ljharb" 7869 + } 7870 + }, 7871 + "node_modules/is-generator-function": { 7872 + "version": "1.1.2", 7873 + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", 7874 + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", 7875 + "dev": true, 7876 + "license": "MIT", 7877 + "dependencies": { 7878 + "call-bound": "^1.0.4", 7879 + "generator-function": "^2.0.0", 7880 + "get-proto": "^1.0.1", 7881 + "has-tostringtag": "^1.0.2", 7882 + "safe-regex-test": "^1.1.0" 7883 + }, 7884 + "engines": { 7885 + "node": ">= 0.4" 7886 + }, 7887 + "funding": { 7888 + "url": "https://github.com/sponsors/ljharb" 7889 + } 7890 + }, 3306 7891 "node_modules/is-glob": { 3307 7892 "version": "4.0.3", 3308 7893 "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", ··· 3315 7900 "node": ">=0.10.0" 3316 7901 } 3317 7902 }, 7903 + "node_modules/is-immutable-type": { 7904 + "version": "5.0.1", 7905 + "resolved": "https://registry.npmjs.org/is-immutable-type/-/is-immutable-type-5.0.1.tgz", 7906 + "integrity": "sha512-LkHEOGVZZXxGl8vDs+10k3DvP++SEoYEAJLRk6buTFi6kD7QekThV7xHS0j6gpnUCQ0zpud/gMDGiV4dQneLTg==", 7907 + "dev": true, 7908 + "license": "BSD-3-Clause", 7909 + "dependencies": { 7910 + "@typescript-eslint/type-utils": "^8.0.0", 7911 + "ts-api-utils": "^2.0.0", 7912 + "ts-declaration-location": "^1.0.4" 7913 + }, 7914 + "peerDependencies": { 7915 + "eslint": "*", 7916 + "typescript": ">=4.7.4" 7917 + } 7918 + }, 7919 + "node_modules/is-map": { 7920 + "version": "2.0.3", 7921 + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", 7922 + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", 7923 + "dev": true, 7924 + "license": "MIT", 7925 + "engines": { 7926 + "node": ">= 0.4" 7927 + }, 7928 + "funding": { 7929 + "url": "https://github.com/sponsors/ljharb" 7930 + } 7931 + }, 7932 + "node_modules/is-negative-zero": { 7933 + "version": "2.0.3", 7934 + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", 7935 + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", 7936 + "dev": true, 7937 + "license": "MIT", 7938 + "engines": { 7939 + "node": ">= 0.4" 7940 + }, 7941 + "funding": { 7942 + "url": "https://github.com/sponsors/ljharb" 7943 + } 7944 + }, 3318 7945 "node_modules/is-number": { 3319 7946 "version": "7.0.0", 3320 7947 "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", ··· 3324 7951 "node": ">=0.12.0" 3325 7952 } 3326 7953 }, 7954 + "node_modules/is-number-object": { 7955 + "version": "1.1.1", 7956 + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", 7957 + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", 7958 + "dev": true, 7959 + "license": "MIT", 7960 + "dependencies": { 7961 + "call-bound": "^1.0.3", 7962 + "has-tostringtag": "^1.0.2" 7963 + }, 7964 + "engines": { 7965 + "node": ">= 0.4" 7966 + }, 7967 + "funding": { 7968 + "url": "https://github.com/sponsors/ljharb" 7969 + } 7970 + }, 3327 7971 "node_modules/is-potential-custom-element-name": { 3328 7972 "version": "1.0.1", 3329 7973 "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", ··· 3331 7975 "dev": true, 3332 7976 "license": "MIT" 3333 7977 }, 7978 + "node_modules/is-regex": { 7979 + "version": "1.2.1", 7980 + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", 7981 + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", 7982 + "dev": true, 7983 + "license": "MIT", 7984 + "dependencies": { 7985 + "call-bound": "^1.0.2", 7986 + "gopd": "^1.2.0", 7987 + "has-tostringtag": "^1.0.2", 7988 + "hasown": "^2.0.2" 7989 + }, 7990 + "engines": { 7991 + "node": ">= 0.4" 7992 + }, 7993 + "funding": { 7994 + "url": "https://github.com/sponsors/ljharb" 7995 + } 7996 + }, 7997 + "node_modules/is-set": { 7998 + "version": "2.0.3", 7999 + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", 8000 + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", 8001 + "dev": true, 8002 + "license": "MIT", 8003 + "engines": { 8004 + "node": ">= 0.4" 8005 + }, 8006 + "funding": { 8007 + "url": "https://github.com/sponsors/ljharb" 8008 + } 8009 + }, 8010 + "node_modules/is-shared-array-buffer": { 8011 + "version": "1.0.4", 8012 + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", 8013 + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", 8014 + "dev": true, 8015 + "license": "MIT", 8016 + "dependencies": { 8017 + "call-bound": "^1.0.3" 8018 + }, 8019 + "engines": { 8020 + "node": ">= 0.4" 8021 + }, 8022 + "funding": { 8023 + "url": "https://github.com/sponsors/ljharb" 8024 + } 8025 + }, 8026 + "node_modules/is-string": { 8027 + "version": "1.1.1", 8028 + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", 8029 + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", 8030 + "dev": true, 8031 + "license": "MIT", 8032 + "dependencies": { 8033 + "call-bound": "^1.0.3", 8034 + "has-tostringtag": "^1.0.2" 8035 + }, 8036 + "engines": { 8037 + "node": ">= 0.4" 8038 + }, 8039 + "funding": { 8040 + "url": "https://github.com/sponsors/ljharb" 8041 + } 8042 + }, 8043 + "node_modules/is-symbol": { 8044 + "version": "1.1.1", 8045 + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", 8046 + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", 8047 + "dev": true, 8048 + "license": "MIT", 8049 + "dependencies": { 8050 + "call-bound": "^1.0.2", 8051 + "has-symbols": "^1.1.0", 8052 + "safe-regex-test": "^1.1.0" 8053 + }, 8054 + "engines": { 8055 + "node": ">= 0.4" 8056 + }, 8057 + "funding": { 8058 + "url": "https://github.com/sponsors/ljharb" 8059 + } 8060 + }, 8061 + "node_modules/is-typed-array": { 8062 + "version": "1.1.15", 8063 + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", 8064 + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", 8065 + "dev": true, 8066 + "license": "MIT", 8067 + "dependencies": { 8068 + "which-typed-array": "^1.1.16" 8069 + }, 8070 + "engines": { 8071 + "node": ">= 0.4" 8072 + }, 8073 + "funding": { 8074 + "url": "https://github.com/sponsors/ljharb" 8075 + } 8076 + }, 8077 + "node_modules/is-weakmap": { 8078 + "version": "2.0.2", 8079 + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", 8080 + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", 8081 + "dev": true, 8082 + "license": "MIT", 8083 + "engines": { 8084 + "node": ">= 0.4" 8085 + }, 8086 + "funding": { 8087 + "url": "https://github.com/sponsors/ljharb" 8088 + } 8089 + }, 8090 + "node_modules/is-weakref": { 8091 + "version": "1.1.1", 8092 + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", 8093 + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", 8094 + "dev": true, 8095 + "license": "MIT", 8096 + "dependencies": { 8097 + "call-bound": "^1.0.3" 8098 + }, 8099 + "engines": { 8100 + "node": ">= 0.4" 8101 + }, 8102 + "funding": { 8103 + "url": "https://github.com/sponsors/ljharb" 8104 + } 8105 + }, 8106 + "node_modules/is-weakset": { 8107 + "version": "2.0.4", 8108 + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", 8109 + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", 8110 + "dev": true, 8111 + "license": "MIT", 8112 + "dependencies": { 8113 + "call-bound": "^1.0.3", 8114 + "get-intrinsic": "^1.2.6" 8115 + }, 8116 + "engines": { 8117 + "node": ">= 0.4" 8118 + }, 8119 + "funding": { 8120 + "url": "https://github.com/sponsors/ljharb" 8121 + } 8122 + }, 8123 + "node_modules/isarray": { 8124 + "version": "2.0.5", 8125 + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", 8126 + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", 8127 + "dev": true, 8128 + "license": "MIT" 8129 + }, 3334 8130 "node_modules/isbot": { 3335 8131 "version": "5.1.30", 3336 8132 "resolved": "https://registry.npmjs.org/isbot/-/isbot-5.1.30.tgz", ··· 3340 8136 "node": ">=18" 3341 8137 } 3342 8138 }, 8139 + "node_modules/isexe": { 8140 + "version": "2.0.0", 8141 + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 8142 + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", 8143 + "dev": true, 8144 + "license": "ISC", 8145 + "peer": true 8146 + }, 3343 8147 "node_modules/iso-datestring-validator": { 3344 8148 "version": "2.2.2", 3345 8149 "resolved": "https://registry.npmjs.org/iso-datestring-validator/-/iso-datestring-validator-2.2.2.tgz", 3346 8150 "integrity": "sha512-yLEMkBbLZTlVQqOnQ4FiMujR6T4DEcCb1xizmvXS+OxuhwcbtynoosRzdMA69zZCShCNAbi+gJ71FxZBBXx1SA==", 3347 8151 "license": "MIT" 3348 8152 }, 8153 + "node_modules/iterator.prototype": { 8154 + "version": "1.1.5", 8155 + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", 8156 + "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", 8157 + "dev": true, 8158 + "license": "MIT", 8159 + "dependencies": { 8160 + "define-data-property": "^1.1.4", 8161 + "es-object-atoms": "^1.0.0", 8162 + "get-intrinsic": "^1.2.6", 8163 + "get-proto": "^1.0.0", 8164 + "has-symbols": "^1.1.0", 8165 + "set-function-name": "^2.0.2" 8166 + }, 8167 + "engines": { 8168 + "node": ">= 0.4" 8169 + } 8170 + }, 3349 8171 "node_modules/jiti": { 3350 8172 "version": "2.5.1", 3351 8173 "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz", ··· 3355 8177 "jiti": "lib/jiti-cli.mjs" 3356 8178 } 3357 8179 }, 8180 + "node_modules/jose": { 8181 + "version": "5.10.0", 8182 + "resolved": "https://registry.npmjs.org/jose/-/jose-5.10.0.tgz", 8183 + "integrity": "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==", 8184 + "license": "MIT", 8185 + "funding": { 8186 + "url": "https://github.com/sponsors/panva" 8187 + } 8188 + }, 8189 + "node_modules/jotai": { 8190 + "version": "2.13.1", 8191 + "resolved": "https://registry.npmjs.org/jotai/-/jotai-2.13.1.tgz", 8192 + "integrity": "sha512-cRsw6kFeGC9Z/D3egVKrTXRweycZ4z/k7i2MrfCzPYsL9SIWcPXTyqv258/+Ay8VUEcihNiE/coBLE6Kic6b8A==", 8193 + "license": "MIT", 8194 + "engines": { 8195 + "node": ">=12.20.0" 8196 + }, 8197 + "peerDependencies": { 8198 + "@babel/core": ">=7.0.0", 8199 + "@babel/template": ">=7.0.0", 8200 + "@types/react": ">=17.0.0", 8201 + "react": ">=17.0.0" 8202 + }, 8203 + "peerDependenciesMeta": { 8204 + "@babel/core": { 8205 + "optional": true 8206 + }, 8207 + "@babel/template": { 8208 + "optional": true 8209 + }, 8210 + "@types/react": { 8211 + "optional": true 8212 + }, 8213 + "react": { 8214 + "optional": true 8215 + } 8216 + } 8217 + }, 3358 8218 "node_modules/js-tokens": { 3359 8219 "version": "4.0.0", 3360 8220 "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 3361 8221 "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", 3362 8222 "license": "MIT" 8223 + }, 8224 + "node_modules/js-yaml": { 8225 + "version": "4.1.0", 8226 + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", 8227 + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", 8228 + "dev": true, 8229 + "license": "MIT", 8230 + "dependencies": { 8231 + "argparse": "^2.0.1" 8232 + }, 8233 + "bin": { 8234 + "js-yaml": "bin/js-yaml.js" 8235 + } 3363 8236 }, 3364 8237 "node_modules/jsdom": { 3365 8238 "version": "26.1.0", ··· 3413 8286 "node": ">=6" 3414 8287 } 3415 8288 }, 8289 + "node_modules/json-buffer": { 8290 + "version": "3.0.1", 8291 + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", 8292 + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", 8293 + "dev": true, 8294 + "license": "MIT", 8295 + "peer": true 8296 + }, 8297 + "node_modules/json-parse-even-better-errors": { 8298 + "version": "2.3.1", 8299 + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", 8300 + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", 8301 + "dev": true, 8302 + "license": "MIT" 8303 + }, 8304 + "node_modules/json-schema-traverse": { 8305 + "version": "0.4.1", 8306 + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 8307 + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", 8308 + "dev": true, 8309 + "license": "MIT", 8310 + "peer": true 8311 + }, 8312 + "node_modules/json-stable-stringify-without-jsonify": { 8313 + "version": "1.0.1", 8314 + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", 8315 + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", 8316 + "dev": true, 8317 + "license": "MIT", 8318 + "peer": true 8319 + }, 3416 8320 "node_modules/json5": { 3417 8321 "version": "2.2.3", 3418 8322 "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", ··· 3423 8327 }, 3424 8328 "engines": { 3425 8329 "node": ">=6" 8330 + } 8331 + }, 8332 + "node_modules/jsx-ast-utils": { 8333 + "version": "3.3.5", 8334 + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", 8335 + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", 8336 + "dev": true, 8337 + "license": "MIT", 8338 + "dependencies": { 8339 + "array-includes": "^3.1.6", 8340 + "array.prototype.flat": "^1.3.1", 8341 + "object.assign": "^4.1.4", 8342 + "object.values": "^1.1.6" 8343 + }, 8344 + "engines": { 8345 + "node": ">=4.0" 8346 + } 8347 + }, 8348 + "node_modules/keyv": { 8349 + "version": "4.5.4", 8350 + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", 8351 + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", 8352 + "dev": true, 8353 + "license": "MIT", 8354 + "peer": true, 8355 + "dependencies": { 8356 + "json-buffer": "3.0.1" 8357 + } 8358 + }, 8359 + "node_modules/kolorist": { 8360 + "version": "1.8.0", 8361 + "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz", 8362 + "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==", 8363 + "dev": true, 8364 + "license": "MIT" 8365 + }, 8366 + "node_modules/levn": { 8367 + "version": "0.4.1", 8368 + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", 8369 + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", 8370 + "dev": true, 8371 + "license": "MIT", 8372 + "peer": true, 8373 + "dependencies": { 8374 + "prelude-ls": "^1.2.1", 8375 + "type-check": "~0.4.0" 8376 + }, 8377 + "engines": { 8378 + "node": ">= 0.8.0" 3426 8379 } 3427 8380 }, 3428 8381 "node_modules/lie": { ··· 3662 8615 "url": "https://opencollective.com/parcel" 3663 8616 } 3664 8617 }, 8618 + "node_modules/lines-and-columns": { 8619 + "version": "1.2.4", 8620 + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", 8621 + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", 8622 + "dev": true, 8623 + "license": "MIT" 8624 + }, 8625 + "node_modules/local-pkg": { 8626 + "version": "1.1.2", 8627 + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.1.2.tgz", 8628 + "integrity": "sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==", 8629 + "dev": true, 8630 + "license": "MIT", 8631 + "dependencies": { 8632 + "mlly": "^1.7.4", 8633 + "pkg-types": "^2.3.0", 8634 + "quansync": "^0.2.11" 8635 + }, 8636 + "engines": { 8637 + "node": ">=14" 8638 + }, 8639 + "funding": { 8640 + "url": "https://github.com/sponsors/antfu" 8641 + } 8642 + }, 3665 8643 "node_modules/localforage": { 3666 8644 "version": "1.10.0", 3667 8645 "resolved": "https://registry.npmjs.org/localforage/-/localforage-1.10.0.tgz", ··· 3671 8649 "lie": "3.1.1" 3672 8650 } 3673 8651 }, 8652 + "node_modules/locate-path": { 8653 + "version": "6.0.0", 8654 + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", 8655 + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", 8656 + "dev": true, 8657 + "license": "MIT", 8658 + "peer": true, 8659 + "dependencies": { 8660 + "p-locate": "^5.0.0" 8661 + }, 8662 + "engines": { 8663 + "node": ">=10" 8664 + }, 8665 + "funding": { 8666 + "url": "https://github.com/sponsors/sindresorhus" 8667 + } 8668 + }, 8669 + "node_modules/lodash.clonedeep": { 8670 + "version": "4.5.0", 8671 + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", 8672 + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", 8673 + "license": "MIT" 8674 + }, 8675 + "node_modules/lodash.merge": { 8676 + "version": "4.6.2", 8677 + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", 8678 + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", 8679 + "dev": true, 8680 + "license": "MIT", 8681 + "peer": true 8682 + }, 3674 8683 "node_modules/loose-envify": { 3675 8684 "version": "1.4.0", 3676 8685 "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", ··· 3690 8699 "dev": true, 3691 8700 "license": "MIT" 3692 8701 }, 8702 + "node_modules/lower-case": { 8703 + "version": "2.0.2", 8704 + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", 8705 + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", 8706 + "dev": true, 8707 + "license": "MIT", 8708 + "dependencies": { 8709 + "tslib": "^2.0.3" 8710 + } 8711 + }, 3693 8712 "node_modules/lru-cache": { 3694 8713 "version": "5.1.1", 3695 8714 "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", ··· 3710 8729 } 3711 8730 }, 3712 8731 "node_modules/magic-string": { 3713 - "version": "0.30.18", 3714 - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.18.tgz", 3715 - "integrity": "sha512-yi8swmWbO17qHhwIBNeeZxTceJMeBvWJaId6dyvTSOwTipqeHhMhOrz6513r1sOKnpvQ7zkhlG8tPrpilwTxHQ==", 8732 + "version": "0.30.19", 8733 + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz", 8734 + "integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==", 3716 8735 "license": "MIT", 3717 8736 "dependencies": { 3718 8737 "@jridgewell/sourcemap-codec": "^1.5.5" 3719 8738 } 3720 8739 }, 8740 + "node_modules/math-intrinsics": { 8741 + "version": "1.1.0", 8742 + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", 8743 + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", 8744 + "dev": true, 8745 + "license": "MIT", 8746 + "engines": { 8747 + "node": ">= 0.4" 8748 + } 8749 + }, 3721 8750 "node_modules/media-chrome": { 3722 8751 "version": "4.11.1", 3723 8752 "resolved": "https://registry.npmjs.org/media-chrome/-/media-chrome-4.11.1.tgz", ··· 3734 8763 "integrity": "sha512-9P2FuUHnZZ3iji+2RQk7Zkh5AmZTnOG5fODACnjhCVveX1McY3jmCRHofIEI+yTBqplz7LXy48c7fQ3Uigp88w==", 3735 8764 "license": "MIT" 3736 8765 }, 8766 + "node_modules/merge2": { 8767 + "version": "1.4.1", 8768 + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", 8769 + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", 8770 + "dev": true, 8771 + "license": "MIT", 8772 + "engines": { 8773 + "node": ">= 8" 8774 + } 8775 + }, 8776 + "node_modules/micromatch": { 8777 + "version": "4.0.8", 8778 + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", 8779 + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", 8780 + "dev": true, 8781 + "license": "MIT", 8782 + "dependencies": { 8783 + "braces": "^3.0.3", 8784 + "picomatch": "^2.3.1" 8785 + }, 8786 + "engines": { 8787 + "node": ">=8.6" 8788 + } 8789 + }, 8790 + "node_modules/minimatch": { 8791 + "version": "3.1.2", 8792 + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 8793 + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 8794 + "dev": true, 8795 + "license": "ISC", 8796 + "dependencies": { 8797 + "brace-expansion": "^1.1.7" 8798 + }, 8799 + "engines": { 8800 + "node": "*" 8801 + } 8802 + }, 3737 8803 "node_modules/minipass": { 3738 8804 "version": "7.1.2", 3739 8805 "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", ··· 3770 8836 "url": "https://github.com/sponsors/isaacs" 3771 8837 } 3772 8838 }, 8839 + "node_modules/mlly": { 8840 + "version": "1.8.0", 8841 + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz", 8842 + "integrity": "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==", 8843 + "dev": true, 8844 + "license": "MIT", 8845 + "dependencies": { 8846 + "acorn": "^8.15.0", 8847 + "pathe": "^2.0.3", 8848 + "pkg-types": "^1.3.1", 8849 + "ufo": "^1.6.1" 8850 + } 8851 + }, 8852 + "node_modules/mlly/node_modules/confbox": { 8853 + "version": "0.1.8", 8854 + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", 8855 + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", 8856 + "dev": true, 8857 + "license": "MIT" 8858 + }, 8859 + "node_modules/mlly/node_modules/pkg-types": { 8860 + "version": "1.3.1", 8861 + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", 8862 + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", 8863 + "dev": true, 8864 + "license": "MIT", 8865 + "dependencies": { 8866 + "confbox": "^0.1.8", 8867 + "mlly": "^1.7.4", 8868 + "pathe": "^2.0.1" 8869 + } 8870 + }, 3773 8871 "node_modules/ms": { 3774 8872 "version": "2.1.3", 3775 8873 "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", ··· 3812 8910 "integrity": "sha512-zkVhZUA3y8mbz652WrL5x0fB0ehrBkulWT3TomAQ9iDtyXZvzKeEA6GPxAItBYeNYl5yngKRX612qHOhvMkDeg==", 3813 8911 "license": "MIT" 3814 8912 }, 8913 + "node_modules/natural-compare": { 8914 + "version": "1.4.0", 8915 + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", 8916 + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", 8917 + "dev": true, 8918 + "license": "MIT" 8919 + }, 8920 + "node_modules/no-case": { 8921 + "version": "3.0.4", 8922 + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", 8923 + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", 8924 + "dev": true, 8925 + "license": "MIT", 8926 + "dependencies": { 8927 + "lower-case": "^2.0.2", 8928 + "tslib": "^2.0.3" 8929 + } 8930 + }, 3815 8931 "node_modules/node-releases": { 3816 8932 "version": "2.0.19", 3817 8933 "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", ··· 3827 8943 "node": ">=0.10.0" 3828 8944 } 3829 8945 }, 8946 + "node_modules/npm": { 8947 + "version": "11.6.2", 8948 + "resolved": "https://registry.npmjs.org/npm/-/npm-11.6.2.tgz", 8949 + "integrity": "sha512-7iKzNfy8lWYs3zq4oFPa8EXZz5xt9gQNKJZau3B1ErLBb6bF7sBJ00x09485DOvRT2l5Gerbl3VlZNT57MxJVA==", 8950 + "bundleDependencies": [ 8951 + "@isaacs/string-locale-compare", 8952 + "@npmcli/arborist", 8953 + "@npmcli/config", 8954 + "@npmcli/fs", 8955 + "@npmcli/map-workspaces", 8956 + "@npmcli/package-json", 8957 + "@npmcli/promise-spawn", 8958 + "@npmcli/redact", 8959 + "@npmcli/run-script", 8960 + "@sigstore/tuf", 8961 + "abbrev", 8962 + "archy", 8963 + "cacache", 8964 + "chalk", 8965 + "ci-info", 8966 + "cli-columns", 8967 + "fastest-levenshtein", 8968 + "fs-minipass", 8969 + "glob", 8970 + "graceful-fs", 8971 + "hosted-git-info", 8972 + "ini", 8973 + "init-package-json", 8974 + "is-cidr", 8975 + "json-parse-even-better-errors", 8976 + "libnpmaccess", 8977 + "libnpmdiff", 8978 + "libnpmexec", 8979 + "libnpmfund", 8980 + "libnpmorg", 8981 + "libnpmpack", 8982 + "libnpmpublish", 8983 + "libnpmsearch", 8984 + "libnpmteam", 8985 + "libnpmversion", 8986 + "make-fetch-happen", 8987 + "minimatch", 8988 + "minipass", 8989 + "minipass-pipeline", 8990 + "ms", 8991 + "node-gyp", 8992 + "nopt", 8993 + "npm-audit-report", 8994 + "npm-install-checks", 8995 + "npm-package-arg", 8996 + "npm-pick-manifest", 8997 + "npm-profile", 8998 + "npm-registry-fetch", 8999 + "npm-user-validate", 9000 + "p-map", 9001 + "pacote", 9002 + "parse-conflict-json", 9003 + "proc-log", 9004 + "qrcode-terminal", 9005 + "read", 9006 + "semver", 9007 + "spdx-expression-parse", 9008 + "ssri", 9009 + "supports-color", 9010 + "tar", 9011 + "text-table", 9012 + "tiny-relative-date", 9013 + "treeverse", 9014 + "validate-npm-package-name", 9015 + "which" 9016 + ], 9017 + "license": "Artistic-2.0", 9018 + "workspaces": [ 9019 + "docs", 9020 + "smoke-tests", 9021 + "mock-globals", 9022 + "mock-registry", 9023 + "workspaces/*" 9024 + ], 9025 + "dependencies": { 9026 + "@isaacs/string-locale-compare": "^1.1.0", 9027 + "@npmcli/arborist": "^9.1.6", 9028 + "@npmcli/config": "^10.4.2", 9029 + "@npmcli/fs": "^4.0.0", 9030 + "@npmcli/map-workspaces": "^5.0.0", 9031 + "@npmcli/package-json": "^7.0.1", 9032 + "@npmcli/promise-spawn": "^8.0.3", 9033 + "@npmcli/redact": "^3.2.2", 9034 + "@npmcli/run-script": "^10.0.0", 9035 + "@sigstore/tuf": "^4.0.0", 9036 + "abbrev": "^3.0.1", 9037 + "archy": "~1.0.0", 9038 + "cacache": "^20.0.1", 9039 + "chalk": "^5.6.2", 9040 + "ci-info": "^4.3.1", 9041 + "cli-columns": "^4.0.0", 9042 + "fastest-levenshtein": "^1.0.16", 9043 + "fs-minipass": "^3.0.3", 9044 + "glob": "^11.0.3", 9045 + "graceful-fs": "^4.2.11", 9046 + "hosted-git-info": "^9.0.2", 9047 + "ini": "^5.0.0", 9048 + "init-package-json": "^8.2.2", 9049 + "is-cidr": "^6.0.1", 9050 + "json-parse-even-better-errors": "^4.0.0", 9051 + "libnpmaccess": "^10.0.3", 9052 + "libnpmdiff": "^8.0.9", 9053 + "libnpmexec": "^10.1.8", 9054 + "libnpmfund": "^7.0.9", 9055 + "libnpmorg": "^8.0.1", 9056 + "libnpmpack": "^9.0.9", 9057 + "libnpmpublish": "^11.1.2", 9058 + "libnpmsearch": "^9.0.1", 9059 + "libnpmteam": "^8.0.2", 9060 + "libnpmversion": "^8.0.2", 9061 + "make-fetch-happen": "^15.0.2", 9062 + "minimatch": "^10.0.3", 9063 + "minipass": "^7.1.1", 9064 + "minipass-pipeline": "^1.2.4", 9065 + "ms": "^2.1.2", 9066 + "node-gyp": "^11.4.2", 9067 + "nopt": "^8.1.0", 9068 + "npm-audit-report": "^6.0.0", 9069 + "npm-install-checks": "^7.1.2", 9070 + "npm-package-arg": "^13.0.1", 9071 + "npm-pick-manifest": "^11.0.1", 9072 + "npm-profile": "^12.0.0", 9073 + "npm-registry-fetch": "^19.0.0", 9074 + "npm-user-validate": "^3.0.0", 9075 + "p-map": "^7.0.3", 9076 + "pacote": "^21.0.3", 9077 + "parse-conflict-json": "^4.0.0", 9078 + "proc-log": "^5.0.0", 9079 + "qrcode-terminal": "^0.12.0", 9080 + "read": "^4.1.0", 9081 + "semver": "^7.7.3", 9082 + "spdx-expression-parse": "^4.0.0", 9083 + "ssri": "^12.0.0", 9084 + "supports-color": "^10.2.2", 9085 + "tar": "^7.5.1", 9086 + "text-table": "~0.2.0", 9087 + "tiny-relative-date": "^2.0.2", 9088 + "treeverse": "^3.0.0", 9089 + "validate-npm-package-name": "^6.0.2", 9090 + "which": "^5.0.0" 9091 + }, 9092 + "bin": { 9093 + "npm": "bin/npm-cli.js", 9094 + "npx": "bin/npx-cli.js" 9095 + }, 9096 + "engines": { 9097 + "node": "^20.17.0 || >=22.9.0" 9098 + } 9099 + }, 9100 + "node_modules/npm/node_modules/@isaacs/balanced-match": { 9101 + "version": "4.0.1", 9102 + "inBundle": true, 9103 + "license": "MIT", 9104 + "engines": { 9105 + "node": "20 || >=22" 9106 + } 9107 + }, 9108 + "node_modules/npm/node_modules/@isaacs/brace-expansion": { 9109 + "version": "5.0.0", 9110 + "inBundle": true, 9111 + "license": "MIT", 9112 + "dependencies": { 9113 + "@isaacs/balanced-match": "^4.0.1" 9114 + }, 9115 + "engines": { 9116 + "node": "20 || >=22" 9117 + } 9118 + }, 9119 + "node_modules/npm/node_modules/@isaacs/cliui": { 9120 + "version": "8.0.2", 9121 + "inBundle": true, 9122 + "license": "ISC", 9123 + "dependencies": { 9124 + "string-width": "^5.1.2", 9125 + "string-width-cjs": "npm:string-width@^4.2.0", 9126 + "strip-ansi": "^7.0.1", 9127 + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", 9128 + "wrap-ansi": "^8.1.0", 9129 + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" 9130 + }, 9131 + "engines": { 9132 + "node": ">=12" 9133 + } 9134 + }, 9135 + "node_modules/npm/node_modules/@isaacs/cliui/node_modules/ansi-regex": { 9136 + "version": "6.2.2", 9137 + "inBundle": true, 9138 + "license": "MIT", 9139 + "engines": { 9140 + "node": ">=12" 9141 + }, 9142 + "funding": { 9143 + "url": "https://github.com/chalk/ansi-regex?sponsor=1" 9144 + } 9145 + }, 9146 + "node_modules/npm/node_modules/@isaacs/cliui/node_modules/emoji-regex": { 9147 + "version": "9.2.2", 9148 + "inBundle": true, 9149 + "license": "MIT" 9150 + }, 9151 + "node_modules/npm/node_modules/@isaacs/cliui/node_modules/string-width": { 9152 + "version": "5.1.2", 9153 + "inBundle": true, 9154 + "license": "MIT", 9155 + "dependencies": { 9156 + "eastasianwidth": "^0.2.0", 9157 + "emoji-regex": "^9.2.2", 9158 + "strip-ansi": "^7.0.1" 9159 + }, 9160 + "engines": { 9161 + "node": ">=12" 9162 + }, 9163 + "funding": { 9164 + "url": "https://github.com/sponsors/sindresorhus" 9165 + } 9166 + }, 9167 + "node_modules/npm/node_modules/@isaacs/cliui/node_modules/strip-ansi": { 9168 + "version": "7.1.2", 9169 + "inBundle": true, 9170 + "license": "MIT", 9171 + "dependencies": { 9172 + "ansi-regex": "^6.0.1" 9173 + }, 9174 + "engines": { 9175 + "node": ">=12" 9176 + }, 9177 + "funding": { 9178 + "url": "https://github.com/chalk/strip-ansi?sponsor=1" 9179 + } 9180 + }, 9181 + "node_modules/npm/node_modules/@isaacs/fs-minipass": { 9182 + "version": "4.0.1", 9183 + "inBundle": true, 9184 + "license": "ISC", 9185 + "dependencies": { 9186 + "minipass": "^7.0.4" 9187 + }, 9188 + "engines": { 9189 + "node": ">=18.0.0" 9190 + } 9191 + }, 9192 + "node_modules/npm/node_modules/@isaacs/string-locale-compare": { 9193 + "version": "1.1.0", 9194 + "inBundle": true, 9195 + "license": "ISC" 9196 + }, 9197 + "node_modules/npm/node_modules/@npmcli/agent": { 9198 + "version": "4.0.0", 9199 + "inBundle": true, 9200 + "license": "ISC", 9201 + "dependencies": { 9202 + "agent-base": "^7.1.0", 9203 + "http-proxy-agent": "^7.0.0", 9204 + "https-proxy-agent": "^7.0.1", 9205 + "lru-cache": "^11.2.1", 9206 + "socks-proxy-agent": "^8.0.3" 9207 + }, 9208 + "engines": { 9209 + "node": "^20.17.0 || >=22.9.0" 9210 + } 9211 + }, 9212 + "node_modules/npm/node_modules/@npmcli/arborist": { 9213 + "version": "9.1.6", 9214 + "inBundle": true, 9215 + "license": "ISC", 9216 + "dependencies": { 9217 + "@isaacs/string-locale-compare": "^1.1.0", 9218 + "@npmcli/fs": "^4.0.0", 9219 + "@npmcli/installed-package-contents": "^3.0.0", 9220 + "@npmcli/map-workspaces": "^5.0.0", 9221 + "@npmcli/metavuln-calculator": "^9.0.2", 9222 + "@npmcli/name-from-folder": "^3.0.0", 9223 + "@npmcli/node-gyp": "^4.0.0", 9224 + "@npmcli/package-json": "^7.0.0", 9225 + "@npmcli/query": "^4.0.0", 9226 + "@npmcli/redact": "^3.0.0", 9227 + "@npmcli/run-script": "^10.0.0", 9228 + "bin-links": "^5.0.0", 9229 + "cacache": "^20.0.1", 9230 + "common-ancestor-path": "^1.0.1", 9231 + "hosted-git-info": "^9.0.0", 9232 + "json-stringify-nice": "^1.1.4", 9233 + "lru-cache": "^11.2.1", 9234 + "minimatch": "^10.0.3", 9235 + "nopt": "^8.0.0", 9236 + "npm-install-checks": "^7.1.0", 9237 + "npm-package-arg": "^13.0.0", 9238 + "npm-pick-manifest": "^11.0.1", 9239 + "npm-registry-fetch": "^19.0.0", 9240 + "pacote": "^21.0.2", 9241 + "parse-conflict-json": "^4.0.0", 9242 + "proc-log": "^5.0.0", 9243 + "proggy": "^3.0.0", 9244 + "promise-all-reject-late": "^1.0.0", 9245 + "promise-call-limit": "^3.0.1", 9246 + "semver": "^7.3.7", 9247 + "ssri": "^12.0.0", 9248 + "treeverse": "^3.0.0", 9249 + "walk-up-path": "^4.0.0" 9250 + }, 9251 + "bin": { 9252 + "arborist": "bin/index.js" 9253 + }, 9254 + "engines": { 9255 + "node": "^20.17.0 || >=22.9.0" 9256 + } 9257 + }, 9258 + "node_modules/npm/node_modules/@npmcli/config": { 9259 + "version": "10.4.2", 9260 + "inBundle": true, 9261 + "license": "ISC", 9262 + "dependencies": { 9263 + "@npmcli/map-workspaces": "^5.0.0", 9264 + "@npmcli/package-json": "^7.0.0", 9265 + "ci-info": "^4.0.0", 9266 + "ini": "^5.0.0", 9267 + "nopt": "^8.1.0", 9268 + "proc-log": "^5.0.0", 9269 + "semver": "^7.3.5", 9270 + "walk-up-path": "^4.0.0" 9271 + }, 9272 + "engines": { 9273 + "node": "^20.17.0 || >=22.9.0" 9274 + } 9275 + }, 9276 + "node_modules/npm/node_modules/@npmcli/fs": { 9277 + "version": "4.0.0", 9278 + "inBundle": true, 9279 + "license": "ISC", 9280 + "dependencies": { 9281 + "semver": "^7.3.5" 9282 + }, 9283 + "engines": { 9284 + "node": "^18.17.0 || >=20.5.0" 9285 + } 9286 + }, 9287 + "node_modules/npm/node_modules/@npmcli/git": { 9288 + "version": "7.0.0", 9289 + "inBundle": true, 9290 + "license": "ISC", 9291 + "dependencies": { 9292 + "@npmcli/promise-spawn": "^8.0.0", 9293 + "ini": "^5.0.0", 9294 + "lru-cache": "^11.2.1", 9295 + "npm-pick-manifest": "^11.0.1", 9296 + "proc-log": "^5.0.0", 9297 + "promise-retry": "^2.0.1", 9298 + "semver": "^7.3.5", 9299 + "which": "^5.0.0" 9300 + }, 9301 + "engines": { 9302 + "node": "^20.17.0 || >=22.9.0" 9303 + } 9304 + }, 9305 + "node_modules/npm/node_modules/@npmcli/installed-package-contents": { 9306 + "version": "3.0.0", 9307 + "inBundle": true, 9308 + "license": "ISC", 9309 + "dependencies": { 9310 + "npm-bundled": "^4.0.0", 9311 + "npm-normalize-package-bin": "^4.0.0" 9312 + }, 9313 + "bin": { 9314 + "installed-package-contents": "bin/index.js" 9315 + }, 9316 + "engines": { 9317 + "node": "^18.17.0 || >=20.5.0" 9318 + } 9319 + }, 9320 + "node_modules/npm/node_modules/@npmcli/map-workspaces": { 9321 + "version": "5.0.0", 9322 + "inBundle": true, 9323 + "license": "ISC", 9324 + "dependencies": { 9325 + "@npmcli/name-from-folder": "^3.0.0", 9326 + "@npmcli/package-json": "^7.0.0", 9327 + "glob": "^11.0.3", 9328 + "minimatch": "^10.0.3" 9329 + }, 9330 + "engines": { 9331 + "node": "^20.17.0 || >=22.9.0" 9332 + } 9333 + }, 9334 + "node_modules/npm/node_modules/@npmcli/metavuln-calculator": { 9335 + "version": "9.0.2", 9336 + "inBundle": true, 9337 + "license": "ISC", 9338 + "dependencies": { 9339 + "cacache": "^20.0.0", 9340 + "json-parse-even-better-errors": "^4.0.0", 9341 + "pacote": "^21.0.0", 9342 + "proc-log": "^5.0.0", 9343 + "semver": "^7.3.5" 9344 + }, 9345 + "engines": { 9346 + "node": "^20.17.0 || >=22.9.0" 9347 + } 9348 + }, 9349 + "node_modules/npm/node_modules/@npmcli/name-from-folder": { 9350 + "version": "3.0.0", 9351 + "inBundle": true, 9352 + "license": "ISC", 9353 + "engines": { 9354 + "node": "^18.17.0 || >=20.5.0" 9355 + } 9356 + }, 9357 + "node_modules/npm/node_modules/@npmcli/node-gyp": { 9358 + "version": "4.0.0", 9359 + "inBundle": true, 9360 + "license": "ISC", 9361 + "engines": { 9362 + "node": "^18.17.0 || >=20.5.0" 9363 + } 9364 + }, 9365 + "node_modules/npm/node_modules/@npmcli/package-json": { 9366 + "version": "7.0.1", 9367 + "inBundle": true, 9368 + "license": "ISC", 9369 + "dependencies": { 9370 + "@npmcli/git": "^7.0.0", 9371 + "glob": "^11.0.3", 9372 + "hosted-git-info": "^9.0.0", 9373 + "json-parse-even-better-errors": "^4.0.0", 9374 + "proc-log": "^5.0.0", 9375 + "semver": "^7.5.3", 9376 + "validate-npm-package-license": "^3.0.4" 9377 + }, 9378 + "engines": { 9379 + "node": "^20.17.0 || >=22.9.0" 9380 + } 9381 + }, 9382 + "node_modules/npm/node_modules/@npmcli/promise-spawn": { 9383 + "version": "8.0.3", 9384 + "inBundle": true, 9385 + "license": "ISC", 9386 + "dependencies": { 9387 + "which": "^5.0.0" 9388 + }, 9389 + "engines": { 9390 + "node": "^18.17.0 || >=20.5.0" 9391 + } 9392 + }, 9393 + "node_modules/npm/node_modules/@npmcli/query": { 9394 + "version": "4.0.1", 9395 + "inBundle": true, 9396 + "license": "ISC", 9397 + "dependencies": { 9398 + "postcss-selector-parser": "^7.0.0" 9399 + }, 9400 + "engines": { 9401 + "node": "^18.17.0 || >=20.5.0" 9402 + } 9403 + }, 9404 + "node_modules/npm/node_modules/@npmcli/redact": { 9405 + "version": "3.2.2", 9406 + "inBundle": true, 9407 + "license": "ISC", 9408 + "engines": { 9409 + "node": "^18.17.0 || >=20.5.0" 9410 + } 9411 + }, 9412 + "node_modules/npm/node_modules/@npmcli/run-script": { 9413 + "version": "10.0.0", 9414 + "inBundle": true, 9415 + "license": "ISC", 9416 + "dependencies": { 9417 + "@npmcli/node-gyp": "^4.0.0", 9418 + "@npmcli/package-json": "^7.0.0", 9419 + "@npmcli/promise-spawn": "^8.0.0", 9420 + "node-gyp": "^11.0.0", 9421 + "proc-log": "^5.0.0", 9422 + "which": "^5.0.0" 9423 + }, 9424 + "engines": { 9425 + "node": "^20.17.0 || >=22.9.0" 9426 + } 9427 + }, 9428 + "node_modules/npm/node_modules/@pkgjs/parseargs": { 9429 + "version": "0.11.0", 9430 + "inBundle": true, 9431 + "license": "MIT", 9432 + "optional": true, 9433 + "engines": { 9434 + "node": ">=14" 9435 + } 9436 + }, 9437 + "node_modules/npm/node_modules/@sigstore/bundle": { 9438 + "version": "4.0.0", 9439 + "inBundle": true, 9440 + "license": "Apache-2.0", 9441 + "dependencies": { 9442 + "@sigstore/protobuf-specs": "^0.5.0" 9443 + }, 9444 + "engines": { 9445 + "node": "^20.17.0 || >=22.9.0" 9446 + } 9447 + }, 9448 + "node_modules/npm/node_modules/@sigstore/core": { 9449 + "version": "3.0.0", 9450 + "inBundle": true, 9451 + "license": "Apache-2.0", 9452 + "engines": { 9453 + "node": "^20.17.0 || >=22.9.0" 9454 + } 9455 + }, 9456 + "node_modules/npm/node_modules/@sigstore/protobuf-specs": { 9457 + "version": "0.5.0", 9458 + "inBundle": true, 9459 + "license": "Apache-2.0", 9460 + "engines": { 9461 + "node": "^18.17.0 || >=20.5.0" 9462 + } 9463 + }, 9464 + "node_modules/npm/node_modules/@sigstore/sign": { 9465 + "version": "4.0.1", 9466 + "inBundle": true, 9467 + "license": "Apache-2.0", 9468 + "dependencies": { 9469 + "@sigstore/bundle": "^4.0.0", 9470 + "@sigstore/core": "^3.0.0", 9471 + "@sigstore/protobuf-specs": "^0.5.0", 9472 + "make-fetch-happen": "^15.0.2", 9473 + "proc-log": "^5.0.0", 9474 + "promise-retry": "^2.0.1" 9475 + }, 9476 + "engines": { 9477 + "node": "^20.17.0 || >=22.9.0" 9478 + } 9479 + }, 9480 + "node_modules/npm/node_modules/@sigstore/tuf": { 9481 + "version": "4.0.0", 9482 + "inBundle": true, 9483 + "license": "Apache-2.0", 9484 + "dependencies": { 9485 + "@sigstore/protobuf-specs": "^0.5.0", 9486 + "tuf-js": "^4.0.0" 9487 + }, 9488 + "engines": { 9489 + "node": "^20.17.0 || >=22.9.0" 9490 + } 9491 + }, 9492 + "node_modules/npm/node_modules/@sigstore/verify": { 9493 + "version": "3.0.0", 9494 + "inBundle": true, 9495 + "license": "Apache-2.0", 9496 + "dependencies": { 9497 + "@sigstore/bundle": "^4.0.0", 9498 + "@sigstore/core": "^3.0.0", 9499 + "@sigstore/protobuf-specs": "^0.5.0" 9500 + }, 9501 + "engines": { 9502 + "node": "^20.17.0 || >=22.9.0" 9503 + } 9504 + }, 9505 + "node_modules/npm/node_modules/@tufjs/canonical-json": { 9506 + "version": "2.0.0", 9507 + "inBundle": true, 9508 + "license": "MIT", 9509 + "engines": { 9510 + "node": "^16.14.0 || >=18.0.0" 9511 + } 9512 + }, 9513 + "node_modules/npm/node_modules/@tufjs/models": { 9514 + "version": "4.0.0", 9515 + "inBundle": true, 9516 + "license": "MIT", 9517 + "dependencies": { 9518 + "@tufjs/canonical-json": "2.0.0", 9519 + "minimatch": "^9.0.5" 9520 + }, 9521 + "engines": { 9522 + "node": "^20.17.0 || >=22.9.0" 9523 + } 9524 + }, 9525 + "node_modules/npm/node_modules/@tufjs/models/node_modules/minimatch": { 9526 + "version": "9.0.5", 9527 + "inBundle": true, 9528 + "license": "ISC", 9529 + "dependencies": { 9530 + "brace-expansion": "^2.0.1" 9531 + }, 9532 + "engines": { 9533 + "node": ">=16 || 14 >=14.17" 9534 + }, 9535 + "funding": { 9536 + "url": "https://github.com/sponsors/isaacs" 9537 + } 9538 + }, 9539 + "node_modules/npm/node_modules/abbrev": { 9540 + "version": "3.0.1", 9541 + "inBundle": true, 9542 + "license": "ISC", 9543 + "engines": { 9544 + "node": "^18.17.0 || >=20.5.0" 9545 + } 9546 + }, 9547 + "node_modules/npm/node_modules/agent-base": { 9548 + "version": "7.1.4", 9549 + "inBundle": true, 9550 + "license": "MIT", 9551 + "engines": { 9552 + "node": ">= 14" 9553 + } 9554 + }, 9555 + "node_modules/npm/node_modules/ansi-regex": { 9556 + "version": "5.0.1", 9557 + "inBundle": true, 9558 + "license": "MIT", 9559 + "engines": { 9560 + "node": ">=8" 9561 + } 9562 + }, 9563 + "node_modules/npm/node_modules/ansi-styles": { 9564 + "version": "6.2.3", 9565 + "inBundle": true, 9566 + "license": "MIT", 9567 + "engines": { 9568 + "node": ">=12" 9569 + }, 9570 + "funding": { 9571 + "url": "https://github.com/chalk/ansi-styles?sponsor=1" 9572 + } 9573 + }, 9574 + "node_modules/npm/node_modules/aproba": { 9575 + "version": "2.1.0", 9576 + "inBundle": true, 9577 + "license": "ISC" 9578 + }, 9579 + "node_modules/npm/node_modules/archy": { 9580 + "version": "1.0.0", 9581 + "inBundle": true, 9582 + "license": "MIT" 9583 + }, 9584 + "node_modules/npm/node_modules/balanced-match": { 9585 + "version": "1.0.2", 9586 + "inBundle": true, 9587 + "license": "MIT" 9588 + }, 9589 + "node_modules/npm/node_modules/bin-links": { 9590 + "version": "5.0.0", 9591 + "inBundle": true, 9592 + "license": "ISC", 9593 + "dependencies": { 9594 + "cmd-shim": "^7.0.0", 9595 + "npm-normalize-package-bin": "^4.0.0", 9596 + "proc-log": "^5.0.0", 9597 + "read-cmd-shim": "^5.0.0", 9598 + "write-file-atomic": "^6.0.0" 9599 + }, 9600 + "engines": { 9601 + "node": "^18.17.0 || >=20.5.0" 9602 + } 9603 + }, 9604 + "node_modules/npm/node_modules/binary-extensions": { 9605 + "version": "3.1.0", 9606 + "inBundle": true, 9607 + "license": "MIT", 9608 + "engines": { 9609 + "node": ">=18.20" 9610 + }, 9611 + "funding": { 9612 + "url": "https://github.com/sponsors/sindresorhus" 9613 + } 9614 + }, 9615 + "node_modules/npm/node_modules/brace-expansion": { 9616 + "version": "2.0.2", 9617 + "inBundle": true, 9618 + "license": "MIT", 9619 + "dependencies": { 9620 + "balanced-match": "^1.0.0" 9621 + } 9622 + }, 9623 + "node_modules/npm/node_modules/cacache": { 9624 + "version": "20.0.1", 9625 + "inBundle": true, 9626 + "license": "ISC", 9627 + "dependencies": { 9628 + "@npmcli/fs": "^4.0.0", 9629 + "fs-minipass": "^3.0.0", 9630 + "glob": "^11.0.3", 9631 + "lru-cache": "^11.1.0", 9632 + "minipass": "^7.0.3", 9633 + "minipass-collect": "^2.0.1", 9634 + "minipass-flush": "^1.0.5", 9635 + "minipass-pipeline": "^1.2.4", 9636 + "p-map": "^7.0.2", 9637 + "ssri": "^12.0.0", 9638 + "unique-filename": "^4.0.0" 9639 + }, 9640 + "engines": { 9641 + "node": "^20.17.0 || >=22.9.0" 9642 + } 9643 + }, 9644 + "node_modules/npm/node_modules/chalk": { 9645 + "version": "5.6.2", 9646 + "inBundle": true, 9647 + "license": "MIT", 9648 + "engines": { 9649 + "node": "^12.17.0 || ^14.13 || >=16.0.0" 9650 + }, 9651 + "funding": { 9652 + "url": "https://github.com/chalk/chalk?sponsor=1" 9653 + } 9654 + }, 9655 + "node_modules/npm/node_modules/chownr": { 9656 + "version": "3.0.0", 9657 + "inBundle": true, 9658 + "license": "BlueOak-1.0.0", 9659 + "engines": { 9660 + "node": ">=18" 9661 + } 9662 + }, 9663 + "node_modules/npm/node_modules/ci-info": { 9664 + "version": "4.3.1", 9665 + "funding": [ 9666 + { 9667 + "type": "github", 9668 + "url": "https://github.com/sponsors/sibiraj-s" 9669 + } 9670 + ], 9671 + "inBundle": true, 9672 + "license": "MIT", 9673 + "engines": { 9674 + "node": ">=8" 9675 + } 9676 + }, 9677 + "node_modules/npm/node_modules/cidr-regex": { 9678 + "version": "5.0.1", 9679 + "inBundle": true, 9680 + "license": "BSD-2-Clause", 9681 + "dependencies": { 9682 + "ip-regex": "5.0.0" 9683 + }, 9684 + "engines": { 9685 + "node": ">=20" 9686 + } 9687 + }, 9688 + "node_modules/npm/node_modules/cli-columns": { 9689 + "version": "4.0.0", 9690 + "inBundle": true, 9691 + "license": "MIT", 9692 + "dependencies": { 9693 + "string-width": "^4.2.3", 9694 + "strip-ansi": "^6.0.1" 9695 + }, 9696 + "engines": { 9697 + "node": ">= 10" 9698 + } 9699 + }, 9700 + "node_modules/npm/node_modules/cmd-shim": { 9701 + "version": "7.0.0", 9702 + "inBundle": true, 9703 + "license": "ISC", 9704 + "engines": { 9705 + "node": "^18.17.0 || >=20.5.0" 9706 + } 9707 + }, 9708 + "node_modules/npm/node_modules/color-convert": { 9709 + "version": "2.0.1", 9710 + "inBundle": true, 9711 + "license": "MIT", 9712 + "dependencies": { 9713 + "color-name": "~1.1.4" 9714 + }, 9715 + "engines": { 9716 + "node": ">=7.0.0" 9717 + } 9718 + }, 9719 + "node_modules/npm/node_modules/color-name": { 9720 + "version": "1.1.4", 9721 + "inBundle": true, 9722 + "license": "MIT" 9723 + }, 9724 + "node_modules/npm/node_modules/common-ancestor-path": { 9725 + "version": "1.0.1", 9726 + "inBundle": true, 9727 + "license": "ISC" 9728 + }, 9729 + "node_modules/npm/node_modules/cross-spawn": { 9730 + "version": "7.0.6", 9731 + "inBundle": true, 9732 + "license": "MIT", 9733 + "dependencies": { 9734 + "path-key": "^3.1.0", 9735 + "shebang-command": "^2.0.0", 9736 + "which": "^2.0.1" 9737 + }, 9738 + "engines": { 9739 + "node": ">= 8" 9740 + } 9741 + }, 9742 + "node_modules/npm/node_modules/cross-spawn/node_modules/isexe": { 9743 + "version": "2.0.0", 9744 + "inBundle": true, 9745 + "license": "ISC" 9746 + }, 9747 + "node_modules/npm/node_modules/cross-spawn/node_modules/which": { 9748 + "version": "2.0.2", 9749 + "inBundle": true, 9750 + "license": "ISC", 9751 + "dependencies": { 9752 + "isexe": "^2.0.0" 9753 + }, 9754 + "bin": { 9755 + "node-which": "bin/node-which" 9756 + }, 9757 + "engines": { 9758 + "node": ">= 8" 9759 + } 9760 + }, 9761 + "node_modules/npm/node_modules/cssesc": { 9762 + "version": "3.0.0", 9763 + "inBundle": true, 9764 + "license": "MIT", 9765 + "bin": { 9766 + "cssesc": "bin/cssesc" 9767 + }, 9768 + "engines": { 9769 + "node": ">=4" 9770 + } 9771 + }, 9772 + "node_modules/npm/node_modules/debug": { 9773 + "version": "4.4.3", 9774 + "inBundle": true, 9775 + "license": "MIT", 9776 + "dependencies": { 9777 + "ms": "^2.1.3" 9778 + }, 9779 + "engines": { 9780 + "node": ">=6.0" 9781 + }, 9782 + "peerDependenciesMeta": { 9783 + "supports-color": { 9784 + "optional": true 9785 + } 9786 + } 9787 + }, 9788 + "node_modules/npm/node_modules/diff": { 9789 + "version": "8.0.2", 9790 + "inBundle": true, 9791 + "license": "BSD-3-Clause", 9792 + "engines": { 9793 + "node": ">=0.3.1" 9794 + } 9795 + }, 9796 + "node_modules/npm/node_modules/eastasianwidth": { 9797 + "version": "0.2.0", 9798 + "inBundle": true, 9799 + "license": "MIT" 9800 + }, 9801 + "node_modules/npm/node_modules/emoji-regex": { 9802 + "version": "8.0.0", 9803 + "inBundle": true, 9804 + "license": "MIT" 9805 + }, 9806 + "node_modules/npm/node_modules/encoding": { 9807 + "version": "0.1.13", 9808 + "inBundle": true, 9809 + "license": "MIT", 9810 + "optional": true, 9811 + "dependencies": { 9812 + "iconv-lite": "^0.6.2" 9813 + } 9814 + }, 9815 + "node_modules/npm/node_modules/env-paths": { 9816 + "version": "2.2.1", 9817 + "inBundle": true, 9818 + "license": "MIT", 9819 + "engines": { 9820 + "node": ">=6" 9821 + } 9822 + }, 9823 + "node_modules/npm/node_modules/err-code": { 9824 + "version": "2.0.3", 9825 + "inBundle": true, 9826 + "license": "MIT" 9827 + }, 9828 + "node_modules/npm/node_modules/exponential-backoff": { 9829 + "version": "3.1.2", 9830 + "inBundle": true, 9831 + "license": "Apache-2.0" 9832 + }, 9833 + "node_modules/npm/node_modules/fastest-levenshtein": { 9834 + "version": "1.0.16", 9835 + "inBundle": true, 9836 + "license": "MIT", 9837 + "engines": { 9838 + "node": ">= 4.9.1" 9839 + } 9840 + }, 9841 + "node_modules/npm/node_modules/foreground-child": { 9842 + "version": "3.3.1", 9843 + "inBundle": true, 9844 + "license": "ISC", 9845 + "dependencies": { 9846 + "cross-spawn": "^7.0.6", 9847 + "signal-exit": "^4.0.1" 9848 + }, 9849 + "engines": { 9850 + "node": ">=14" 9851 + }, 9852 + "funding": { 9853 + "url": "https://github.com/sponsors/isaacs" 9854 + } 9855 + }, 9856 + "node_modules/npm/node_modules/fs-minipass": { 9857 + "version": "3.0.3", 9858 + "inBundle": true, 9859 + "license": "ISC", 9860 + "dependencies": { 9861 + "minipass": "^7.0.3" 9862 + }, 9863 + "engines": { 9864 + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" 9865 + } 9866 + }, 9867 + "node_modules/npm/node_modules/glob": { 9868 + "version": "11.0.3", 9869 + "inBundle": true, 9870 + "license": "ISC", 9871 + "dependencies": { 9872 + "foreground-child": "^3.3.1", 9873 + "jackspeak": "^4.1.1", 9874 + "minimatch": "^10.0.3", 9875 + "minipass": "^7.1.2", 9876 + "package-json-from-dist": "^1.0.0", 9877 + "path-scurry": "^2.0.0" 9878 + }, 9879 + "bin": { 9880 + "glob": "dist/esm/bin.mjs" 9881 + }, 9882 + "engines": { 9883 + "node": "20 || >=22" 9884 + }, 9885 + "funding": { 9886 + "url": "https://github.com/sponsors/isaacs" 9887 + } 9888 + }, 9889 + "node_modules/npm/node_modules/graceful-fs": { 9890 + "version": "4.2.11", 9891 + "inBundle": true, 9892 + "license": "ISC" 9893 + }, 9894 + "node_modules/npm/node_modules/hosted-git-info": { 9895 + "version": "9.0.2", 9896 + "inBundle": true, 9897 + "license": "ISC", 9898 + "dependencies": { 9899 + "lru-cache": "^11.1.0" 9900 + }, 9901 + "engines": { 9902 + "node": "^20.17.0 || >=22.9.0" 9903 + } 9904 + }, 9905 + "node_modules/npm/node_modules/http-cache-semantics": { 9906 + "version": "4.2.0", 9907 + "inBundle": true, 9908 + "license": "BSD-2-Clause" 9909 + }, 9910 + "node_modules/npm/node_modules/http-proxy-agent": { 9911 + "version": "7.0.2", 9912 + "inBundle": true, 9913 + "license": "MIT", 9914 + "dependencies": { 9915 + "agent-base": "^7.1.0", 9916 + "debug": "^4.3.4" 9917 + }, 9918 + "engines": { 9919 + "node": ">= 14" 9920 + } 9921 + }, 9922 + "node_modules/npm/node_modules/https-proxy-agent": { 9923 + "version": "7.0.6", 9924 + "inBundle": true, 9925 + "license": "MIT", 9926 + "dependencies": { 9927 + "agent-base": "^7.1.2", 9928 + "debug": "4" 9929 + }, 9930 + "engines": { 9931 + "node": ">= 14" 9932 + } 9933 + }, 9934 + "node_modules/npm/node_modules/iconv-lite": { 9935 + "version": "0.6.3", 9936 + "inBundle": true, 9937 + "license": "MIT", 9938 + "optional": true, 9939 + "dependencies": { 9940 + "safer-buffer": ">= 2.1.2 < 3.0.0" 9941 + }, 9942 + "engines": { 9943 + "node": ">=0.10.0" 9944 + } 9945 + }, 9946 + "node_modules/npm/node_modules/ignore-walk": { 9947 + "version": "8.0.0", 9948 + "inBundle": true, 9949 + "license": "ISC", 9950 + "dependencies": { 9951 + "minimatch": "^10.0.3" 9952 + }, 9953 + "engines": { 9954 + "node": "^20.17.0 || >=22.9.0" 9955 + } 9956 + }, 9957 + "node_modules/npm/node_modules/imurmurhash": { 9958 + "version": "0.1.4", 9959 + "inBundle": true, 9960 + "license": "MIT", 9961 + "engines": { 9962 + "node": ">=0.8.19" 9963 + } 9964 + }, 9965 + "node_modules/npm/node_modules/ini": { 9966 + "version": "5.0.0", 9967 + "inBundle": true, 9968 + "license": "ISC", 9969 + "engines": { 9970 + "node": "^18.17.0 || >=20.5.0" 9971 + } 9972 + }, 9973 + "node_modules/npm/node_modules/init-package-json": { 9974 + "version": "8.2.2", 9975 + "inBundle": true, 9976 + "license": "ISC", 9977 + "dependencies": { 9978 + "@npmcli/package-json": "^7.0.0", 9979 + "npm-package-arg": "^13.0.0", 9980 + "promzard": "^2.0.0", 9981 + "read": "^4.0.0", 9982 + "semver": "^7.7.2", 9983 + "validate-npm-package-license": "^3.0.4", 9984 + "validate-npm-package-name": "^6.0.2" 9985 + }, 9986 + "engines": { 9987 + "node": "^20.17.0 || >=22.9.0" 9988 + } 9989 + }, 9990 + "node_modules/npm/node_modules/ip-address": { 9991 + "version": "10.0.1", 9992 + "inBundle": true, 9993 + "license": "MIT", 9994 + "engines": { 9995 + "node": ">= 12" 9996 + } 9997 + }, 9998 + "node_modules/npm/node_modules/ip-regex": { 9999 + "version": "5.0.0", 10000 + "inBundle": true, 10001 + "license": "MIT", 10002 + "engines": { 10003 + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" 10004 + }, 10005 + "funding": { 10006 + "url": "https://github.com/sponsors/sindresorhus" 10007 + } 10008 + }, 10009 + "node_modules/npm/node_modules/is-cidr": { 10010 + "version": "6.0.1", 10011 + "inBundle": true, 10012 + "license": "BSD-2-Clause", 10013 + "dependencies": { 10014 + "cidr-regex": "5.0.1" 10015 + }, 10016 + "engines": { 10017 + "node": ">=20" 10018 + } 10019 + }, 10020 + "node_modules/npm/node_modules/is-fullwidth-code-point": { 10021 + "version": "3.0.0", 10022 + "inBundle": true, 10023 + "license": "MIT", 10024 + "engines": { 10025 + "node": ">=8" 10026 + } 10027 + }, 10028 + "node_modules/npm/node_modules/isexe": { 10029 + "version": "3.1.1", 10030 + "inBundle": true, 10031 + "license": "ISC", 10032 + "engines": { 10033 + "node": ">=16" 10034 + } 10035 + }, 10036 + "node_modules/npm/node_modules/jackspeak": { 10037 + "version": "4.1.1", 10038 + "inBundle": true, 10039 + "license": "BlueOak-1.0.0", 10040 + "dependencies": { 10041 + "@isaacs/cliui": "^8.0.2" 10042 + }, 10043 + "engines": { 10044 + "node": "20 || >=22" 10045 + }, 10046 + "funding": { 10047 + "url": "https://github.com/sponsors/isaacs" 10048 + } 10049 + }, 10050 + "node_modules/npm/node_modules/json-parse-even-better-errors": { 10051 + "version": "4.0.0", 10052 + "inBundle": true, 10053 + "license": "MIT", 10054 + "engines": { 10055 + "node": "^18.17.0 || >=20.5.0" 10056 + } 10057 + }, 10058 + "node_modules/npm/node_modules/json-stringify-nice": { 10059 + "version": "1.1.4", 10060 + "inBundle": true, 10061 + "license": "ISC", 10062 + "funding": { 10063 + "url": "https://github.com/sponsors/isaacs" 10064 + } 10065 + }, 10066 + "node_modules/npm/node_modules/jsonparse": { 10067 + "version": "1.3.1", 10068 + "engines": [ 10069 + "node >= 0.2.0" 10070 + ], 10071 + "inBundle": true, 10072 + "license": "MIT" 10073 + }, 10074 + "node_modules/npm/node_modules/just-diff": { 10075 + "version": "6.0.2", 10076 + "inBundle": true, 10077 + "license": "MIT" 10078 + }, 10079 + "node_modules/npm/node_modules/just-diff-apply": { 10080 + "version": "5.5.0", 10081 + "inBundle": true, 10082 + "license": "MIT" 10083 + }, 10084 + "node_modules/npm/node_modules/libnpmaccess": { 10085 + "version": "10.0.3", 10086 + "inBundle": true, 10087 + "license": "ISC", 10088 + "dependencies": { 10089 + "npm-package-arg": "^13.0.0", 10090 + "npm-registry-fetch": "^19.0.0" 10091 + }, 10092 + "engines": { 10093 + "node": "^20.17.0 || >=22.9.0" 10094 + } 10095 + }, 10096 + "node_modules/npm/node_modules/libnpmdiff": { 10097 + "version": "8.0.9", 10098 + "inBundle": true, 10099 + "license": "ISC", 10100 + "dependencies": { 10101 + "@npmcli/arborist": "^9.1.6", 10102 + "@npmcli/installed-package-contents": "^3.0.0", 10103 + "binary-extensions": "^3.0.0", 10104 + "diff": "^8.0.2", 10105 + "minimatch": "^10.0.3", 10106 + "npm-package-arg": "^13.0.0", 10107 + "pacote": "^21.0.2", 10108 + "tar": "^7.5.1" 10109 + }, 10110 + "engines": { 10111 + "node": "^20.17.0 || >=22.9.0" 10112 + } 10113 + }, 10114 + "node_modules/npm/node_modules/libnpmexec": { 10115 + "version": "10.1.8", 10116 + "inBundle": true, 10117 + "license": "ISC", 10118 + "dependencies": { 10119 + "@npmcli/arborist": "^9.1.6", 10120 + "@npmcli/package-json": "^7.0.0", 10121 + "@npmcli/run-script": "^10.0.0", 10122 + "ci-info": "^4.0.0", 10123 + "npm-package-arg": "^13.0.0", 10124 + "pacote": "^21.0.2", 10125 + "proc-log": "^5.0.0", 10126 + "promise-retry": "^2.0.1", 10127 + "read": "^4.0.0", 10128 + "semver": "^7.3.7", 10129 + "signal-exit": "^4.1.0", 10130 + "walk-up-path": "^4.0.0" 10131 + }, 10132 + "engines": { 10133 + "node": "^20.17.0 || >=22.9.0" 10134 + } 10135 + }, 10136 + "node_modules/npm/node_modules/libnpmfund": { 10137 + "version": "7.0.9", 10138 + "inBundle": true, 10139 + "license": "ISC", 10140 + "dependencies": { 10141 + "@npmcli/arborist": "^9.1.6" 10142 + }, 10143 + "engines": { 10144 + "node": "^20.17.0 || >=22.9.0" 10145 + } 10146 + }, 10147 + "node_modules/npm/node_modules/libnpmorg": { 10148 + "version": "8.0.1", 10149 + "inBundle": true, 10150 + "license": "ISC", 10151 + "dependencies": { 10152 + "aproba": "^2.0.0", 10153 + "npm-registry-fetch": "^19.0.0" 10154 + }, 10155 + "engines": { 10156 + "node": "^20.17.0 || >=22.9.0" 10157 + } 10158 + }, 10159 + "node_modules/npm/node_modules/libnpmpack": { 10160 + "version": "9.0.9", 10161 + "inBundle": true, 10162 + "license": "ISC", 10163 + "dependencies": { 10164 + "@npmcli/arborist": "^9.1.6", 10165 + "@npmcli/run-script": "^10.0.0", 10166 + "npm-package-arg": "^13.0.0", 10167 + "pacote": "^21.0.2" 10168 + }, 10169 + "engines": { 10170 + "node": "^20.17.0 || >=22.9.0" 10171 + } 10172 + }, 10173 + "node_modules/npm/node_modules/libnpmpublish": { 10174 + "version": "11.1.2", 10175 + "inBundle": true, 10176 + "license": "ISC", 10177 + "dependencies": { 10178 + "@npmcli/package-json": "^7.0.0", 10179 + "ci-info": "^4.0.0", 10180 + "npm-package-arg": "^13.0.0", 10181 + "npm-registry-fetch": "^19.0.0", 10182 + "proc-log": "^5.0.0", 10183 + "semver": "^7.3.7", 10184 + "sigstore": "^4.0.0", 10185 + "ssri": "^12.0.0" 10186 + }, 10187 + "engines": { 10188 + "node": "^20.17.0 || >=22.9.0" 10189 + } 10190 + }, 10191 + "node_modules/npm/node_modules/libnpmsearch": { 10192 + "version": "9.0.1", 10193 + "inBundle": true, 10194 + "license": "ISC", 10195 + "dependencies": { 10196 + "npm-registry-fetch": "^19.0.0" 10197 + }, 10198 + "engines": { 10199 + "node": "^20.17.0 || >=22.9.0" 10200 + } 10201 + }, 10202 + "node_modules/npm/node_modules/libnpmteam": { 10203 + "version": "8.0.2", 10204 + "inBundle": true, 10205 + "license": "ISC", 10206 + "dependencies": { 10207 + "aproba": "^2.0.0", 10208 + "npm-registry-fetch": "^19.0.0" 10209 + }, 10210 + "engines": { 10211 + "node": "^20.17.0 || >=22.9.0" 10212 + } 10213 + }, 10214 + "node_modules/npm/node_modules/libnpmversion": { 10215 + "version": "8.0.2", 10216 + "inBundle": true, 10217 + "license": "ISC", 10218 + "dependencies": { 10219 + "@npmcli/git": "^7.0.0", 10220 + "@npmcli/run-script": "^10.0.0", 10221 + "json-parse-even-better-errors": "^4.0.0", 10222 + "proc-log": "^5.0.0", 10223 + "semver": "^7.3.7" 10224 + }, 10225 + "engines": { 10226 + "node": "^20.17.0 || >=22.9.0" 10227 + } 10228 + }, 10229 + "node_modules/npm/node_modules/lru-cache": { 10230 + "version": "11.2.2", 10231 + "inBundle": true, 10232 + "license": "ISC", 10233 + "engines": { 10234 + "node": "20 || >=22" 10235 + } 10236 + }, 10237 + "node_modules/npm/node_modules/make-fetch-happen": { 10238 + "version": "15.0.2", 10239 + "inBundle": true, 10240 + "license": "ISC", 10241 + "dependencies": { 10242 + "@npmcli/agent": "^4.0.0", 10243 + "cacache": "^20.0.1", 10244 + "http-cache-semantics": "^4.1.1", 10245 + "minipass": "^7.0.2", 10246 + "minipass-fetch": "^4.0.0", 10247 + "minipass-flush": "^1.0.5", 10248 + "minipass-pipeline": "^1.2.4", 10249 + "negotiator": "^1.0.0", 10250 + "proc-log": "^5.0.0", 10251 + "promise-retry": "^2.0.1", 10252 + "ssri": "^12.0.0" 10253 + }, 10254 + "engines": { 10255 + "node": "^20.17.0 || >=22.9.0" 10256 + } 10257 + }, 10258 + "node_modules/npm/node_modules/minimatch": { 10259 + "version": "10.0.3", 10260 + "inBundle": true, 10261 + "license": "ISC", 10262 + "dependencies": { 10263 + "@isaacs/brace-expansion": "^5.0.0" 10264 + }, 10265 + "engines": { 10266 + "node": "20 || >=22" 10267 + }, 10268 + "funding": { 10269 + "url": "https://github.com/sponsors/isaacs" 10270 + } 10271 + }, 10272 + "node_modules/npm/node_modules/minipass": { 10273 + "version": "7.1.2", 10274 + "inBundle": true, 10275 + "license": "ISC", 10276 + "engines": { 10277 + "node": ">=16 || 14 >=14.17" 10278 + } 10279 + }, 10280 + "node_modules/npm/node_modules/minipass-collect": { 10281 + "version": "2.0.1", 10282 + "inBundle": true, 10283 + "license": "ISC", 10284 + "dependencies": { 10285 + "minipass": "^7.0.3" 10286 + }, 10287 + "engines": { 10288 + "node": ">=16 || 14 >=14.17" 10289 + } 10290 + }, 10291 + "node_modules/npm/node_modules/minipass-fetch": { 10292 + "version": "4.0.1", 10293 + "inBundle": true, 10294 + "license": "MIT", 10295 + "dependencies": { 10296 + "minipass": "^7.0.3", 10297 + "minipass-sized": "^1.0.3", 10298 + "minizlib": "^3.0.1" 10299 + }, 10300 + "engines": { 10301 + "node": "^18.17.0 || >=20.5.0" 10302 + }, 10303 + "optionalDependencies": { 10304 + "encoding": "^0.1.13" 10305 + } 10306 + }, 10307 + "node_modules/npm/node_modules/minipass-flush": { 10308 + "version": "1.0.5", 10309 + "inBundle": true, 10310 + "license": "ISC", 10311 + "dependencies": { 10312 + "minipass": "^3.0.0" 10313 + }, 10314 + "engines": { 10315 + "node": ">= 8" 10316 + } 10317 + }, 10318 + "node_modules/npm/node_modules/minipass-flush/node_modules/minipass": { 10319 + "version": "3.3.6", 10320 + "inBundle": true, 10321 + "license": "ISC", 10322 + "dependencies": { 10323 + "yallist": "^4.0.0" 10324 + }, 10325 + "engines": { 10326 + "node": ">=8" 10327 + } 10328 + }, 10329 + "node_modules/npm/node_modules/minipass-pipeline": { 10330 + "version": "1.2.4", 10331 + "inBundle": true, 10332 + "license": "ISC", 10333 + "dependencies": { 10334 + "minipass": "^3.0.0" 10335 + }, 10336 + "engines": { 10337 + "node": ">=8" 10338 + } 10339 + }, 10340 + "node_modules/npm/node_modules/minipass-pipeline/node_modules/minipass": { 10341 + "version": "3.3.6", 10342 + "inBundle": true, 10343 + "license": "ISC", 10344 + "dependencies": { 10345 + "yallist": "^4.0.0" 10346 + }, 10347 + "engines": { 10348 + "node": ">=8" 10349 + } 10350 + }, 10351 + "node_modules/npm/node_modules/minipass-sized": { 10352 + "version": "1.0.3", 10353 + "inBundle": true, 10354 + "license": "ISC", 10355 + "dependencies": { 10356 + "minipass": "^3.0.0" 10357 + }, 10358 + "engines": { 10359 + "node": ">=8" 10360 + } 10361 + }, 10362 + "node_modules/npm/node_modules/minipass-sized/node_modules/minipass": { 10363 + "version": "3.3.6", 10364 + "inBundle": true, 10365 + "license": "ISC", 10366 + "dependencies": { 10367 + "yallist": "^4.0.0" 10368 + }, 10369 + "engines": { 10370 + "node": ">=8" 10371 + } 10372 + }, 10373 + "node_modules/npm/node_modules/minizlib": { 10374 + "version": "3.1.0", 10375 + "inBundle": true, 10376 + "license": "MIT", 10377 + "dependencies": { 10378 + "minipass": "^7.1.2" 10379 + }, 10380 + "engines": { 10381 + "node": ">= 18" 10382 + } 10383 + }, 10384 + "node_modules/npm/node_modules/ms": { 10385 + "version": "2.1.3", 10386 + "inBundle": true, 10387 + "license": "MIT" 10388 + }, 10389 + "node_modules/npm/node_modules/mute-stream": { 10390 + "version": "2.0.0", 10391 + "inBundle": true, 10392 + "license": "ISC", 10393 + "engines": { 10394 + "node": "^18.17.0 || >=20.5.0" 10395 + } 10396 + }, 10397 + "node_modules/npm/node_modules/negotiator": { 10398 + "version": "1.0.0", 10399 + "inBundle": true, 10400 + "license": "MIT", 10401 + "engines": { 10402 + "node": ">= 0.6" 10403 + } 10404 + }, 10405 + "node_modules/npm/node_modules/node-gyp": { 10406 + "version": "11.4.2", 10407 + "inBundle": true, 10408 + "license": "MIT", 10409 + "dependencies": { 10410 + "env-paths": "^2.2.0", 10411 + "exponential-backoff": "^3.1.1", 10412 + "graceful-fs": "^4.2.6", 10413 + "make-fetch-happen": "^14.0.3", 10414 + "nopt": "^8.0.0", 10415 + "proc-log": "^5.0.0", 10416 + "semver": "^7.3.5", 10417 + "tar": "^7.4.3", 10418 + "tinyglobby": "^0.2.12", 10419 + "which": "^5.0.0" 10420 + }, 10421 + "bin": { 10422 + "node-gyp": "bin/node-gyp.js" 10423 + }, 10424 + "engines": { 10425 + "node": "^18.17.0 || >=20.5.0" 10426 + } 10427 + }, 10428 + "node_modules/npm/node_modules/node-gyp/node_modules/@npmcli/agent": { 10429 + "version": "3.0.0", 10430 + "inBundle": true, 10431 + "license": "ISC", 10432 + "dependencies": { 10433 + "agent-base": "^7.1.0", 10434 + "http-proxy-agent": "^7.0.0", 10435 + "https-proxy-agent": "^7.0.1", 10436 + "lru-cache": "^10.0.1", 10437 + "socks-proxy-agent": "^8.0.3" 10438 + }, 10439 + "engines": { 10440 + "node": "^18.17.0 || >=20.5.0" 10441 + } 10442 + }, 10443 + "node_modules/npm/node_modules/node-gyp/node_modules/cacache": { 10444 + "version": "19.0.1", 10445 + "inBundle": true, 10446 + "license": "ISC", 10447 + "dependencies": { 10448 + "@npmcli/fs": "^4.0.0", 10449 + "fs-minipass": "^3.0.0", 10450 + "glob": "^10.2.2", 10451 + "lru-cache": "^10.0.1", 10452 + "minipass": "^7.0.3", 10453 + "minipass-collect": "^2.0.1", 10454 + "minipass-flush": "^1.0.5", 10455 + "minipass-pipeline": "^1.2.4", 10456 + "p-map": "^7.0.2", 10457 + "ssri": "^12.0.0", 10458 + "tar": "^7.4.3", 10459 + "unique-filename": "^4.0.0" 10460 + }, 10461 + "engines": { 10462 + "node": "^18.17.0 || >=20.5.0" 10463 + } 10464 + }, 10465 + "node_modules/npm/node_modules/node-gyp/node_modules/glob": { 10466 + "version": "10.4.5", 10467 + "inBundle": true, 10468 + "license": "ISC", 10469 + "dependencies": { 10470 + "foreground-child": "^3.1.0", 10471 + "jackspeak": "^3.1.2", 10472 + "minimatch": "^9.0.4", 10473 + "minipass": "^7.1.2", 10474 + "package-json-from-dist": "^1.0.0", 10475 + "path-scurry": "^1.11.1" 10476 + }, 10477 + "bin": { 10478 + "glob": "dist/esm/bin.mjs" 10479 + }, 10480 + "funding": { 10481 + "url": "https://github.com/sponsors/isaacs" 10482 + } 10483 + }, 10484 + "node_modules/npm/node_modules/node-gyp/node_modules/jackspeak": { 10485 + "version": "3.4.3", 10486 + "inBundle": true, 10487 + "license": "BlueOak-1.0.0", 10488 + "dependencies": { 10489 + "@isaacs/cliui": "^8.0.2" 10490 + }, 10491 + "funding": { 10492 + "url": "https://github.com/sponsors/isaacs" 10493 + }, 10494 + "optionalDependencies": { 10495 + "@pkgjs/parseargs": "^0.11.0" 10496 + } 10497 + }, 10498 + "node_modules/npm/node_modules/node-gyp/node_modules/lru-cache": { 10499 + "version": "10.4.3", 10500 + "inBundle": true, 10501 + "license": "ISC" 10502 + }, 10503 + "node_modules/npm/node_modules/node-gyp/node_modules/make-fetch-happen": { 10504 + "version": "14.0.3", 10505 + "inBundle": true, 10506 + "license": "ISC", 10507 + "dependencies": { 10508 + "@npmcli/agent": "^3.0.0", 10509 + "cacache": "^19.0.1", 10510 + "http-cache-semantics": "^4.1.1", 10511 + "minipass": "^7.0.2", 10512 + "minipass-fetch": "^4.0.0", 10513 + "minipass-flush": "^1.0.5", 10514 + "minipass-pipeline": "^1.2.4", 10515 + "negotiator": "^1.0.0", 10516 + "proc-log": "^5.0.0", 10517 + "promise-retry": "^2.0.1", 10518 + "ssri": "^12.0.0" 10519 + }, 10520 + "engines": { 10521 + "node": "^18.17.0 || >=20.5.0" 10522 + } 10523 + }, 10524 + "node_modules/npm/node_modules/node-gyp/node_modules/minimatch": { 10525 + "version": "9.0.5", 10526 + "inBundle": true, 10527 + "license": "ISC", 10528 + "dependencies": { 10529 + "brace-expansion": "^2.0.1" 10530 + }, 10531 + "engines": { 10532 + "node": ">=16 || 14 >=14.17" 10533 + }, 10534 + "funding": { 10535 + "url": "https://github.com/sponsors/isaacs" 10536 + } 10537 + }, 10538 + "node_modules/npm/node_modules/node-gyp/node_modules/path-scurry": { 10539 + "version": "1.11.1", 10540 + "inBundle": true, 10541 + "license": "BlueOak-1.0.0", 10542 + "dependencies": { 10543 + "lru-cache": "^10.2.0", 10544 + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" 10545 + }, 10546 + "engines": { 10547 + "node": ">=16 || 14 >=14.18" 10548 + }, 10549 + "funding": { 10550 + "url": "https://github.com/sponsors/isaacs" 10551 + } 10552 + }, 10553 + "node_modules/npm/node_modules/nopt": { 10554 + "version": "8.1.0", 10555 + "inBundle": true, 10556 + "license": "ISC", 10557 + "dependencies": { 10558 + "abbrev": "^3.0.0" 10559 + }, 10560 + "bin": { 10561 + "nopt": "bin/nopt.js" 10562 + }, 10563 + "engines": { 10564 + "node": "^18.17.0 || >=20.5.0" 10565 + } 10566 + }, 10567 + "node_modules/npm/node_modules/npm-audit-report": { 10568 + "version": "6.0.0", 10569 + "inBundle": true, 10570 + "license": "ISC", 10571 + "engines": { 10572 + "node": "^18.17.0 || >=20.5.0" 10573 + } 10574 + }, 10575 + "node_modules/npm/node_modules/npm-bundled": { 10576 + "version": "4.0.0", 10577 + "inBundle": true, 10578 + "license": "ISC", 10579 + "dependencies": { 10580 + "npm-normalize-package-bin": "^4.0.0" 10581 + }, 10582 + "engines": { 10583 + "node": "^18.17.0 || >=20.5.0" 10584 + } 10585 + }, 10586 + "node_modules/npm/node_modules/npm-install-checks": { 10587 + "version": "7.1.2", 10588 + "inBundle": true, 10589 + "license": "BSD-2-Clause", 10590 + "dependencies": { 10591 + "semver": "^7.1.1" 10592 + }, 10593 + "engines": { 10594 + "node": "^18.17.0 || >=20.5.0" 10595 + } 10596 + }, 10597 + "node_modules/npm/node_modules/npm-normalize-package-bin": { 10598 + "version": "4.0.0", 10599 + "inBundle": true, 10600 + "license": "ISC", 10601 + "engines": { 10602 + "node": "^18.17.0 || >=20.5.0" 10603 + } 10604 + }, 10605 + "node_modules/npm/node_modules/npm-package-arg": { 10606 + "version": "13.0.1", 10607 + "inBundle": true, 10608 + "license": "ISC", 10609 + "dependencies": { 10610 + "hosted-git-info": "^9.0.0", 10611 + "proc-log": "^5.0.0", 10612 + "semver": "^7.3.5", 10613 + "validate-npm-package-name": "^6.0.0" 10614 + }, 10615 + "engines": { 10616 + "node": "^20.17.0 || >=22.9.0" 10617 + } 10618 + }, 10619 + "node_modules/npm/node_modules/npm-packlist": { 10620 + "version": "10.0.2", 10621 + "inBundle": true, 10622 + "license": "ISC", 10623 + "dependencies": { 10624 + "ignore-walk": "^8.0.0", 10625 + "proc-log": "^5.0.0" 10626 + }, 10627 + "engines": { 10628 + "node": "^20.17.0 || >=22.9.0" 10629 + } 10630 + }, 10631 + "node_modules/npm/node_modules/npm-pick-manifest": { 10632 + "version": "11.0.1", 10633 + "inBundle": true, 10634 + "license": "ISC", 10635 + "dependencies": { 10636 + "npm-install-checks": "^7.1.0", 10637 + "npm-normalize-package-bin": "^4.0.0", 10638 + "npm-package-arg": "^13.0.0", 10639 + "semver": "^7.3.5" 10640 + }, 10641 + "engines": { 10642 + "node": "^20.17.0 || >=22.9.0" 10643 + } 10644 + }, 10645 + "node_modules/npm/node_modules/npm-profile": { 10646 + "version": "12.0.0", 10647 + "inBundle": true, 10648 + "license": "ISC", 10649 + "dependencies": { 10650 + "npm-registry-fetch": "^19.0.0", 10651 + "proc-log": "^5.0.0" 10652 + }, 10653 + "engines": { 10654 + "node": "^20.17.0 || >=22.9.0" 10655 + } 10656 + }, 10657 + "node_modules/npm/node_modules/npm-registry-fetch": { 10658 + "version": "19.0.0", 10659 + "inBundle": true, 10660 + "license": "ISC", 10661 + "dependencies": { 10662 + "@npmcli/redact": "^3.0.0", 10663 + "jsonparse": "^1.3.1", 10664 + "make-fetch-happen": "^15.0.0", 10665 + "minipass": "^7.0.2", 10666 + "minipass-fetch": "^4.0.0", 10667 + "minizlib": "^3.0.1", 10668 + "npm-package-arg": "^13.0.0", 10669 + "proc-log": "^5.0.0" 10670 + }, 10671 + "engines": { 10672 + "node": "^20.17.0 || >=22.9.0" 10673 + } 10674 + }, 10675 + "node_modules/npm/node_modules/npm-user-validate": { 10676 + "version": "3.0.0", 10677 + "inBundle": true, 10678 + "license": "BSD-2-Clause", 10679 + "engines": { 10680 + "node": "^18.17.0 || >=20.5.0" 10681 + } 10682 + }, 10683 + "node_modules/npm/node_modules/p-map": { 10684 + "version": "7.0.3", 10685 + "inBundle": true, 10686 + "license": "MIT", 10687 + "engines": { 10688 + "node": ">=18" 10689 + }, 10690 + "funding": { 10691 + "url": "https://github.com/sponsors/sindresorhus" 10692 + } 10693 + }, 10694 + "node_modules/npm/node_modules/package-json-from-dist": { 10695 + "version": "1.0.1", 10696 + "inBundle": true, 10697 + "license": "BlueOak-1.0.0" 10698 + }, 10699 + "node_modules/npm/node_modules/pacote": { 10700 + "version": "21.0.3", 10701 + "inBundle": true, 10702 + "license": "ISC", 10703 + "dependencies": { 10704 + "@npmcli/git": "^7.0.0", 10705 + "@npmcli/installed-package-contents": "^3.0.0", 10706 + "@npmcli/package-json": "^7.0.0", 10707 + "@npmcli/promise-spawn": "^8.0.0", 10708 + "@npmcli/run-script": "^10.0.0", 10709 + "cacache": "^20.0.0", 10710 + "fs-minipass": "^3.0.0", 10711 + "minipass": "^7.0.2", 10712 + "npm-package-arg": "^13.0.0", 10713 + "npm-packlist": "^10.0.1", 10714 + "npm-pick-manifest": "^11.0.1", 10715 + "npm-registry-fetch": "^19.0.0", 10716 + "proc-log": "^5.0.0", 10717 + "promise-retry": "^2.0.1", 10718 + "sigstore": "^4.0.0", 10719 + "ssri": "^12.0.0", 10720 + "tar": "^7.4.3" 10721 + }, 10722 + "bin": { 10723 + "pacote": "bin/index.js" 10724 + }, 10725 + "engines": { 10726 + "node": "^20.17.0 || >=22.9.0" 10727 + } 10728 + }, 10729 + "node_modules/npm/node_modules/parse-conflict-json": { 10730 + "version": "4.0.0", 10731 + "inBundle": true, 10732 + "license": "ISC", 10733 + "dependencies": { 10734 + "json-parse-even-better-errors": "^4.0.0", 10735 + "just-diff": "^6.0.0", 10736 + "just-diff-apply": "^5.2.0" 10737 + }, 10738 + "engines": { 10739 + "node": "^18.17.0 || >=20.5.0" 10740 + } 10741 + }, 10742 + "node_modules/npm/node_modules/path-key": { 10743 + "version": "3.1.1", 10744 + "inBundle": true, 10745 + "license": "MIT", 10746 + "engines": { 10747 + "node": ">=8" 10748 + } 10749 + }, 10750 + "node_modules/npm/node_modules/path-scurry": { 10751 + "version": "2.0.0", 10752 + "inBundle": true, 10753 + "license": "BlueOak-1.0.0", 10754 + "dependencies": { 10755 + "lru-cache": "^11.0.0", 10756 + "minipass": "^7.1.2" 10757 + }, 10758 + "engines": { 10759 + "node": "20 || >=22" 10760 + }, 10761 + "funding": { 10762 + "url": "https://github.com/sponsors/isaacs" 10763 + } 10764 + }, 10765 + "node_modules/npm/node_modules/postcss-selector-parser": { 10766 + "version": "7.1.0", 10767 + "inBundle": true, 10768 + "license": "MIT", 10769 + "dependencies": { 10770 + "cssesc": "^3.0.0", 10771 + "util-deprecate": "^1.0.2" 10772 + }, 10773 + "engines": { 10774 + "node": ">=4" 10775 + } 10776 + }, 10777 + "node_modules/npm/node_modules/proc-log": { 10778 + "version": "5.0.0", 10779 + "inBundle": true, 10780 + "license": "ISC", 10781 + "engines": { 10782 + "node": "^18.17.0 || >=20.5.0" 10783 + } 10784 + }, 10785 + "node_modules/npm/node_modules/proggy": { 10786 + "version": "3.0.0", 10787 + "inBundle": true, 10788 + "license": "ISC", 10789 + "engines": { 10790 + "node": "^18.17.0 || >=20.5.0" 10791 + } 10792 + }, 10793 + "node_modules/npm/node_modules/promise-all-reject-late": { 10794 + "version": "1.0.1", 10795 + "inBundle": true, 10796 + "license": "ISC", 10797 + "funding": { 10798 + "url": "https://github.com/sponsors/isaacs" 10799 + } 10800 + }, 10801 + "node_modules/npm/node_modules/promise-call-limit": { 10802 + "version": "3.0.2", 10803 + "inBundle": true, 10804 + "license": "ISC", 10805 + "funding": { 10806 + "url": "https://github.com/sponsors/isaacs" 10807 + } 10808 + }, 10809 + "node_modules/npm/node_modules/promise-retry": { 10810 + "version": "2.0.1", 10811 + "inBundle": true, 10812 + "license": "MIT", 10813 + "dependencies": { 10814 + "err-code": "^2.0.2", 10815 + "retry": "^0.12.0" 10816 + }, 10817 + "engines": { 10818 + "node": ">=10" 10819 + } 10820 + }, 10821 + "node_modules/npm/node_modules/promzard": { 10822 + "version": "2.0.0", 10823 + "inBundle": true, 10824 + "license": "ISC", 10825 + "dependencies": { 10826 + "read": "^4.0.0" 10827 + }, 10828 + "engines": { 10829 + "node": "^18.17.0 || >=20.5.0" 10830 + } 10831 + }, 10832 + "node_modules/npm/node_modules/qrcode-terminal": { 10833 + "version": "0.12.0", 10834 + "inBundle": true, 10835 + "bin": { 10836 + "qrcode-terminal": "bin/qrcode-terminal.js" 10837 + } 10838 + }, 10839 + "node_modules/npm/node_modules/read": { 10840 + "version": "4.1.0", 10841 + "inBundle": true, 10842 + "license": "ISC", 10843 + "dependencies": { 10844 + "mute-stream": "^2.0.0" 10845 + }, 10846 + "engines": { 10847 + "node": "^18.17.0 || >=20.5.0" 10848 + } 10849 + }, 10850 + "node_modules/npm/node_modules/read-cmd-shim": { 10851 + "version": "5.0.0", 10852 + "inBundle": true, 10853 + "license": "ISC", 10854 + "engines": { 10855 + "node": "^18.17.0 || >=20.5.0" 10856 + } 10857 + }, 10858 + "node_modules/npm/node_modules/retry": { 10859 + "version": "0.12.0", 10860 + "inBundle": true, 10861 + "license": "MIT", 10862 + "engines": { 10863 + "node": ">= 4" 10864 + } 10865 + }, 10866 + "node_modules/npm/node_modules/safer-buffer": { 10867 + "version": "2.1.2", 10868 + "inBundle": true, 10869 + "license": "MIT", 10870 + "optional": true 10871 + }, 10872 + "node_modules/npm/node_modules/semver": { 10873 + "version": "7.7.3", 10874 + "inBundle": true, 10875 + "license": "ISC", 10876 + "bin": { 10877 + "semver": "bin/semver.js" 10878 + }, 10879 + "engines": { 10880 + "node": ">=10" 10881 + } 10882 + }, 10883 + "node_modules/npm/node_modules/shebang-command": { 10884 + "version": "2.0.0", 10885 + "inBundle": true, 10886 + "license": "MIT", 10887 + "dependencies": { 10888 + "shebang-regex": "^3.0.0" 10889 + }, 10890 + "engines": { 10891 + "node": ">=8" 10892 + } 10893 + }, 10894 + "node_modules/npm/node_modules/shebang-regex": { 10895 + "version": "3.0.0", 10896 + "inBundle": true, 10897 + "license": "MIT", 10898 + "engines": { 10899 + "node": ">=8" 10900 + } 10901 + }, 10902 + "node_modules/npm/node_modules/signal-exit": { 10903 + "version": "4.1.0", 10904 + "inBundle": true, 10905 + "license": "ISC", 10906 + "engines": { 10907 + "node": ">=14" 10908 + }, 10909 + "funding": { 10910 + "url": "https://github.com/sponsors/isaacs" 10911 + } 10912 + }, 10913 + "node_modules/npm/node_modules/sigstore": { 10914 + "version": "4.0.0", 10915 + "inBundle": true, 10916 + "license": "Apache-2.0", 10917 + "dependencies": { 10918 + "@sigstore/bundle": "^4.0.0", 10919 + "@sigstore/core": "^3.0.0", 10920 + "@sigstore/protobuf-specs": "^0.5.0", 10921 + "@sigstore/sign": "^4.0.0", 10922 + "@sigstore/tuf": "^4.0.0", 10923 + "@sigstore/verify": "^3.0.0" 10924 + }, 10925 + "engines": { 10926 + "node": "^20.17.0 || >=22.9.0" 10927 + } 10928 + }, 10929 + "node_modules/npm/node_modules/smart-buffer": { 10930 + "version": "4.2.0", 10931 + "inBundle": true, 10932 + "license": "MIT", 10933 + "engines": { 10934 + "node": ">= 6.0.0", 10935 + "npm": ">= 3.0.0" 10936 + } 10937 + }, 10938 + "node_modules/npm/node_modules/socks": { 10939 + "version": "2.8.7", 10940 + "inBundle": true, 10941 + "license": "MIT", 10942 + "dependencies": { 10943 + "ip-address": "^10.0.1", 10944 + "smart-buffer": "^4.2.0" 10945 + }, 10946 + "engines": { 10947 + "node": ">= 10.0.0", 10948 + "npm": ">= 3.0.0" 10949 + } 10950 + }, 10951 + "node_modules/npm/node_modules/socks-proxy-agent": { 10952 + "version": "8.0.5", 10953 + "inBundle": true, 10954 + "license": "MIT", 10955 + "dependencies": { 10956 + "agent-base": "^7.1.2", 10957 + "debug": "^4.3.4", 10958 + "socks": "^2.8.3" 10959 + }, 10960 + "engines": { 10961 + "node": ">= 14" 10962 + } 10963 + }, 10964 + "node_modules/npm/node_modules/spdx-correct": { 10965 + "version": "3.2.0", 10966 + "inBundle": true, 10967 + "license": "Apache-2.0", 10968 + "dependencies": { 10969 + "spdx-expression-parse": "^3.0.0", 10970 + "spdx-license-ids": "^3.0.0" 10971 + } 10972 + }, 10973 + "node_modules/npm/node_modules/spdx-correct/node_modules/spdx-expression-parse": { 10974 + "version": "3.0.1", 10975 + "inBundle": true, 10976 + "license": "MIT", 10977 + "dependencies": { 10978 + "spdx-exceptions": "^2.1.0", 10979 + "spdx-license-ids": "^3.0.0" 10980 + } 10981 + }, 10982 + "node_modules/npm/node_modules/spdx-exceptions": { 10983 + "version": "2.5.0", 10984 + "inBundle": true, 10985 + "license": "CC-BY-3.0" 10986 + }, 10987 + "node_modules/npm/node_modules/spdx-expression-parse": { 10988 + "version": "4.0.0", 10989 + "inBundle": true, 10990 + "license": "MIT", 10991 + "dependencies": { 10992 + "spdx-exceptions": "^2.1.0", 10993 + "spdx-license-ids": "^3.0.0" 10994 + } 10995 + }, 10996 + "node_modules/npm/node_modules/spdx-license-ids": { 10997 + "version": "3.0.22", 10998 + "inBundle": true, 10999 + "license": "CC0-1.0" 11000 + }, 11001 + "node_modules/npm/node_modules/ssri": { 11002 + "version": "12.0.0", 11003 + "inBundle": true, 11004 + "license": "ISC", 11005 + "dependencies": { 11006 + "minipass": "^7.0.3" 11007 + }, 11008 + "engines": { 11009 + "node": "^18.17.0 || >=20.5.0" 11010 + } 11011 + }, 11012 + "node_modules/npm/node_modules/string-width": { 11013 + "version": "4.2.3", 11014 + "inBundle": true, 11015 + "license": "MIT", 11016 + "dependencies": { 11017 + "emoji-regex": "^8.0.0", 11018 + "is-fullwidth-code-point": "^3.0.0", 11019 + "strip-ansi": "^6.0.1" 11020 + }, 11021 + "engines": { 11022 + "node": ">=8" 11023 + } 11024 + }, 11025 + "node_modules/npm/node_modules/string-width-cjs": { 11026 + "name": "string-width", 11027 + "version": "4.2.3", 11028 + "inBundle": true, 11029 + "license": "MIT", 11030 + "dependencies": { 11031 + "emoji-regex": "^8.0.0", 11032 + "is-fullwidth-code-point": "^3.0.0", 11033 + "strip-ansi": "^6.0.1" 11034 + }, 11035 + "engines": { 11036 + "node": ">=8" 11037 + } 11038 + }, 11039 + "node_modules/npm/node_modules/strip-ansi": { 11040 + "version": "6.0.1", 11041 + "inBundle": true, 11042 + "license": "MIT", 11043 + "dependencies": { 11044 + "ansi-regex": "^5.0.1" 11045 + }, 11046 + "engines": { 11047 + "node": ">=8" 11048 + } 11049 + }, 11050 + "node_modules/npm/node_modules/strip-ansi-cjs": { 11051 + "name": "strip-ansi", 11052 + "version": "6.0.1", 11053 + "inBundle": true, 11054 + "license": "MIT", 11055 + "dependencies": { 11056 + "ansi-regex": "^5.0.1" 11057 + }, 11058 + "engines": { 11059 + "node": ">=8" 11060 + } 11061 + }, 11062 + "node_modules/npm/node_modules/supports-color": { 11063 + "version": "10.2.2", 11064 + "inBundle": true, 11065 + "license": "MIT", 11066 + "engines": { 11067 + "node": ">=18" 11068 + }, 11069 + "funding": { 11070 + "url": "https://github.com/chalk/supports-color?sponsor=1" 11071 + } 11072 + }, 11073 + "node_modules/npm/node_modules/tar": { 11074 + "version": "7.5.1", 11075 + "inBundle": true, 11076 + "license": "ISC", 11077 + "dependencies": { 11078 + "@isaacs/fs-minipass": "^4.0.0", 11079 + "chownr": "^3.0.0", 11080 + "minipass": "^7.1.2", 11081 + "minizlib": "^3.1.0", 11082 + "yallist": "^5.0.0" 11083 + }, 11084 + "engines": { 11085 + "node": ">=18" 11086 + } 11087 + }, 11088 + "node_modules/npm/node_modules/tar/node_modules/yallist": { 11089 + "version": "5.0.0", 11090 + "inBundle": true, 11091 + "license": "BlueOak-1.0.0", 11092 + "engines": { 11093 + "node": ">=18" 11094 + } 11095 + }, 11096 + "node_modules/npm/node_modules/text-table": { 11097 + "version": "0.2.0", 11098 + "inBundle": true, 11099 + "license": "MIT" 11100 + }, 11101 + "node_modules/npm/node_modules/tiny-relative-date": { 11102 + "version": "2.0.2", 11103 + "inBundle": true, 11104 + "license": "MIT" 11105 + }, 11106 + "node_modules/npm/node_modules/tinyglobby": { 11107 + "version": "0.2.15", 11108 + "inBundle": true, 11109 + "license": "MIT", 11110 + "dependencies": { 11111 + "fdir": "^6.5.0", 11112 + "picomatch": "^4.0.3" 11113 + }, 11114 + "engines": { 11115 + "node": ">=12.0.0" 11116 + }, 11117 + "funding": { 11118 + "url": "https://github.com/sponsors/SuperchupuDev" 11119 + } 11120 + }, 11121 + "node_modules/npm/node_modules/tinyglobby/node_modules/fdir": { 11122 + "version": "6.5.0", 11123 + "inBundle": true, 11124 + "license": "MIT", 11125 + "engines": { 11126 + "node": ">=12.0.0" 11127 + }, 11128 + "peerDependencies": { 11129 + "picomatch": "^3 || ^4" 11130 + }, 11131 + "peerDependenciesMeta": { 11132 + "picomatch": { 11133 + "optional": true 11134 + } 11135 + } 11136 + }, 11137 + "node_modules/npm/node_modules/tinyglobby/node_modules/picomatch": { 11138 + "version": "4.0.3", 11139 + "inBundle": true, 11140 + "license": "MIT", 11141 + "engines": { 11142 + "node": ">=12" 11143 + }, 11144 + "funding": { 11145 + "url": "https://github.com/sponsors/jonschlinkert" 11146 + } 11147 + }, 11148 + "node_modules/npm/node_modules/treeverse": { 11149 + "version": "3.0.0", 11150 + "inBundle": true, 11151 + "license": "ISC", 11152 + "engines": { 11153 + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" 11154 + } 11155 + }, 11156 + "node_modules/npm/node_modules/tuf-js": { 11157 + "version": "4.0.0", 11158 + "inBundle": true, 11159 + "license": "MIT", 11160 + "dependencies": { 11161 + "@tufjs/models": "4.0.0", 11162 + "debug": "^4.4.1", 11163 + "make-fetch-happen": "^15.0.0" 11164 + }, 11165 + "engines": { 11166 + "node": "^20.17.0 || >=22.9.0" 11167 + } 11168 + }, 11169 + "node_modules/npm/node_modules/unique-filename": { 11170 + "version": "4.0.0", 11171 + "inBundle": true, 11172 + "license": "ISC", 11173 + "dependencies": { 11174 + "unique-slug": "^5.0.0" 11175 + }, 11176 + "engines": { 11177 + "node": "^18.17.0 || >=20.5.0" 11178 + } 11179 + }, 11180 + "node_modules/npm/node_modules/unique-slug": { 11181 + "version": "5.0.0", 11182 + "inBundle": true, 11183 + "license": "ISC", 11184 + "dependencies": { 11185 + "imurmurhash": "^0.1.4" 11186 + }, 11187 + "engines": { 11188 + "node": "^18.17.0 || >=20.5.0" 11189 + } 11190 + }, 11191 + "node_modules/npm/node_modules/util-deprecate": { 11192 + "version": "1.0.2", 11193 + "inBundle": true, 11194 + "license": "MIT" 11195 + }, 11196 + "node_modules/npm/node_modules/validate-npm-package-license": { 11197 + "version": "3.0.4", 11198 + "inBundle": true, 11199 + "license": "Apache-2.0", 11200 + "dependencies": { 11201 + "spdx-correct": "^3.0.0", 11202 + "spdx-expression-parse": "^3.0.0" 11203 + } 11204 + }, 11205 + "node_modules/npm/node_modules/validate-npm-package-license/node_modules/spdx-expression-parse": { 11206 + "version": "3.0.1", 11207 + "inBundle": true, 11208 + "license": "MIT", 11209 + "dependencies": { 11210 + "spdx-exceptions": "^2.1.0", 11211 + "spdx-license-ids": "^3.0.0" 11212 + } 11213 + }, 11214 + "node_modules/npm/node_modules/validate-npm-package-name": { 11215 + "version": "6.0.2", 11216 + "inBundle": true, 11217 + "license": "ISC", 11218 + "engines": { 11219 + "node": "^18.17.0 || >=20.5.0" 11220 + } 11221 + }, 11222 + "node_modules/npm/node_modules/walk-up-path": { 11223 + "version": "4.0.0", 11224 + "inBundle": true, 11225 + "license": "ISC", 11226 + "engines": { 11227 + "node": "20 || >=22" 11228 + } 11229 + }, 11230 + "node_modules/npm/node_modules/which": { 11231 + "version": "5.0.0", 11232 + "inBundle": true, 11233 + "license": "ISC", 11234 + "dependencies": { 11235 + "isexe": "^3.1.1" 11236 + }, 11237 + "bin": { 11238 + "node-which": "bin/which.js" 11239 + }, 11240 + "engines": { 11241 + "node": "^18.17.0 || >=20.5.0" 11242 + } 11243 + }, 11244 + "node_modules/npm/node_modules/wrap-ansi": { 11245 + "version": "8.1.0", 11246 + "inBundle": true, 11247 + "license": "MIT", 11248 + "dependencies": { 11249 + "ansi-styles": "^6.1.0", 11250 + "string-width": "^5.0.1", 11251 + "strip-ansi": "^7.0.1" 11252 + }, 11253 + "engines": { 11254 + "node": ">=12" 11255 + }, 11256 + "funding": { 11257 + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" 11258 + } 11259 + }, 11260 + "node_modules/npm/node_modules/wrap-ansi-cjs": { 11261 + "name": "wrap-ansi", 11262 + "version": "7.0.0", 11263 + "inBundle": true, 11264 + "license": "MIT", 11265 + "dependencies": { 11266 + "ansi-styles": "^4.0.0", 11267 + "string-width": "^4.1.0", 11268 + "strip-ansi": "^6.0.0" 11269 + }, 11270 + "engines": { 11271 + "node": ">=10" 11272 + }, 11273 + "funding": { 11274 + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" 11275 + } 11276 + }, 11277 + "node_modules/npm/node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { 11278 + "version": "4.3.0", 11279 + "inBundle": true, 11280 + "license": "MIT", 11281 + "dependencies": { 11282 + "color-convert": "^2.0.1" 11283 + }, 11284 + "engines": { 11285 + "node": ">=8" 11286 + }, 11287 + "funding": { 11288 + "url": "https://github.com/chalk/ansi-styles?sponsor=1" 11289 + } 11290 + }, 11291 + "node_modules/npm/node_modules/wrap-ansi/node_modules/ansi-regex": { 11292 + "version": "6.2.2", 11293 + "inBundle": true, 11294 + "license": "MIT", 11295 + "engines": { 11296 + "node": ">=12" 11297 + }, 11298 + "funding": { 11299 + "url": "https://github.com/chalk/ansi-regex?sponsor=1" 11300 + } 11301 + }, 11302 + "node_modules/npm/node_modules/wrap-ansi/node_modules/emoji-regex": { 11303 + "version": "9.2.2", 11304 + "inBundle": true, 11305 + "license": "MIT" 11306 + }, 11307 + "node_modules/npm/node_modules/wrap-ansi/node_modules/string-width": { 11308 + "version": "5.1.2", 11309 + "inBundle": true, 11310 + "license": "MIT", 11311 + "dependencies": { 11312 + "eastasianwidth": "^0.2.0", 11313 + "emoji-regex": "^9.2.2", 11314 + "strip-ansi": "^7.0.1" 11315 + }, 11316 + "engines": { 11317 + "node": ">=12" 11318 + }, 11319 + "funding": { 11320 + "url": "https://github.com/sponsors/sindresorhus" 11321 + } 11322 + }, 11323 + "node_modules/npm/node_modules/wrap-ansi/node_modules/strip-ansi": { 11324 + "version": "7.1.2", 11325 + "inBundle": true, 11326 + "license": "MIT", 11327 + "dependencies": { 11328 + "ansi-regex": "^6.0.1" 11329 + }, 11330 + "engines": { 11331 + "node": ">=12" 11332 + }, 11333 + "funding": { 11334 + "url": "https://github.com/chalk/strip-ansi?sponsor=1" 11335 + } 11336 + }, 11337 + "node_modules/npm/node_modules/write-file-atomic": { 11338 + "version": "6.0.0", 11339 + "inBundle": true, 11340 + "license": "ISC", 11341 + "dependencies": { 11342 + "imurmurhash": "^0.1.4", 11343 + "signal-exit": "^4.0.1" 11344 + }, 11345 + "engines": { 11346 + "node": "^18.17.0 || >=20.5.0" 11347 + } 11348 + }, 11349 + "node_modules/npm/node_modules/yallist": { 11350 + "version": "4.0.0", 11351 + "inBundle": true, 11352 + "license": "ISC" 11353 + }, 3830 11354 "node_modules/nwsapi": { 3831 11355 "version": "2.2.21", 3832 11356 "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.21.tgz", ··· 3843 11367 "node": ">=0.10.0" 3844 11368 } 3845 11369 }, 11370 + "node_modules/object-inspect": { 11371 + "version": "1.13.4", 11372 + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", 11373 + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", 11374 + "dev": true, 11375 + "license": "MIT", 11376 + "engines": { 11377 + "node": ">= 0.4" 11378 + }, 11379 + "funding": { 11380 + "url": "https://github.com/sponsors/ljharb" 11381 + } 11382 + }, 11383 + "node_modules/object-keys": { 11384 + "version": "1.1.1", 11385 + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", 11386 + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", 11387 + "dev": true, 11388 + "license": "MIT", 11389 + "engines": { 11390 + "node": ">= 0.4" 11391 + } 11392 + }, 11393 + "node_modules/object.assign": { 11394 + "version": "4.1.7", 11395 + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", 11396 + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", 11397 + "dev": true, 11398 + "license": "MIT", 11399 + "dependencies": { 11400 + "call-bind": "^1.0.8", 11401 + "call-bound": "^1.0.3", 11402 + "define-properties": "^1.2.1", 11403 + "es-object-atoms": "^1.0.0", 11404 + "has-symbols": "^1.1.0", 11405 + "object-keys": "^1.1.1" 11406 + }, 11407 + "engines": { 11408 + "node": ">= 0.4" 11409 + }, 11410 + "funding": { 11411 + "url": "https://github.com/sponsors/ljharb" 11412 + } 11413 + }, 11414 + "node_modules/object.entries": { 11415 + "version": "1.1.9", 11416 + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz", 11417 + "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==", 11418 + "dev": true, 11419 + "license": "MIT", 11420 + "dependencies": { 11421 + "call-bind": "^1.0.8", 11422 + "call-bound": "^1.0.4", 11423 + "define-properties": "^1.2.1", 11424 + "es-object-atoms": "^1.1.1" 11425 + }, 11426 + "engines": { 11427 + "node": ">= 0.4" 11428 + } 11429 + }, 11430 + "node_modules/object.fromentries": { 11431 + "version": "2.0.8", 11432 + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", 11433 + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", 11434 + "dev": true, 11435 + "license": "MIT", 11436 + "dependencies": { 11437 + "call-bind": "^1.0.7", 11438 + "define-properties": "^1.2.1", 11439 + "es-abstract": "^1.23.2", 11440 + "es-object-atoms": "^1.0.0" 11441 + }, 11442 + "engines": { 11443 + "node": ">= 0.4" 11444 + }, 11445 + "funding": { 11446 + "url": "https://github.com/sponsors/ljharb" 11447 + } 11448 + }, 11449 + "node_modules/object.values": { 11450 + "version": "1.2.1", 11451 + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", 11452 + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", 11453 + "dev": true, 11454 + "license": "MIT", 11455 + "dependencies": { 11456 + "call-bind": "^1.0.8", 11457 + "call-bound": "^1.0.3", 11458 + "define-properties": "^1.2.1", 11459 + "es-object-atoms": "^1.0.0" 11460 + }, 11461 + "engines": { 11462 + "node": ">= 0.4" 11463 + }, 11464 + "funding": { 11465 + "url": "https://github.com/sponsors/ljharb" 11466 + } 11467 + }, 11468 + "node_modules/optionator": { 11469 + "version": "0.9.4", 11470 + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", 11471 + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", 11472 + "dev": true, 11473 + "license": "MIT", 11474 + "peer": true, 11475 + "dependencies": { 11476 + "deep-is": "^0.1.3", 11477 + "fast-levenshtein": "^2.0.6", 11478 + "levn": "^0.4.1", 11479 + "prelude-ls": "^1.2.1", 11480 + "type-check": "^0.4.0", 11481 + "word-wrap": "^1.2.5" 11482 + }, 11483 + "engines": { 11484 + "node": ">= 0.8.0" 11485 + } 11486 + }, 11487 + "node_modules/own-keys": { 11488 + "version": "1.0.1", 11489 + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", 11490 + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", 11491 + "dev": true, 11492 + "license": "MIT", 11493 + "dependencies": { 11494 + "get-intrinsic": "^1.2.6", 11495 + "object-keys": "^1.1.1", 11496 + "safe-push-apply": "^1.0.0" 11497 + }, 11498 + "engines": { 11499 + "node": ">= 0.4" 11500 + }, 11501 + "funding": { 11502 + "url": "https://github.com/sponsors/ljharb" 11503 + } 11504 + }, 11505 + "node_modules/p-limit": { 11506 + "version": "3.1.0", 11507 + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", 11508 + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", 11509 + "dev": true, 11510 + "license": "MIT", 11511 + "peer": true, 11512 + "dependencies": { 11513 + "yocto-queue": "^0.1.0" 11514 + }, 11515 + "engines": { 11516 + "node": ">=10" 11517 + }, 11518 + "funding": { 11519 + "url": "https://github.com/sponsors/sindresorhus" 11520 + } 11521 + }, 11522 + "node_modules/p-locate": { 11523 + "version": "5.0.0", 11524 + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", 11525 + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", 11526 + "dev": true, 11527 + "license": "MIT", 11528 + "peer": true, 11529 + "dependencies": { 11530 + "p-limit": "^3.0.2" 11531 + }, 11532 + "engines": { 11533 + "node": ">=10" 11534 + }, 11535 + "funding": { 11536 + "url": "https://github.com/sponsors/sindresorhus" 11537 + } 11538 + }, 11539 + "node_modules/package-manager-detector": { 11540 + "version": "1.4.1", 11541 + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.4.1.tgz", 11542 + "integrity": "sha512-dSMiVLBEA4XaNJ0PRb4N5cV/SEP4BWrWZKBmfF+OUm2pQTiZ6DDkKeWaltwu3JRhLoy59ayIkJ00cx9K9CaYTg==", 11543 + "dev": true, 11544 + "license": "MIT" 11545 + }, 11546 + "node_modules/parent-module": { 11547 + "version": "1.0.1", 11548 + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", 11549 + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", 11550 + "dev": true, 11551 + "license": "MIT", 11552 + "dependencies": { 11553 + "callsites": "^3.0.0" 11554 + }, 11555 + "engines": { 11556 + "node": ">=6" 11557 + } 11558 + }, 11559 + "node_modules/parse-json": { 11560 + "version": "5.2.0", 11561 + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", 11562 + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", 11563 + "dev": true, 11564 + "license": "MIT", 11565 + "dependencies": { 11566 + "@babel/code-frame": "^7.0.0", 11567 + "error-ex": "^1.3.1", 11568 + "json-parse-even-better-errors": "^2.3.0", 11569 + "lines-and-columns": "^1.1.6" 11570 + }, 11571 + "engines": { 11572 + "node": ">=8" 11573 + }, 11574 + "funding": { 11575 + "url": "https://github.com/sponsors/sindresorhus" 11576 + } 11577 + }, 3846 11578 "node_modules/parse5": { 3847 11579 "version": "7.3.0", 3848 11580 "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", ··· 3862 11594 "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", 3863 11595 "license": "MIT" 3864 11596 }, 11597 + "node_modules/path-exists": { 11598 + "version": "4.0.0", 11599 + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", 11600 + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", 11601 + "dev": true, 11602 + "license": "MIT", 11603 + "peer": true, 11604 + "engines": { 11605 + "node": ">=8" 11606 + } 11607 + }, 11608 + "node_modules/path-key": { 11609 + "version": "3.1.1", 11610 + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", 11611 + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", 11612 + "dev": true, 11613 + "license": "MIT", 11614 + "peer": true, 11615 + "engines": { 11616 + "node": ">=8" 11617 + } 11618 + }, 11619 + "node_modules/path-parse": { 11620 + "version": "1.0.7", 11621 + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 11622 + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 11623 + "dev": true, 11624 + "license": "MIT" 11625 + }, 11626 + "node_modules/path-type": { 11627 + "version": "4.0.0", 11628 + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", 11629 + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", 11630 + "dev": true, 11631 + "license": "MIT", 11632 + "engines": { 11633 + "node": ">=8" 11634 + } 11635 + }, 3865 11636 "node_modules/pathe": { 3866 11637 "version": "2.0.3", 3867 11638 "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", ··· 3897 11668 "url": "https://github.com/sponsors/jonschlinkert" 3898 11669 } 3899 11670 }, 11671 + "node_modules/pkg-types": { 11672 + "version": "2.3.0", 11673 + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", 11674 + "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", 11675 + "dev": true, 11676 + "license": "MIT", 11677 + "dependencies": { 11678 + "confbox": "^0.2.2", 11679 + "exsolve": "^1.0.7", 11680 + "pathe": "^2.0.3" 11681 + } 11682 + }, 3900 11683 "node_modules/player.style": { 3901 11684 "version": "0.1.10", 3902 11685 "resolved": "https://registry.npmjs.org/player.style/-/player.style-0.1.10.tgz", ··· 3913 11696 "media-chrome": "~4.11.0" 3914 11697 } 3915 11698 }, 11699 + "node_modules/possible-typed-array-names": { 11700 + "version": "1.1.0", 11701 + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", 11702 + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", 11703 + "dev": true, 11704 + "license": "MIT", 11705 + "engines": { 11706 + "node": ">= 0.4" 11707 + } 11708 + }, 3916 11709 "node_modules/postcss": { 3917 11710 "version": "8.5.6", 3918 11711 "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", ··· 3939 11732 }, 3940 11733 "engines": { 3941 11734 "node": "^10 || ^12 || >=14" 11735 + } 11736 + }, 11737 + "node_modules/prelude-ls": { 11738 + "version": "1.2.1", 11739 + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", 11740 + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", 11741 + "dev": true, 11742 + "license": "MIT", 11743 + "peer": true, 11744 + "engines": { 11745 + "node": ">= 0.8.0" 3942 11746 } 3943 11747 }, 3944 11748 "node_modules/prettier": { ··· 3998 11802 "node": ">=6" 3999 11803 } 4000 11804 }, 11805 + "node_modules/quansync": { 11806 + "version": "0.2.11", 11807 + "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz", 11808 + "integrity": "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==", 11809 + "dev": true, 11810 + "funding": [ 11811 + { 11812 + "type": "individual", 11813 + "url": "https://github.com/sponsors/antfu" 11814 + }, 11815 + { 11816 + "type": "individual", 11817 + "url": "https://github.com/sponsors/sxzz" 11818 + } 11819 + ], 11820 + "license": "MIT" 11821 + }, 11822 + "node_modules/queue-microtask": { 11823 + "version": "1.2.3", 11824 + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", 11825 + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", 11826 + "dev": true, 11827 + "funding": [ 11828 + { 11829 + "type": "github", 11830 + "url": "https://github.com/sponsors/feross" 11831 + }, 11832 + { 11833 + "type": "patreon", 11834 + "url": "https://www.patreon.com/feross" 11835 + }, 11836 + { 11837 + "type": "consulting", 11838 + "url": "https://feross.org/support" 11839 + } 11840 + ], 11841 + "license": "MIT" 11842 + }, 11843 + "node_modules/radix-ui": { 11844 + "version": "1.4.3", 11845 + "resolved": "https://registry.npmjs.org/radix-ui/-/radix-ui-1.4.3.tgz", 11846 + "integrity": "sha512-aWizCQiyeAenIdUbqEpXgRA1ya65P13NKn/W8rWkcN0OPkRDxdBVLWnIEDsS2RpwCK2nobI7oMUSmexzTDyAmA==", 11847 + "dependencies": { 11848 + "@radix-ui/primitive": "1.1.3", 11849 + "@radix-ui/react-accessible-icon": "1.1.7", 11850 + "@radix-ui/react-accordion": "1.2.12", 11851 + "@radix-ui/react-alert-dialog": "1.1.15", 11852 + "@radix-ui/react-arrow": "1.1.7", 11853 + "@radix-ui/react-aspect-ratio": "1.1.7", 11854 + "@radix-ui/react-avatar": "1.1.10", 11855 + "@radix-ui/react-checkbox": "1.3.3", 11856 + "@radix-ui/react-collapsible": "1.1.12", 11857 + "@radix-ui/react-collection": "1.1.7", 11858 + "@radix-ui/react-compose-refs": "1.1.2", 11859 + "@radix-ui/react-context": "1.1.2", 11860 + "@radix-ui/react-context-menu": "2.2.16", 11861 + "@radix-ui/react-dialog": "1.1.15", 11862 + "@radix-ui/react-direction": "1.1.1", 11863 + "@radix-ui/react-dismissable-layer": "1.1.11", 11864 + "@radix-ui/react-dropdown-menu": "2.1.16", 11865 + "@radix-ui/react-focus-guards": "1.1.3", 11866 + "@radix-ui/react-focus-scope": "1.1.7", 11867 + "@radix-ui/react-form": "0.1.8", 11868 + "@radix-ui/react-hover-card": "1.1.15", 11869 + "@radix-ui/react-label": "2.1.7", 11870 + "@radix-ui/react-menu": "2.1.16", 11871 + "@radix-ui/react-menubar": "1.1.16", 11872 + "@radix-ui/react-navigation-menu": "1.2.14", 11873 + "@radix-ui/react-one-time-password-field": "0.1.8", 11874 + "@radix-ui/react-password-toggle-field": "0.1.3", 11875 + "@radix-ui/react-popover": "1.1.15", 11876 + "@radix-ui/react-popper": "1.2.8", 11877 + "@radix-ui/react-portal": "1.1.9", 11878 + "@radix-ui/react-presence": "1.1.5", 11879 + "@radix-ui/react-primitive": "2.1.3", 11880 + "@radix-ui/react-progress": "1.1.7", 11881 + "@radix-ui/react-radio-group": "1.3.8", 11882 + "@radix-ui/react-roving-focus": "1.1.11", 11883 + "@radix-ui/react-scroll-area": "1.2.10", 11884 + "@radix-ui/react-select": "2.2.6", 11885 + "@radix-ui/react-separator": "1.1.7", 11886 + "@radix-ui/react-slider": "1.3.6", 11887 + "@radix-ui/react-slot": "1.2.3", 11888 + "@radix-ui/react-switch": "1.2.6", 11889 + "@radix-ui/react-tabs": "1.1.13", 11890 + "@radix-ui/react-toast": "1.2.15", 11891 + "@radix-ui/react-toggle": "1.1.10", 11892 + "@radix-ui/react-toggle-group": "1.1.11", 11893 + "@radix-ui/react-toolbar": "1.1.11", 11894 + "@radix-ui/react-tooltip": "1.2.8", 11895 + "@radix-ui/react-use-callback-ref": "1.1.1", 11896 + "@radix-ui/react-use-controllable-state": "1.2.2", 11897 + "@radix-ui/react-use-effect-event": "0.0.2", 11898 + "@radix-ui/react-use-escape-keydown": "1.1.1", 11899 + "@radix-ui/react-use-is-hydrated": "0.1.0", 11900 + "@radix-ui/react-use-layout-effect": "1.1.1", 11901 + "@radix-ui/react-use-size": "1.1.1", 11902 + "@radix-ui/react-visually-hidden": "1.2.3" 11903 + }, 11904 + "peerDependencies": { 11905 + "@types/react": "*", 11906 + "@types/react-dom": "*", 11907 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 11908 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 11909 + }, 11910 + "peerDependenciesMeta": { 11911 + "@types/react": { 11912 + "optional": true 11913 + }, 11914 + "@types/react-dom": { 11915 + "optional": true 11916 + } 11917 + } 11918 + }, 4001 11919 "node_modules/react": { 4002 11920 "version": "19.1.1", 4003 11921 "resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz", ··· 4059 11977 "node": ">=0.10.0" 4060 11978 } 4061 11979 }, 11980 + "node_modules/react-remove-scroll": { 11981 + "version": "2.7.1", 11982 + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.1.tgz", 11983 + "integrity": "sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==", 11984 + "dependencies": { 11985 + "react-remove-scroll-bar": "^2.3.7", 11986 + "react-style-singleton": "^2.2.3", 11987 + "tslib": "^2.1.0", 11988 + "use-callback-ref": "^1.3.3", 11989 + "use-sidecar": "^1.1.3" 11990 + }, 11991 + "engines": { 11992 + "node": ">=10" 11993 + }, 11994 + "peerDependencies": { 11995 + "@types/react": "*", 11996 + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" 11997 + }, 11998 + "peerDependenciesMeta": { 11999 + "@types/react": { 12000 + "optional": true 12001 + } 12002 + } 12003 + }, 12004 + "node_modules/react-remove-scroll-bar": { 12005 + "version": "2.3.8", 12006 + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", 12007 + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", 12008 + "dependencies": { 12009 + "react-style-singleton": "^2.2.2", 12010 + "tslib": "^2.0.0" 12011 + }, 12012 + "engines": { 12013 + "node": ">=10" 12014 + }, 12015 + "peerDependencies": { 12016 + "@types/react": "*", 12017 + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" 12018 + }, 12019 + "peerDependenciesMeta": { 12020 + "@types/react": { 12021 + "optional": true 12022 + } 12023 + } 12024 + }, 12025 + "node_modules/react-style-singleton": { 12026 + "version": "2.2.3", 12027 + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", 12028 + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", 12029 + "dependencies": { 12030 + "get-nonce": "^1.0.0", 12031 + "tslib": "^2.0.0" 12032 + }, 12033 + "engines": { 12034 + "node": ">=10" 12035 + }, 12036 + "peerDependencies": { 12037 + "@types/react": "*", 12038 + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" 12039 + }, 12040 + "peerDependenciesMeta": { 12041 + "@types/react": { 12042 + "optional": true 12043 + } 12044 + } 12045 + }, 4062 12046 "node_modules/readdirp": { 4063 12047 "version": "3.6.0", 4064 12048 "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", ··· 4096 12080 "node": ">=0.10.0" 4097 12081 } 4098 12082 }, 12083 + "node_modules/reflect.getprototypeof": { 12084 + "version": "1.0.10", 12085 + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", 12086 + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", 12087 + "dev": true, 12088 + "license": "MIT", 12089 + "dependencies": { 12090 + "call-bind": "^1.0.8", 12091 + "define-properties": "^1.2.1", 12092 + "es-abstract": "^1.23.9", 12093 + "es-errors": "^1.3.0", 12094 + "es-object-atoms": "^1.0.0", 12095 + "get-intrinsic": "^1.2.7", 12096 + "get-proto": "^1.0.1", 12097 + "which-builtin-type": "^1.2.1" 12098 + }, 12099 + "engines": { 12100 + "node": ">= 0.4" 12101 + }, 12102 + "funding": { 12103 + "url": "https://github.com/sponsors/ljharb" 12104 + } 12105 + }, 12106 + "node_modules/regexp.prototype.flags": { 12107 + "version": "1.5.4", 12108 + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", 12109 + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", 12110 + "dev": true, 12111 + "license": "MIT", 12112 + "dependencies": { 12113 + "call-bind": "^1.0.8", 12114 + "define-properties": "^1.2.1", 12115 + "es-errors": "^1.3.0", 12116 + "get-proto": "^1.0.1", 12117 + "gopd": "^1.2.0", 12118 + "set-function-name": "^2.0.2" 12119 + }, 12120 + "engines": { 12121 + "node": ">= 0.4" 12122 + }, 12123 + "funding": { 12124 + "url": "https://github.com/sponsors/ljharb" 12125 + } 12126 + }, 12127 + "node_modules/resolve": { 12128 + "version": "2.0.0-next.5", 12129 + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", 12130 + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", 12131 + "dev": true, 12132 + "license": "MIT", 12133 + "dependencies": { 12134 + "is-core-module": "^2.13.0", 12135 + "path-parse": "^1.0.7", 12136 + "supports-preserve-symlinks-flag": "^1.0.0" 12137 + }, 12138 + "bin": { 12139 + "resolve": "bin/resolve" 12140 + }, 12141 + "funding": { 12142 + "url": "https://github.com/sponsors/ljharb" 12143 + } 12144 + }, 12145 + "node_modules/resolve-from": { 12146 + "version": "4.0.0", 12147 + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", 12148 + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", 12149 + "dev": true, 12150 + "license": "MIT", 12151 + "engines": { 12152 + "node": ">=4" 12153 + } 12154 + }, 4099 12155 "node_modules/resolve-pkg-maps": { 4100 12156 "version": "1.0.0", 4101 12157 "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", ··· 4103 12159 "license": "MIT", 4104 12160 "funding": { 4105 12161 "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" 12162 + } 12163 + }, 12164 + "node_modules/reusify": { 12165 + "version": "1.1.0", 12166 + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", 12167 + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", 12168 + "dev": true, 12169 + "license": "MIT", 12170 + "engines": { 12171 + "iojs": ">=1.0.0", 12172 + "node": ">=0.10.0" 4106 12173 } 4107 12174 }, 4108 12175 "node_modules/rollup": { ··· 4151 12218 "dev": true, 4152 12219 "license": "MIT" 4153 12220 }, 12221 + "node_modules/run-parallel": { 12222 + "version": "1.2.0", 12223 + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", 12224 + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", 12225 + "dev": true, 12226 + "funding": [ 12227 + { 12228 + "type": "github", 12229 + "url": "https://github.com/sponsors/feross" 12230 + }, 12231 + { 12232 + "type": "patreon", 12233 + "url": "https://www.patreon.com/feross" 12234 + }, 12235 + { 12236 + "type": "consulting", 12237 + "url": "https://feross.org/support" 12238 + } 12239 + ], 12240 + "license": "MIT", 12241 + "dependencies": { 12242 + "queue-microtask": "^1.2.2" 12243 + } 12244 + }, 12245 + "node_modules/safe-array-concat": { 12246 + "version": "1.1.3", 12247 + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", 12248 + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", 12249 + "dev": true, 12250 + "license": "MIT", 12251 + "dependencies": { 12252 + "call-bind": "^1.0.8", 12253 + "call-bound": "^1.0.2", 12254 + "get-intrinsic": "^1.2.6", 12255 + "has-symbols": "^1.1.0", 12256 + "isarray": "^2.0.5" 12257 + }, 12258 + "engines": { 12259 + "node": ">=0.4" 12260 + }, 12261 + "funding": { 12262 + "url": "https://github.com/sponsors/ljharb" 12263 + } 12264 + }, 12265 + "node_modules/safe-push-apply": { 12266 + "version": "1.0.0", 12267 + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", 12268 + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", 12269 + "dev": true, 12270 + "license": "MIT", 12271 + "dependencies": { 12272 + "es-errors": "^1.3.0", 12273 + "isarray": "^2.0.5" 12274 + }, 12275 + "engines": { 12276 + "node": ">= 0.4" 12277 + }, 12278 + "funding": { 12279 + "url": "https://github.com/sponsors/ljharb" 12280 + } 12281 + }, 12282 + "node_modules/safe-regex-test": { 12283 + "version": "1.1.0", 12284 + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", 12285 + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", 12286 + "dev": true, 12287 + "license": "MIT", 12288 + "dependencies": { 12289 + "call-bound": "^1.0.2", 12290 + "es-errors": "^1.3.0", 12291 + "is-regex": "^1.2.1" 12292 + }, 12293 + "engines": { 12294 + "node": ">= 0.4" 12295 + }, 12296 + "funding": { 12297 + "url": "https://github.com/sponsors/ljharb" 12298 + } 12299 + }, 4154 12300 "node_modules/safer-buffer": { 4155 12301 "version": "2.1.2", 4156 12302 "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", ··· 4183 12329 "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", 4184 12330 "license": "MIT" 4185 12331 }, 12332 + "node_modules/scule": { 12333 + "version": "1.3.0", 12334 + "resolved": "https://registry.npmjs.org/scule/-/scule-1.3.0.tgz", 12335 + "integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==", 12336 + "dev": true, 12337 + "license": "MIT" 12338 + }, 4186 12339 "node_modules/semver": { 4187 12340 "version": "6.3.1", 4188 12341 "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", ··· 4213 12366 "seroval": "^1.0" 4214 12367 } 4215 12368 }, 12369 + "node_modules/set-function-length": { 12370 + "version": "1.2.2", 12371 + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", 12372 + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", 12373 + "dev": true, 12374 + "license": "MIT", 12375 + "dependencies": { 12376 + "define-data-property": "^1.1.4", 12377 + "es-errors": "^1.3.0", 12378 + "function-bind": "^1.1.2", 12379 + "get-intrinsic": "^1.2.4", 12380 + "gopd": "^1.0.1", 12381 + "has-property-descriptors": "^1.0.2" 12382 + }, 12383 + "engines": { 12384 + "node": ">= 0.4" 12385 + } 12386 + }, 12387 + "node_modules/set-function-name": { 12388 + "version": "2.0.2", 12389 + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", 12390 + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", 12391 + "dev": true, 12392 + "license": "MIT", 12393 + "dependencies": { 12394 + "define-data-property": "^1.1.4", 12395 + "es-errors": "^1.3.0", 12396 + "functions-have-names": "^1.2.3", 12397 + "has-property-descriptors": "^1.0.2" 12398 + }, 12399 + "engines": { 12400 + "node": ">= 0.4" 12401 + } 12402 + }, 12403 + "node_modules/set-proto": { 12404 + "version": "1.0.0", 12405 + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", 12406 + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", 12407 + "dev": true, 12408 + "license": "MIT", 12409 + "dependencies": { 12410 + "dunder-proto": "^1.0.1", 12411 + "es-errors": "^1.3.0", 12412 + "es-object-atoms": "^1.0.0" 12413 + }, 12414 + "engines": { 12415 + "node": ">= 0.4" 12416 + } 12417 + }, 12418 + "node_modules/shebang-command": { 12419 + "version": "2.0.0", 12420 + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", 12421 + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", 12422 + "dev": true, 12423 + "license": "MIT", 12424 + "peer": true, 12425 + "dependencies": { 12426 + "shebang-regex": "^3.0.0" 12427 + }, 12428 + "engines": { 12429 + "node": ">=8" 12430 + } 12431 + }, 12432 + "node_modules/shebang-regex": { 12433 + "version": "3.0.0", 12434 + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", 12435 + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", 12436 + "dev": true, 12437 + "license": "MIT", 12438 + "peer": true, 12439 + "engines": { 12440 + "node": ">=8" 12441 + } 12442 + }, 12443 + "node_modules/side-channel": { 12444 + "version": "1.1.0", 12445 + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", 12446 + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", 12447 + "dev": true, 12448 + "license": "MIT", 12449 + "dependencies": { 12450 + "es-errors": "^1.3.0", 12451 + "object-inspect": "^1.13.3", 12452 + "side-channel-list": "^1.0.0", 12453 + "side-channel-map": "^1.0.1", 12454 + "side-channel-weakmap": "^1.0.2" 12455 + }, 12456 + "engines": { 12457 + "node": ">= 0.4" 12458 + }, 12459 + "funding": { 12460 + "url": "https://github.com/sponsors/ljharb" 12461 + } 12462 + }, 12463 + "node_modules/side-channel-list": { 12464 + "version": "1.0.0", 12465 + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", 12466 + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", 12467 + "dev": true, 12468 + "license": "MIT", 12469 + "dependencies": { 12470 + "es-errors": "^1.3.0", 12471 + "object-inspect": "^1.13.3" 12472 + }, 12473 + "engines": { 12474 + "node": ">= 0.4" 12475 + }, 12476 + "funding": { 12477 + "url": "https://github.com/sponsors/ljharb" 12478 + } 12479 + }, 12480 + "node_modules/side-channel-map": { 12481 + "version": "1.0.1", 12482 + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", 12483 + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", 12484 + "dev": true, 12485 + "license": "MIT", 12486 + "dependencies": { 12487 + "call-bound": "^1.0.2", 12488 + "es-errors": "^1.3.0", 12489 + "get-intrinsic": "^1.2.5", 12490 + "object-inspect": "^1.13.3" 12491 + }, 12492 + "engines": { 12493 + "node": ">= 0.4" 12494 + }, 12495 + "funding": { 12496 + "url": "https://github.com/sponsors/ljharb" 12497 + } 12498 + }, 12499 + "node_modules/side-channel-weakmap": { 12500 + "version": "1.0.2", 12501 + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", 12502 + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", 12503 + "dev": true, 12504 + "license": "MIT", 12505 + "dependencies": { 12506 + "call-bound": "^1.0.2", 12507 + "es-errors": "^1.3.0", 12508 + "get-intrinsic": "^1.2.5", 12509 + "object-inspect": "^1.13.3", 12510 + "side-channel-map": "^1.0.1" 12511 + }, 12512 + "engines": { 12513 + "node": ">= 0.4" 12514 + }, 12515 + "funding": { 12516 + "url": "https://github.com/sponsors/ljharb" 12517 + } 12518 + }, 4216 12519 "node_modules/siginfo": { 4217 12520 "version": "2.0.0", 4218 12521 "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", ··· 4220 12523 "dev": true, 4221 12524 "license": "ISC" 4222 12525 }, 12526 + "node_modules/snake-case": { 12527 + "version": "3.0.4", 12528 + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", 12529 + "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", 12530 + "dev": true, 12531 + "license": "MIT", 12532 + "dependencies": { 12533 + "dot-case": "^3.0.4", 12534 + "tslib": "^2.0.3" 12535 + } 12536 + }, 4223 12537 "node_modules/solid-js": { 4224 12538 "version": "1.9.9", 4225 12539 "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.9.9.tgz", ··· 4269 12583 "dev": true, 4270 12584 "license": "MIT" 4271 12585 }, 12586 + "node_modules/stop-iteration-iterator": { 12587 + "version": "1.1.0", 12588 + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", 12589 + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", 12590 + "dev": true, 12591 + "license": "MIT", 12592 + "dependencies": { 12593 + "es-errors": "^1.3.0", 12594 + "internal-slot": "^1.1.0" 12595 + }, 12596 + "engines": { 12597 + "node": ">= 0.4" 12598 + } 12599 + }, 12600 + "node_modules/string-ts": { 12601 + "version": "2.2.1", 12602 + "resolved": "https://registry.npmjs.org/string-ts/-/string-ts-2.2.1.tgz", 12603 + "integrity": "sha512-Q2u0gko67PLLhbte5HmPfdOjNvUKbKQM+mCNQae6jE91DmoFHY6HH9GcdqCeNx87DZ2KKjiFxmA0R/42OneGWw==", 12604 + "dev": true, 12605 + "license": "MIT" 12606 + }, 12607 + "node_modules/string.prototype.matchall": { 12608 + "version": "4.0.12", 12609 + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", 12610 + "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", 12611 + "dev": true, 12612 + "license": "MIT", 12613 + "dependencies": { 12614 + "call-bind": "^1.0.8", 12615 + "call-bound": "^1.0.3", 12616 + "define-properties": "^1.2.1", 12617 + "es-abstract": "^1.23.6", 12618 + "es-errors": "^1.3.0", 12619 + "es-object-atoms": "^1.0.0", 12620 + "get-intrinsic": "^1.2.6", 12621 + "gopd": "^1.2.0", 12622 + "has-symbols": "^1.1.0", 12623 + "internal-slot": "^1.1.0", 12624 + "regexp.prototype.flags": "^1.5.3", 12625 + "set-function-name": "^2.0.2", 12626 + "side-channel": "^1.1.0" 12627 + }, 12628 + "engines": { 12629 + "node": ">= 0.4" 12630 + }, 12631 + "funding": { 12632 + "url": "https://github.com/sponsors/ljharb" 12633 + } 12634 + }, 12635 + "node_modules/string.prototype.repeat": { 12636 + "version": "1.0.0", 12637 + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", 12638 + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", 12639 + "dev": true, 12640 + "license": "MIT", 12641 + "dependencies": { 12642 + "define-properties": "^1.1.3", 12643 + "es-abstract": "^1.17.5" 12644 + } 12645 + }, 12646 + "node_modules/string.prototype.trim": { 12647 + "version": "1.2.10", 12648 + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", 12649 + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", 12650 + "dev": true, 12651 + "license": "MIT", 12652 + "dependencies": { 12653 + "call-bind": "^1.0.8", 12654 + "call-bound": "^1.0.2", 12655 + "define-data-property": "^1.1.4", 12656 + "define-properties": "^1.2.1", 12657 + "es-abstract": "^1.23.5", 12658 + "es-object-atoms": "^1.0.0", 12659 + "has-property-descriptors": "^1.0.2" 12660 + }, 12661 + "engines": { 12662 + "node": ">= 0.4" 12663 + }, 12664 + "funding": { 12665 + "url": "https://github.com/sponsors/ljharb" 12666 + } 12667 + }, 12668 + "node_modules/string.prototype.trimend": { 12669 + "version": "1.0.9", 12670 + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", 12671 + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", 12672 + "dev": true, 12673 + "license": "MIT", 12674 + "dependencies": { 12675 + "call-bind": "^1.0.8", 12676 + "call-bound": "^1.0.2", 12677 + "define-properties": "^1.2.1", 12678 + "es-object-atoms": "^1.0.0" 12679 + }, 12680 + "engines": { 12681 + "node": ">= 0.4" 12682 + }, 12683 + "funding": { 12684 + "url": "https://github.com/sponsors/ljharb" 12685 + } 12686 + }, 12687 + "node_modules/string.prototype.trimstart": { 12688 + "version": "1.0.8", 12689 + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", 12690 + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", 12691 + "dev": true, 12692 + "license": "MIT", 12693 + "dependencies": { 12694 + "call-bind": "^1.0.7", 12695 + "define-properties": "^1.2.1", 12696 + "es-object-atoms": "^1.0.0" 12697 + }, 12698 + "engines": { 12699 + "node": ">= 0.4" 12700 + }, 12701 + "funding": { 12702 + "url": "https://github.com/sponsors/ljharb" 12703 + } 12704 + }, 12705 + "node_modules/strip-json-comments": { 12706 + "version": "3.1.1", 12707 + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", 12708 + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", 12709 + "dev": true, 12710 + "license": "MIT", 12711 + "peer": true, 12712 + "engines": { 12713 + "node": ">=8" 12714 + }, 12715 + "funding": { 12716 + "url": "https://github.com/sponsors/sindresorhus" 12717 + } 12718 + }, 4272 12719 "node_modules/strip-literal": { 4273 - "version": "3.0.0", 4274 - "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.0.0.tgz", 4275 - "integrity": "sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==", 12720 + "version": "3.1.0", 12721 + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz", 12722 + "integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==", 4276 12723 "dev": true, 4277 12724 "license": "MIT", 4278 12725 "dependencies": { ··· 4295 12742 "integrity": "sha512-9pP/CVNp4NF2MNlRzLwQkjiTgKKe9WYXrLh9+8QokWmMxz+zt2mf1utkWLco26IuA3AfVcTb//qtlTIjY3VHxA==", 4296 12743 "license": "MIT" 4297 12744 }, 12745 + "node_modules/supports-color": { 12746 + "version": "7.2.0", 12747 + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 12748 + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 12749 + "dev": true, 12750 + "license": "MIT", 12751 + "peer": true, 12752 + "dependencies": { 12753 + "has-flag": "^4.0.0" 12754 + }, 12755 + "engines": { 12756 + "node": ">=8" 12757 + } 12758 + }, 12759 + "node_modules/supports-preserve-symlinks-flag": { 12760 + "version": "1.0.0", 12761 + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", 12762 + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", 12763 + "dev": true, 12764 + "license": "MIT", 12765 + "engines": { 12766 + "node": ">= 0.4" 12767 + }, 12768 + "funding": { 12769 + "url": "https://github.com/sponsors/ljharb" 12770 + } 12771 + }, 12772 + "node_modules/svg-parser": { 12773 + "version": "2.0.4", 12774 + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", 12775 + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==", 12776 + "dev": true, 12777 + "license": "MIT" 12778 + }, 4298 12779 "node_modules/symbol-tree": { 4299 12780 "version": "3.2.4", 4300 12781 "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", ··· 4307 12788 "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.12.tgz", 4308 12789 "integrity": "sha512-DzFtxOi+7NsFf7DBtI3BJsynR+0Yp6etH+nRPTbpWnS2pZBaSksv/JGctNwSWzbFjp0vxSqknaUylseZqMDGrA==", 4309 12790 "license": "MIT" 12791 + }, 12792 + "node_modules/tanstack-router-keepalive": { 12793 + "version": "1.0.0", 12794 + "resolved": "https://registry.npmjs.org/tanstack-router-keepalive/-/tanstack-router-keepalive-1.0.0.tgz", 12795 + "integrity": "sha512-SxMl9sgIZGjB4OZvGXufTz14ygmZi+eAbrhz3sjmXYZzhSQOekx5LYi9TvKcMXVu8fQR6W/itF5hdglqD6WB/w==", 12796 + "license": "MIT", 12797 + "dependencies": { 12798 + "eventemitter3": "^5.0.1", 12799 + "lodash.clonedeep": "^4.5.0" 12800 + } 4310 12801 }, 4311 12802 "node_modules/tapable": { 4312 12803 "version": "2.2.3", ··· 4380 12871 "license": "MIT" 4381 12872 }, 4382 12873 "node_modules/tinyglobby": { 4383 - "version": "0.2.14", 4384 - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", 4385 - "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", 12874 + "version": "0.2.15", 12875 + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", 12876 + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", 4386 12877 "license": "MIT", 4387 12878 "dependencies": { 4388 - "fdir": "^6.4.4", 4389 - "picomatch": "^4.0.2" 12879 + "fdir": "^6.5.0", 12880 + "picomatch": "^4.0.3" 4390 12881 }, 4391 12882 "engines": { 4392 12883 "node": ">=12.0.0" ··· 4521 13012 "node": ">=18" 4522 13013 } 4523 13014 }, 13015 + "node_modules/ts-api-utils": { 13016 + "version": "2.1.0", 13017 + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", 13018 + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", 13019 + "dev": true, 13020 + "license": "MIT", 13021 + "engines": { 13022 + "node": ">=18.12" 13023 + }, 13024 + "peerDependencies": { 13025 + "typescript": ">=4.8.4" 13026 + } 13027 + }, 13028 + "node_modules/ts-declaration-location": { 13029 + "version": "1.0.7", 13030 + "resolved": "https://registry.npmjs.org/ts-declaration-location/-/ts-declaration-location-1.0.7.tgz", 13031 + "integrity": "sha512-EDyGAwH1gO0Ausm9gV6T2nUvBgXT5kGoCMJPllOaooZ+4VvJiKBdZE7wK18N1deEowhcUptS+5GXZK8U/fvpwA==", 13032 + "dev": true, 13033 + "funding": [ 13034 + { 13035 + "type": "ko-fi", 13036 + "url": "https://ko-fi.com/rebeccastevens" 13037 + }, 13038 + { 13039 + "type": "tidelift", 13040 + "url": "https://tidelift.com/funding/github/npm/ts-declaration-location" 13041 + } 13042 + ], 13043 + "license": "BSD-3-Clause", 13044 + "dependencies": { 13045 + "picomatch": "^4.0.2" 13046 + }, 13047 + "peerDependencies": { 13048 + "typescript": ">=4.0.0" 13049 + } 13050 + }, 13051 + "node_modules/ts-declaration-location/node_modules/picomatch": { 13052 + "version": "4.0.3", 13053 + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", 13054 + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", 13055 + "dev": true, 13056 + "license": "MIT", 13057 + "engines": { 13058 + "node": ">=12" 13059 + }, 13060 + "funding": { 13061 + "url": "https://github.com/sponsors/jonschlinkert" 13062 + } 13063 + }, 13064 + "node_modules/ts-pattern": { 13065 + "version": "5.8.0", 13066 + "resolved": "https://registry.npmjs.org/ts-pattern/-/ts-pattern-5.8.0.tgz", 13067 + "integrity": "sha512-kIjN2qmWiHnhgr5DAkAafF9fwb0T5OhMVSWrm8XEdTFnX6+wfXwYOFjeF86UZ54vduqiR7BfqScFmXSzSaH8oA==", 13068 + "dev": true, 13069 + "license": "MIT" 13070 + }, 4524 13071 "node_modules/tslib": { 4525 13072 "version": "2.8.1", 4526 13073 "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", ··· 4552 13099 "integrity": "sha512-SDpZ4f7sZmwHF6XG5PF0KWuP18pH/kNG04MhTcpqJby7Lk/D3TS/lCYd+RSg0rIAAVi1LDgSIo1yJs9kmHlhgw==", 4553 13100 "license": "MIT" 4554 13101 }, 13102 + "node_modules/type-check": { 13103 + "version": "0.4.0", 13104 + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", 13105 + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", 13106 + "dev": true, 13107 + "license": "MIT", 13108 + "peer": true, 13109 + "dependencies": { 13110 + "prelude-ls": "^1.2.1" 13111 + }, 13112 + "engines": { 13113 + "node": ">= 0.8.0" 13114 + } 13115 + }, 13116 + "node_modules/typed-array-buffer": { 13117 + "version": "1.0.3", 13118 + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", 13119 + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", 13120 + "dev": true, 13121 + "license": "MIT", 13122 + "dependencies": { 13123 + "call-bound": "^1.0.3", 13124 + "es-errors": "^1.3.0", 13125 + "is-typed-array": "^1.1.14" 13126 + }, 13127 + "engines": { 13128 + "node": ">= 0.4" 13129 + } 13130 + }, 13131 + "node_modules/typed-array-byte-length": { 13132 + "version": "1.0.3", 13133 + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", 13134 + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", 13135 + "dev": true, 13136 + "license": "MIT", 13137 + "dependencies": { 13138 + "call-bind": "^1.0.8", 13139 + "for-each": "^0.3.3", 13140 + "gopd": "^1.2.0", 13141 + "has-proto": "^1.2.0", 13142 + "is-typed-array": "^1.1.14" 13143 + }, 13144 + "engines": { 13145 + "node": ">= 0.4" 13146 + }, 13147 + "funding": { 13148 + "url": "https://github.com/sponsors/ljharb" 13149 + } 13150 + }, 13151 + "node_modules/typed-array-byte-offset": { 13152 + "version": "1.0.4", 13153 + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", 13154 + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", 13155 + "dev": true, 13156 + "license": "MIT", 13157 + "dependencies": { 13158 + "available-typed-arrays": "^1.0.7", 13159 + "call-bind": "^1.0.8", 13160 + "for-each": "^0.3.3", 13161 + "gopd": "^1.2.0", 13162 + "has-proto": "^1.2.0", 13163 + "is-typed-array": "^1.1.15", 13164 + "reflect.getprototypeof": "^1.0.9" 13165 + }, 13166 + "engines": { 13167 + "node": ">= 0.4" 13168 + }, 13169 + "funding": { 13170 + "url": "https://github.com/sponsors/ljharb" 13171 + } 13172 + }, 13173 + "node_modules/typed-array-length": { 13174 + "version": "1.0.7", 13175 + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", 13176 + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", 13177 + "dev": true, 13178 + "license": "MIT", 13179 + "dependencies": { 13180 + "call-bind": "^1.0.7", 13181 + "for-each": "^0.3.3", 13182 + "gopd": "^1.0.1", 13183 + "is-typed-array": "^1.1.13", 13184 + "possible-typed-array-names": "^1.0.0", 13185 + "reflect.getprototypeof": "^1.0.6" 13186 + }, 13187 + "engines": { 13188 + "node": ">= 0.4" 13189 + }, 13190 + "funding": { 13191 + "url": "https://github.com/sponsors/ljharb" 13192 + } 13193 + }, 4555 13194 "node_modules/typescript": { 4556 - "version": "5.9.2", 4557 - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", 4558 - "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", 13195 + "version": "5.9.3", 13196 + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", 13197 + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", 4559 13198 "dev": true, 4560 13199 "license": "Apache-2.0", 4561 13200 "bin": { ··· 4566 13205 "node": ">=14.17" 4567 13206 } 4568 13207 }, 13208 + "node_modules/typescript-eslint": { 13209 + "version": "8.46.1", 13210 + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.46.1.tgz", 13211 + "integrity": "sha512-VHgijW803JafdSsDO8I761r3SHrgk4T00IdyQ+/UsthtgPRsBWQLqoSxOolxTpxRKi1kGXK0bSz4CoAc9ObqJA==", 13212 + "dev": true, 13213 + "license": "MIT", 13214 + "dependencies": { 13215 + "@typescript-eslint/eslint-plugin": "8.46.1", 13216 + "@typescript-eslint/parser": "8.46.1", 13217 + "@typescript-eslint/typescript-estree": "8.46.1", 13218 + "@typescript-eslint/utils": "8.46.1" 13219 + }, 13220 + "engines": { 13221 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 13222 + }, 13223 + "funding": { 13224 + "type": "opencollective", 13225 + "url": "https://opencollective.com/typescript-eslint" 13226 + }, 13227 + "peerDependencies": { 13228 + "eslint": "^8.57.0 || ^9.0.0", 13229 + "typescript": ">=4.8.4 <6.0.0" 13230 + } 13231 + }, 4569 13232 "node_modules/ua-parser-js": { 4570 13233 "version": "1.0.41", 4571 13234 "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.41.tgz", ··· 4592 13255 "node": "*" 4593 13256 } 4594 13257 }, 13258 + "node_modules/ufo": { 13259 + "version": "1.6.1", 13260 + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.1.tgz", 13261 + "integrity": "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==", 13262 + "dev": true, 13263 + "license": "MIT" 13264 + }, 4595 13265 "node_modules/uint8arrays": { 4596 13266 "version": "3.0.0", 4597 13267 "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.0.0.tgz", ··· 4601 13271 "multiformats": "^9.4.2" 4602 13272 } 4603 13273 }, 13274 + "node_modules/unbox-primitive": { 13275 + "version": "1.1.0", 13276 + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", 13277 + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", 13278 + "dev": true, 13279 + "license": "MIT", 13280 + "dependencies": { 13281 + "call-bound": "^1.0.3", 13282 + "has-bigints": "^1.0.2", 13283 + "has-symbols": "^1.1.0", 13284 + "which-boxed-primitive": "^1.1.1" 13285 + }, 13286 + "engines": { 13287 + "node": ">= 0.4" 13288 + }, 13289 + "funding": { 13290 + "url": "https://github.com/sponsors/ljharb" 13291 + } 13292 + }, 4604 13293 "node_modules/undici-types": { 4605 13294 "version": "7.10.0", 4606 13295 "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", ··· 4608 13297 "devOptional": true, 4609 13298 "license": "MIT" 4610 13299 }, 13300 + "node_modules/unimport": { 13301 + "version": "5.5.0", 13302 + "resolved": "https://registry.npmjs.org/unimport/-/unimport-5.5.0.tgz", 13303 + "integrity": "sha512-/JpWMG9s1nBSlXJAQ8EREFTFy3oy6USFd8T6AoBaw1q2GGcF4R9yp3ofg32UODZlYEO5VD0EWE1RpI9XDWyPYg==", 13304 + "dev": true, 13305 + "license": "MIT", 13306 + "dependencies": { 13307 + "acorn": "^8.15.0", 13308 + "escape-string-regexp": "^5.0.0", 13309 + "estree-walker": "^3.0.3", 13310 + "local-pkg": "^1.1.2", 13311 + "magic-string": "^0.30.19", 13312 + "mlly": "^1.8.0", 13313 + "pathe": "^2.0.3", 13314 + "picomatch": "^4.0.3", 13315 + "pkg-types": "^2.3.0", 13316 + "scule": "^1.3.0", 13317 + "strip-literal": "^3.1.0", 13318 + "tinyglobby": "^0.2.15", 13319 + "unplugin": "^2.3.10", 13320 + "unplugin-utils": "^0.3.0" 13321 + }, 13322 + "engines": { 13323 + "node": ">=18.12.0" 13324 + } 13325 + }, 13326 + "node_modules/unimport/node_modules/escape-string-regexp": { 13327 + "version": "5.0.0", 13328 + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", 13329 + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", 13330 + "dev": true, 13331 + "license": "MIT", 13332 + "engines": { 13333 + "node": ">=12" 13334 + }, 13335 + "funding": { 13336 + "url": "https://github.com/sponsors/sindresorhus" 13337 + } 13338 + }, 13339 + "node_modules/unimport/node_modules/picomatch": { 13340 + "version": "4.0.3", 13341 + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", 13342 + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", 13343 + "dev": true, 13344 + "license": "MIT", 13345 + "engines": { 13346 + "node": ">=12" 13347 + }, 13348 + "funding": { 13349 + "url": "https://github.com/sponsors/jonschlinkert" 13350 + } 13351 + }, 4611 13352 "node_modules/unplugin": { 4612 - "version": "2.3.9", 4613 - "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.9.tgz", 4614 - "integrity": "sha512-2dcbZq6aprwXTkzptq3k5qm5B8cvpjG9ynPd5fyM2wDJuuF7PeUK64Sxf0d+X1ZyDOeGydbNzMqBSIVlH8GIfA==", 13353 + "version": "2.3.10", 13354 + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.10.tgz", 13355 + "integrity": "sha512-6NCPkv1ClwH+/BGE9QeoTIl09nuiAt0gS28nn1PvYXsGKRwM2TCbFA2QiilmehPDTXIe684k4rZI1yl3A1PCUw==", 4615 13356 "license": "MIT", 4616 13357 "dependencies": { 4617 13358 "@jridgewell/remapping": "^2.3.5", ··· 4623 13364 "node": ">=18.12.0" 4624 13365 } 4625 13366 }, 13367 + "node_modules/unplugin-auto-import": { 13368 + "version": "20.2.0", 13369 + "resolved": "https://registry.npmjs.org/unplugin-auto-import/-/unplugin-auto-import-20.2.0.tgz", 13370 + "integrity": "sha512-vfBI/SvD9hJqYNinipVOAj5n8dS8DJXFlCKFR5iLDp2SaQwsfdnfLXgZ+34Kd3YY3YEY9omk8XQg0bwos3Q8ug==", 13371 + "dev": true, 13372 + "license": "MIT", 13373 + "dependencies": { 13374 + "local-pkg": "^1.1.2", 13375 + "magic-string": "^0.30.19", 13376 + "picomatch": "^4.0.3", 13377 + "unimport": "^5.4.0", 13378 + "unplugin": "^2.3.10", 13379 + "unplugin-utils": "^0.3.0" 13380 + }, 13381 + "engines": { 13382 + "node": ">=14" 13383 + }, 13384 + "funding": { 13385 + "url": "https://github.com/sponsors/antfu" 13386 + }, 13387 + "peerDependencies": { 13388 + "@nuxt/kit": "^4.0.0", 13389 + "@vueuse/core": "*" 13390 + }, 13391 + "peerDependenciesMeta": { 13392 + "@nuxt/kit": { 13393 + "optional": true 13394 + }, 13395 + "@vueuse/core": { 13396 + "optional": true 13397 + } 13398 + } 13399 + }, 13400 + "node_modules/unplugin-auto-import/node_modules/picomatch": { 13401 + "version": "4.0.3", 13402 + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", 13403 + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", 13404 + "dev": true, 13405 + "license": "MIT", 13406 + "engines": { 13407 + "node": ">=12" 13408 + }, 13409 + "funding": { 13410 + "url": "https://github.com/sponsors/jonschlinkert" 13411 + } 13412 + }, 13413 + "node_modules/unplugin-icons": { 13414 + "version": "22.4.2", 13415 + "resolved": "https://registry.npmjs.org/unplugin-icons/-/unplugin-icons-22.4.2.tgz", 13416 + "integrity": "sha512-Yv15405unO67Chme0Slk0JRA/H2AiAZLK5t7ebt8/ZpTDlBfM4d4En2qD3MX2rzOSkIteQ0syIm3q8MSofeoBA==", 13417 + "dev": true, 13418 + "license": "MIT", 13419 + "dependencies": { 13420 + "@antfu/install-pkg": "^1.1.0", 13421 + "@iconify/utils": "^3.0.2", 13422 + "debug": "^4.4.3", 13423 + "local-pkg": "^1.1.2", 13424 + "unplugin": "^2.3.10" 13425 + }, 13426 + "funding": { 13427 + "url": "https://github.com/sponsors/antfu" 13428 + }, 13429 + "peerDependencies": { 13430 + "@svgr/core": ">=7.0.0", 13431 + "@svgx/core": "^1.0.1", 13432 + "@vue/compiler-sfc": "^3.0.2 || ^2.7.0", 13433 + "svelte": "^3.0.0 || ^4.0.0 || ^5.0.0", 13434 + "vue-template-compiler": "^2.6.12", 13435 + "vue-template-es2015-compiler": "^1.9.0" 13436 + }, 13437 + "peerDependenciesMeta": { 13438 + "@svgr/core": { 13439 + "optional": true 13440 + }, 13441 + "@svgx/core": { 13442 + "optional": true 13443 + }, 13444 + "@vue/compiler-sfc": { 13445 + "optional": true 13446 + }, 13447 + "svelte": { 13448 + "optional": true 13449 + }, 13450 + "vue-template-compiler": { 13451 + "optional": true 13452 + }, 13453 + "vue-template-es2015-compiler": { 13454 + "optional": true 13455 + } 13456 + } 13457 + }, 13458 + "node_modules/unplugin-utils": { 13459 + "version": "0.3.1", 13460 + "resolved": "https://registry.npmjs.org/unplugin-utils/-/unplugin-utils-0.3.1.tgz", 13461 + "integrity": "sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog==", 13462 + "dev": true, 13463 + "license": "MIT", 13464 + "dependencies": { 13465 + "pathe": "^2.0.3", 13466 + "picomatch": "^4.0.3" 13467 + }, 13468 + "engines": { 13469 + "node": ">=20.19.0" 13470 + }, 13471 + "funding": { 13472 + "url": "https://github.com/sponsors/sxzz" 13473 + } 13474 + }, 13475 + "node_modules/unplugin-utils/node_modules/picomatch": { 13476 + "version": "4.0.3", 13477 + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", 13478 + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", 13479 + "dev": true, 13480 + "license": "MIT", 13481 + "engines": { 13482 + "node": ">=12" 13483 + }, 13484 + "funding": { 13485 + "url": "https://github.com/sponsors/jonschlinkert" 13486 + } 13487 + }, 4626 13488 "node_modules/unplugin/node_modules/picomatch": { 4627 13489 "version": "4.0.3", 4628 13490 "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", ··· 4663 13525 }, 4664 13526 "peerDependencies": { 4665 13527 "browserslist": ">= 4.21.0" 13528 + } 13529 + }, 13530 + "node_modules/uri-js": { 13531 + "version": "4.4.1", 13532 + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", 13533 + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", 13534 + "dev": true, 13535 + "license": "BSD-2-Clause", 13536 + "peer": true, 13537 + "dependencies": { 13538 + "punycode": "^2.1.0" 13539 + } 13540 + }, 13541 + "node_modules/use-callback-ref": { 13542 + "version": "1.3.3", 13543 + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", 13544 + "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", 13545 + "dependencies": { 13546 + "tslib": "^2.0.0" 13547 + }, 13548 + "engines": { 13549 + "node": ">=10" 13550 + }, 13551 + "peerDependencies": { 13552 + "@types/react": "*", 13553 + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" 13554 + }, 13555 + "peerDependenciesMeta": { 13556 + "@types/react": { 13557 + "optional": true 13558 + } 13559 + } 13560 + }, 13561 + "node_modules/use-sidecar": { 13562 + "version": "1.1.3", 13563 + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", 13564 + "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", 13565 + "dependencies": { 13566 + "detect-node-es": "^1.1.0", 13567 + "tslib": "^2.0.0" 13568 + }, 13569 + "engines": { 13570 + "node": ">=10" 13571 + }, 13572 + "peerDependencies": { 13573 + "@types/react": "*", 13574 + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" 13575 + }, 13576 + "peerDependenciesMeta": { 13577 + "@types/react": { 13578 + "optional": true 13579 + } 4666 13580 } 4667 13581 }, 4668 13582 "node_modules/use-sync-external-store": { ··· 4977 13891 "node": ">=18" 4978 13892 } 4979 13893 }, 13894 + "node_modules/which": { 13895 + "version": "2.0.2", 13896 + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", 13897 + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 13898 + "dev": true, 13899 + "license": "ISC", 13900 + "peer": true, 13901 + "dependencies": { 13902 + "isexe": "^2.0.0" 13903 + }, 13904 + "bin": { 13905 + "node-which": "bin/node-which" 13906 + }, 13907 + "engines": { 13908 + "node": ">= 8" 13909 + } 13910 + }, 13911 + "node_modules/which-boxed-primitive": { 13912 + "version": "1.1.1", 13913 + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", 13914 + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", 13915 + "dev": true, 13916 + "license": "MIT", 13917 + "dependencies": { 13918 + "is-bigint": "^1.1.0", 13919 + "is-boolean-object": "^1.2.1", 13920 + "is-number-object": "^1.1.1", 13921 + "is-string": "^1.1.1", 13922 + "is-symbol": "^1.1.1" 13923 + }, 13924 + "engines": { 13925 + "node": ">= 0.4" 13926 + }, 13927 + "funding": { 13928 + "url": "https://github.com/sponsors/ljharb" 13929 + } 13930 + }, 13931 + "node_modules/which-builtin-type": { 13932 + "version": "1.2.1", 13933 + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", 13934 + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", 13935 + "dev": true, 13936 + "license": "MIT", 13937 + "dependencies": { 13938 + "call-bound": "^1.0.2", 13939 + "function.prototype.name": "^1.1.6", 13940 + "has-tostringtag": "^1.0.2", 13941 + "is-async-function": "^2.0.0", 13942 + "is-date-object": "^1.1.0", 13943 + "is-finalizationregistry": "^1.1.0", 13944 + "is-generator-function": "^1.0.10", 13945 + "is-regex": "^1.2.1", 13946 + "is-weakref": "^1.0.2", 13947 + "isarray": "^2.0.5", 13948 + "which-boxed-primitive": "^1.1.0", 13949 + "which-collection": "^1.0.2", 13950 + "which-typed-array": "^1.1.16" 13951 + }, 13952 + "engines": { 13953 + "node": ">= 0.4" 13954 + }, 13955 + "funding": { 13956 + "url": "https://github.com/sponsors/ljharb" 13957 + } 13958 + }, 13959 + "node_modules/which-collection": { 13960 + "version": "1.0.2", 13961 + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", 13962 + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", 13963 + "dev": true, 13964 + "license": "MIT", 13965 + "dependencies": { 13966 + "is-map": "^2.0.3", 13967 + "is-set": "^2.0.3", 13968 + "is-weakmap": "^2.0.2", 13969 + "is-weakset": "^2.0.3" 13970 + }, 13971 + "engines": { 13972 + "node": ">= 0.4" 13973 + }, 13974 + "funding": { 13975 + "url": "https://github.com/sponsors/ljharb" 13976 + } 13977 + }, 13978 + "node_modules/which-typed-array": { 13979 + "version": "1.1.19", 13980 + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", 13981 + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", 13982 + "dev": true, 13983 + "license": "MIT", 13984 + "dependencies": { 13985 + "available-typed-arrays": "^1.0.7", 13986 + "call-bind": "^1.0.8", 13987 + "call-bound": "^1.0.4", 13988 + "for-each": "^0.3.5", 13989 + "get-proto": "^1.0.1", 13990 + "gopd": "^1.2.0", 13991 + "has-tostringtag": "^1.0.2" 13992 + }, 13993 + "engines": { 13994 + "node": ">= 0.4" 13995 + }, 13996 + "funding": { 13997 + "url": "https://github.com/sponsors/ljharb" 13998 + } 13999 + }, 4980 14000 "node_modules/why-is-node-running": { 4981 14001 "version": "2.3.0", 4982 14002 "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", ··· 5003 14023 "super-media-element": "~1.4.2" 5004 14024 } 5005 14025 }, 14026 + "node_modules/word-wrap": { 14027 + "version": "1.2.5", 14028 + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", 14029 + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", 14030 + "dev": true, 14031 + "license": "MIT", 14032 + "peer": true, 14033 + "engines": { 14034 + "node": ">=0.10.0" 14035 + } 14036 + }, 5006 14037 "node_modules/ws": { 5007 14038 "version": "8.18.3", 5008 14039 "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", ··· 5047 14078 "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", 5048 14079 "license": "ISC" 5049 14080 }, 14081 + "node_modules/yocto-queue": { 14082 + "version": "0.1.0", 14083 + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", 14084 + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", 14085 + "dev": true, 14086 + "license": "MIT", 14087 + "peer": true, 14088 + "engines": { 14089 + "node": ">=10" 14090 + }, 14091 + "funding": { 14092 + "url": "https://github.com/sponsors/sindresorhus" 14093 + } 14094 + }, 5050 14095 "node_modules/youtube-video-element": { 5051 14096 "version": "1.6.2", 5052 14097 "resolved": "https://registry.npmjs.org/youtube-video-element/-/youtube-video-element-1.6.2.tgz", ··· 5060 14105 "license": "MIT", 5061 14106 "funding": { 5062 14107 "url": "https://github.com/sponsors/colinhacks" 14108 + } 14109 + }, 14110 + "node_modules/zod-validation-error": { 14111 + "version": "4.0.2", 14112 + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz", 14113 + "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==", 14114 + "dev": true, 14115 + "license": "MIT", 14116 + "engines": { 14117 + "node": ">=18.0.0" 14118 + }, 14119 + "peerDependencies": { 14120 + "zod": "^3.25.0 || ^4.0.0" 5063 14121 } 5064 14122 } 5065 14123 }
+34 -3
package.json
··· 3 3 "private": true, 4 4 "type": "module", 5 5 "scripts": { 6 - "dev": "vite --port 3000", 7 - "start": "vite --port 3000", 6 + "dev": "vite --port 3768", 7 + "start": "vite --port 3768", 8 8 "build": "vite build && tsc", 9 9 "serve": "vite preview", 10 10 "test": "vitest run" 11 11 }, 12 12 "dependencies": { 13 13 "@atproto/api": "^0.16.6", 14 + "@atproto/oauth-client-browser": "^0.3.33", 15 + "@radix-ui/react-dialog": "^1.1.15", 16 + "@radix-ui/react-dropdown-menu": "^2.1.16", 17 + "@radix-ui/react-hover-card": "^1.1.15", 18 + "@radix-ui/react-slider": "^1.3.6", 14 19 "@tailwindcss/vite": "^4.0.6", 20 + "@tanstack/query-sync-storage-persister": "^5.85.6", 15 21 "@tanstack/react-devtools": "^0.2.2", 22 + "@tanstack/react-query": "^5.85.6", 23 + "@tanstack/react-query-persist-client": "^5.85.6", 16 24 "@tanstack/react-router": "^1.130.2", 17 25 "@tanstack/react-router-devtools": "^1.131.5", 18 26 "@tanstack/router-plugin": "^1.121.2", 27 + "dompurify": "^3.3.0", 28 + "i": "^0.3.7", 19 29 "idb-keyval": "^6.2.2", 30 + "jotai": "^2.13.1", 31 + "npm": "^11.6.2", 32 + "radix-ui": "^1.4.3", 20 33 "react": "^19.0.0", 21 34 "react-dom": "^19.0.0", 22 35 "react-player": "^3.3.2", 23 - "tailwindcss": "^4.0.6" 36 + "tailwindcss": "^4.0.6", 37 + "tanstack-router-keepalive": "^1.0.0" 24 38 }, 25 39 "devDependencies": { 40 + "@eslint-react/eslint-plugin": "^2.2.1", 41 + "@iconify-icon/react": "^3.0.1", 42 + "@iconify-json/material-symbols": "^1.2.42", 43 + "@iconify-json/mdi": "^1.2.3", 44 + "@iconify/json": "^2.2.396", 45 + "@svgr/core": "^8.1.0", 46 + "@svgr/plugin-jsx": "^8.1.0", 26 47 "@testing-library/dom": "^10.4.0", 27 48 "@testing-library/react": "^16.2.0", 28 49 "@types/node": "^24.3.0", 29 50 "@types/react": "^19.0.8", 30 51 "@types/react-dom": "^19.0.3", 52 + "@typescript-eslint/eslint-plugin": "^8.46.1", 53 + "@typescript-eslint/parser": "^8.46.1", 31 54 "@vitejs/plugin-react": "^4.3.4", 55 + "babel-plugin-react-compiler": "^1.0.0", 56 + "eslint-plugin-react": "^7.37.5", 57 + "eslint-plugin-react-hooks": "^7.0.0", 58 + "eslint-plugin-simple-import-sort": "^12.1.1", 59 + "eslint-plugin-unused-imports": "^4.2.0", 32 60 "jsdom": "^26.0.0", 33 61 "prettier": "^3.6.2", 34 62 "typescript": "^5.7.2", 63 + "typescript-eslint": "^8.46.1", 64 + "unplugin-auto-import": "^20.2.0", 65 + "unplugin-icons": "^22.4.2", 35 66 "vite": "^6.3.5", 36 67 "vitest": "^3.0.5", 37 68 "web-vitals": "^4.2.4"
+2 -2
public/manifest.json
··· 20 20 ], 21 21 "start_url": ".", 22 22 "display": "standalone", 23 - "theme_color": "#000000", 24 - "background_color": "#ffffff" 23 + "theme_color": "#180001", 24 + "background_color": "#180001" 25 25 }
public/screenshot.jpg

This is a binary file and will not be displayed.

+22
src/auto-imports.d.ts
··· 1 + /* eslint-disable */ 2 + /* prettier-ignore */ 3 + // @ts-nocheck 4 + // noinspection JSUnusedGlobalSymbols 5 + // Generated by unplugin-auto-import 6 + // biome-ignore lint: disable 7 + export {} 8 + declare global { 9 + const IconMaterialSymbolsAccountCircle: typeof import('~icons/material-symbols/account-circle.jsx').default 10 + const IconMaterialSymbolsAccountCircleOutline: typeof import('~icons/material-symbols/account-circle-outline.jsx').default 11 + const IconMaterialSymbolsArrowBack: typeof import('~icons/material-symbols/arrow-back.jsx').default 12 + const IconMaterialSymbolsHome: typeof import('~icons/material-symbols/home.jsx').default 13 + const IconMaterialSymbolsHomeOutline: typeof import('~icons/material-symbols/home-outline.jsx').default 14 + const IconMaterialSymbolsNotifications: typeof import('~icons/material-symbols/notifications.jsx').default 15 + const IconMaterialSymbolsNotificationsOutline: typeof import('~icons/material-symbols/notifications-outline.jsx').default 16 + const IconMaterialSymbolsSearch: typeof import('~icons/material-symbols/search.jsx').default 17 + const IconMaterialSymbolsSettings: typeof import('~icons/material-symbols/settings.jsx').default 18 + const IconMaterialSymbolsSettingsOutline: typeof import('~icons/material-symbols/settings-outline.jsx').default 19 + const IconMaterialSymbolsTag: typeof import('~icons/material-symbols/tag.jsx').default 20 + const IconMdiAccountCircle: typeof import('~icons/mdi/account-circle.jsx').default 21 + const IconMdiPencilOutline: typeof import('~icons/mdi/pencil-outline.jsx').default 22 + }
+339
src/components/Composer.tsx
··· 1 + import { AppBskyRichtextFacet, RichText } from "@atproto/api"; 2 + import { useAtom } from "jotai"; 3 + import { Dialog } from "radix-ui"; 4 + import { useEffect, useRef, useState } from "react"; 5 + 6 + import { useAuth } from "~/providers/UnifiedAuthProvider"; 7 + import { composerAtom } from "~/utils/atoms"; 8 + import { useQueryPost } from "~/utils/useQuery"; 9 + 10 + import { ProfileThing } from "./Login"; 11 + import { Button } from "./radix-m3-rd/Button"; 12 + import { UniversalPostRendererATURILoader } from "./UniversalPostRenderer"; 13 + 14 + const MAX_POST_LENGTH = 300; 15 + 16 + export function Composer() { 17 + const [composerState, setComposerState] = useAtom(composerAtom); 18 + const [closeConfirmState, setCloseConfirmState] = useState<boolean>(false); 19 + const { agent } = useAuth(); 20 + 21 + const [postText, setPostText] = useState(""); 22 + const [posting, setPosting] = useState(false); 23 + const [postSuccess, setPostSuccess] = useState(false); 24 + const [postError, setPostError] = useState<string | null>(null); 25 + 26 + useEffect(() => { 27 + setPostText(""); 28 + setPosting(false); 29 + setPostSuccess(false); 30 + setPostError(null); 31 + }, [composerState.kind]); 32 + 33 + const parentUri = 34 + composerState.kind === "reply" 35 + ? composerState.parent 36 + : composerState.kind === "quote" 37 + ? composerState.subject 38 + : undefined; 39 + 40 + const { data: parentPost, isLoading: isParentLoading } = 41 + useQueryPost(parentUri); 42 + 43 + async function handlePost() { 44 + if (!agent || !postText.trim() || postText.length > MAX_POST_LENGTH) return; 45 + 46 + setPosting(true); 47 + setPostError(null); 48 + 49 + try { 50 + const rt = new RichText({ text: postText }); 51 + await rt.detectFacets(agent); 52 + 53 + if (rt.facets?.length) { 54 + rt.facets = rt.facets.filter((item) => { 55 + if (item.$type !== "app.bsky.richtext.facet") return true; 56 + if (!item.features?.length) return true; 57 + 58 + item.features = item.features.filter((feature) => { 59 + if (feature.$type !== "app.bsky.richtext.facet#mention") return true; 60 + const did = feature.$type === "app.bsky.richtext.facet#mention" ? (feature as AppBskyRichtextFacet.Mention)?.did : undefined; 61 + return typeof did === "string" && did.startsWith("did:"); 62 + }); 63 + 64 + return item.features.length > 0; 65 + }); 66 + } 67 + 68 + const record: Record<string, unknown> = { 69 + $type: "app.bsky.feed.post", 70 + text: rt.text, 71 + facets: rt.facets, 72 + createdAt: new Date().toISOString(), 73 + }; 74 + 75 + if (composerState.kind === "reply" && parentPost) { 76 + record.reply = { 77 + root: parentPost.value?.reply?.root ?? { 78 + uri: parentPost.uri, 79 + cid: parentPost.cid, 80 + }, 81 + parent: { 82 + uri: parentPost.uri, 83 + cid: parentPost.cid, 84 + }, 85 + }; 86 + } 87 + 88 + if (composerState.kind === "quote" && parentPost) { 89 + record.embed = { 90 + $type: "app.bsky.embed.record", 91 + record: { 92 + uri: parentPost.uri, 93 + cid: parentPost.cid, 94 + }, 95 + }; 96 + } 97 + 98 + await agent.com.atproto.repo.createRecord({ 99 + collection: "app.bsky.feed.post", 100 + repo: agent.assertDid, 101 + record, 102 + }); 103 + 104 + setPostSuccess(true); 105 + setPostText(""); 106 + 107 + setTimeout(() => { 108 + setPostSuccess(false); 109 + setComposerState({ kind: "closed" }); 110 + }, 1500); 111 + } catch (e: any) { 112 + setPostError(e?.message || "Failed to post"); 113 + } finally { 114 + setPosting(false); 115 + } 116 + } 117 + 118 + const getPlaceholder = () => { 119 + switch (composerState.kind) { 120 + case "reply": 121 + return "Post your reply"; 122 + case "quote": 123 + return "Add a comment..."; 124 + case "root": 125 + default: 126 + return "What's happening?!"; 127 + } 128 + }; 129 + 130 + const charsLeft = MAX_POST_LENGTH - postText.length; 131 + const isPostButtonDisabled = 132 + posting || !postText.trim() || isParentLoading || charsLeft < 0; 133 + 134 + function handleAttemptClose() { 135 + if (postText.trim() && !posting) { 136 + setCloseConfirmState(true); 137 + } else { 138 + setComposerState({ kind: "closed" }); 139 + } 140 + } 141 + 142 + function handleConfirmClose() { 143 + setComposerState({ kind: "closed" }); 144 + setCloseConfirmState(false); 145 + setPostText(""); 146 + } 147 + 148 + return ( 149 + <> 150 + <Dialog.Root 151 + open={composerState.kind !== "closed"} 152 + onOpenChange={(open) => { 153 + if (!open) handleAttemptClose(); 154 + }} 155 + > 156 + <Dialog.Portal> 157 + <Dialog.Overlay className="disablegutter fixed inset-0 z-50 bg-black/40 dark:bg-black/50 data-[state=open]:animate-fadeIn" /> 158 + 159 + <Dialog.Content className="fixed overflow-y-auto gutter inset-0 z-50 flex items-start justify-center pt-10 sm:pt-20 pb-[50dvh] sm:pb-[50dvh]"> 160 + <div className="bg-gray-50 dark:bg-gray-950 border border-gray-200 dark:border-gray-700 rounded-2xl shadow-xl w-full max-w-xl relative mx-4"> 161 + <div className="flex flex-row justify-between p-2"> 162 + <Dialog.Close asChild> 163 + <button 164 + className="h-8 w-8 flex items-center justify-center rounded-full text-gray-600 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800" 165 + disabled={posting} 166 + aria-label="Close" 167 + onClick={handleAttemptClose} 168 + > 169 + <svg 170 + xmlns="http://www.w3.org/2000/svg" 171 + width="20" 172 + height="20" 173 + viewBox="0 0 24 24" 174 + fill="none" 175 + stroke="currentColor" 176 + strokeWidth="2.5" 177 + strokeLinecap="round" 178 + strokeLinejoin="round" 179 + > 180 + <line x1="18" y1="6" x2="6" y2="18"></line> 181 + <line x1="6" y1="6" x2="18" y2="18"></line> 182 + </svg> 183 + </button> 184 + </Dialog.Close> 185 + 186 + <div className="flex-1" /> 187 + <div className="flex items-center gap-4"> 188 + <span 189 + className={`text-sm ${charsLeft < 0 ? "text-red-500" : "text-gray-500"}`} 190 + > 191 + {charsLeft} 192 + </span> 193 + <Button 194 + onClick={handlePost} 195 + disabled={isPostButtonDisabled} 196 + > 197 + {posting ? "Posting..." : "Post"} 198 + </Button> 199 + </div> 200 + </div> 201 + 202 + {postSuccess ? ( 203 + <div className="flex flex-col items-center justify-center py-16"> 204 + <span className="text-gray-500 text-6xl mb-4">โœ“</span> 205 + <span className="text-xl font-bold text-black dark:text-white"> 206 + Posted! 207 + </span> 208 + </div> 209 + ) : ( 210 + <div className="px-4"> 211 + {composerState.kind === "reply" && ( 212 + <div className="mb-1 -mx-4"> 213 + {isParentLoading ? ( 214 + <div className="text-sm text-gray-500 animate-pulse"> 215 + Loading parent post... 216 + </div> 217 + ) : parentUri ? ( 218 + <UniversalPostRendererATURILoader 219 + atUri={parentUri} 220 + bottomReplyLine 221 + bottomBorder={false} 222 + /> 223 + ) : ( 224 + <div className="text-sm text-red-500 rounded-lg border border-red-500/50 p-3"> 225 + Could not load parent post. 226 + </div> 227 + )} 228 + </div> 229 + )} 230 + 231 + <div className="flex w-full gap-1 flex-col"> 232 + <ProfileThing agent={agent} large /> 233 + <div className="flex pl-[50px]"> 234 + <AutoGrowTextarea 235 + className="w-full text-lg bg-transparent focus:outline-none resize-none placeholder:text-gray-500 text-black dark:text-white pb-2" 236 + rows={5} 237 + placeholder={getPlaceholder()} 238 + value={postText} 239 + onChange={(e) => setPostText(e.target.value)} 240 + disabled={posting} 241 + autoFocus 242 + /> 243 + </div> 244 + </div> 245 + 246 + {composerState.kind === "quote" && ( 247 + <div className="mb-4 ml-[50px] rounded-lg border border-gray-200 dark:border-gray-700 overflow-hidden"> 248 + {isParentLoading ? ( 249 + <div className="text-sm text-gray-500 animate-pulse"> 250 + Loading parent post... 251 + </div> 252 + ) : parentUri ? ( 253 + <UniversalPostRendererATURILoader 254 + atUri={parentUri} 255 + isQuote 256 + /> 257 + ) : ( 258 + <div className="text-sm text-red-500 rounded-lg border border-red-500/50 p-3"> 259 + Could not load parent post. 260 + </div> 261 + )} 262 + </div> 263 + )} 264 + 265 + {postError && ( 266 + <div className="text-red-500 text-sm my-2 text-center"> 267 + {postError} 268 + </div> 269 + )} 270 + </div> 271 + )} 272 + </div> 273 + </Dialog.Content> 274 + </Dialog.Portal> 275 + </Dialog.Root> 276 + 277 + {/* Close confirmation dialog */} 278 + <Dialog.Root open={closeConfirmState} onOpenChange={setCloseConfirmState}> 279 + <Dialog.Portal> 280 + 281 + <Dialog.Overlay className="disablegutter fixed inset-0 z-50 bg-black/40 dark:bg-black/50 data-[state=open]:animate-fadeIn" /> 282 + 283 + <Dialog.Content className="fixed gutter inset-0 z-50 flex items-start justify-center pt-30 sm:pt-40"> 284 + <div className="bg-gray-50 dark:bg-gray-950 border border-gray-200 dark:border-gray-700 rounded-2xl shadow-xl w-full max-w-md relative mx-4 py-6"> 285 + <div className="text-xl mb-4 text-center"> 286 + Discard your post? 287 + </div> 288 + <div className="text-md mb-4 text-center"> 289 + You will lose your draft 290 + </div> 291 + <div className="flex justify-end gap-2 px-6"> 292 + <Button 293 + onClick={handleConfirmClose} 294 + > 295 + Discard 296 + </Button> 297 + <Button 298 + variant={"outlined"} 299 + onClick={() => setCloseConfirmState(false)} 300 + > 301 + Cancel 302 + </Button> 303 + </div> 304 + </div> 305 + </Dialog.Content> 306 + </Dialog.Portal> 307 + </Dialog.Root> 308 + </> 309 + ); 310 + } 311 + 312 + function AutoGrowTextarea({ 313 + value, 314 + className, 315 + onChange, 316 + ...props 317 + }: React.DetailedHTMLProps< 318 + React.TextareaHTMLAttributes<HTMLTextAreaElement>, 319 + HTMLTextAreaElement 320 + >) { 321 + const ref = useRef<HTMLTextAreaElement>(null); 322 + 323 + useEffect(() => { 324 + const el = ref.current; 325 + if (!el) return; 326 + el.style.height = "auto"; 327 + el.style.height = el.scrollHeight + "px"; 328 + }, [value]); 329 + 330 + return ( 331 + <textarea 332 + ref={ref} 333 + className={className} 334 + value={value} 335 + onChange={onChange} 336 + {...props} 337 + /> 338 + ); 339 + }
+33
src/components/Header.tsx
··· 1 + import { Link, useRouter } from "@tanstack/react-router"; 2 + import { useAtom } from "jotai"; 3 + 4 + import { isAtTopAtom } from "~/utils/atoms"; 5 + 6 + export function Header({ 7 + backButtonCallback, 8 + title 9 + }: { 10 + backButtonCallback?: () => void; 11 + title?: string; 12 + }) { 13 + const router = useRouter(); 14 + const [isAtTop] = useAtom(isAtTopAtom); 15 + //const what = router.history. 16 + return ( 17 + <div className={`flex items-center gap-3 px-3 py-3 h-[52px] sticky top-0 bg-[var(--header-bg-light)] dark:bg-[var(--header-bg-dark)] z-10 border-0 sm:border-b ${!isAtTop && "shadow-sm"} sm:shadow-none sm:dark:bg-gray-950 sm:bg-white border-gray-200 dark:border-gray-700`}> 18 + {backButtonCallback ? (<Link 19 + to=".." 20 + //className="px-3 py-1 rounded hover:bg-gray-100 dark:hover:bg-gray-900 font-bold text-lg" 21 + className="p-2 rounded-full hover:bg-gray-100 dark:hover:bg-gray-900 font-bold text-lg" 22 + onClick={(e) => { 23 + e.preventDefault(); 24 + backButtonCallback(); 25 + }} 26 + aria-label="Go back" 27 + > 28 + <IconMaterialSymbolsArrowBack className="w-6 h-6" /> 29 + </Link>) : (<div className="w-[0px]" />)} 30 + <span className="text-[21px] sm:text-[19px] sm:font-semibold font-roboto">{title}</span> 31 + </div> 32 + ); 33 + }
+150
src/components/Import.tsx
··· 1 + import { AtUri } from "@atproto/api"; 2 + import { useNavigate, type UseNavigateResult } from "@tanstack/react-router"; 3 + import { useState } from "react"; 4 + 5 + /** 6 + * Basically the best equivalent to Search that i can do 7 + */ 8 + export function Import() { 9 + const [textInput, setTextInput] = useState<string | undefined>(); 10 + const navigate = useNavigate(); 11 + 12 + const handleEnter = () => { 13 + if (!textInput) return; 14 + handleImport({ 15 + text: textInput, 16 + navigate, 17 + }); 18 + }; 19 + 20 + return ( 21 + <div className="w-full relative"> 22 + <IconMaterialSymbolsSearch className="w-5 h-5 absolute left-4 top-1/2 -translate-y-1/2 text-gray-400 dark:text-gray-500" /> 23 + 24 + <input 25 + type="text" 26 + placeholder="Import..." 27 + value={textInput} 28 + onChange={(e) => setTextInput(e.target.value)} 29 + onKeyDown={(e) => { 30 + if (e.key === "Enter") handleEnter(); 31 + }} 32 + className="w-full h-12 pl-12 pr-4 rounded-full bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-gray-200 placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-gray-400 dark:focus:ring-gray-500 box-border transition" 33 + /> 34 + </div> 35 + ); 36 + } 37 + 38 + function handleImport({ 39 + text, 40 + navigate, 41 + }: { 42 + text: string; 43 + navigate: UseNavigateResult<string>; 44 + }) { 45 + const trimmed = text.trim(); 46 + // parse text 47 + /** 48 + * text might be 49 + * 1. bsky dot app url (reddwarf link segments might be uri encoded,) 50 + * 2. aturi 51 + * 3. plain handle 52 + * 4. plain did 53 + */ 54 + 55 + // 1. Check if itโ€™s a URL 56 + try { 57 + const url = new URL(text); 58 + const knownHosts = [ 59 + "bsky.app", 60 + "social.daniela.lol", 61 + "deer.social", 62 + "reddwarf.whey.party", 63 + "reddwarf.app", 64 + "main.bsky.dev", 65 + "catsky.social", 66 + "blacksky.community", 67 + "red-dwarf-social-app.whey.party", 68 + "zeppelin.social", 69 + ]; 70 + if (knownHosts.includes(url.hostname)) { 71 + // parse path to get URI or handle 72 + const path = decodeURIComponent(url.pathname.slice(1)); // remove leading / 73 + console.log("BSky URL path:", path); 74 + navigate({ 75 + to: `/${path}`, 76 + }); 77 + return; 78 + } 79 + } catch { 80 + // not a URL, continue 81 + } 82 + 83 + // 2. Check if text looks like an at-uri 84 + try { 85 + if (text.startsWith("at://")) { 86 + console.log("AT URI detected:", text); 87 + const aturi = new AtUri(text); 88 + switch (aturi.collection) { 89 + case "app.bsky.feed.post": { 90 + navigate({ 91 + to: "/profile/$did/post/$rkey", 92 + params: { 93 + did: aturi.host, 94 + rkey: aturi.rkey, 95 + }, 96 + }); 97 + return; 98 + } 99 + case "app.bsky.actor.profile": { 100 + navigate({ 101 + to: "/profile/$did", 102 + params: { 103 + did: aturi.host, 104 + }, 105 + }); 106 + return; 107 + } 108 + // todo add more handlers as more routes are added. like feeds, lists, etc etc thanks! 109 + default: { 110 + // continue 111 + } 112 + } 113 + } 114 + } catch { 115 + // continue 116 + } 117 + 118 + // 3. Plain handle (starts with @) 119 + try { 120 + if (text.startsWith("@")) { 121 + const handle = text.slice(1); 122 + console.log("Handle detected:", handle); 123 + navigate({ to: "/profile/$did", params: { did: handle } }); 124 + return; 125 + } 126 + } catch { 127 + // continue 128 + } 129 + 130 + // 4. Plain DID (starts with did:) 131 + try { 132 + if (text.startsWith("did:")) { 133 + console.log("did detected:", text); 134 + navigate({ to: "/profile/$did", params: { did: text } }); 135 + return; 136 + } 137 + } catch { 138 + // continue 139 + } 140 + 141 + // if all else fails 142 + 143 + // try { 144 + // // probably a user? 145 + // navigate({ to: "/profile/$did", params: { did: text } }); 146 + // return; 147 + // } catch { 148 + // // continue 149 + // } 150 + }
+168
src/components/InfiniteCustomFeed.tsx
··· 1 + import { useQueryClient } from "@tanstack/react-query"; 2 + import * as React from "react"; 3 + 4 + //import { useInView } from "react-intersection-observer"; 5 + import { UniversalPostRendererATURILoader } from "~/components/UniversalPostRenderer"; 6 + import { useAuth } from "~/providers/UnifiedAuthProvider"; 7 + import { 8 + useInfiniteQueryFeedSkeleton, 9 + // useQueryArbitrary, 10 + // useQueryIdentity, 11 + } from "~/utils/useQuery"; 12 + 13 + interface InfiniteCustomFeedProps { 14 + feedUri: string; 15 + pdsUrl?: string; 16 + feedServiceDid?: string; 17 + } 18 + 19 + export function InfiniteCustomFeed({ 20 + feedUri, 21 + pdsUrl, 22 + feedServiceDid, 23 + }: InfiniteCustomFeedProps) { 24 + const { agent } = useAuth(); 25 + const authed = !!agent?.did; 26 + 27 + // const identityresultmaybe = useQueryIdentity(agent?.did); 28 + // const identity = identityresultmaybe?.data; 29 + // const feedGenGetRecordQuery = useQueryArbitrary(feedUri); 30 + 31 + const { 32 + data, 33 + error, 34 + isLoading, 35 + isError, 36 + hasNextPage, 37 + fetchNextPage, 38 + isFetchingNextPage, 39 + refetch, 40 + isRefetching, 41 + queryKey, 42 + } = useInfiniteQueryFeedSkeleton({ 43 + feedUri: feedUri, 44 + agent: agent ?? undefined, 45 + isAuthed: authed ?? false, 46 + pdsUrl: pdsUrl, 47 + feedServiceDid: feedServiceDid, 48 + }); 49 + const queryClient = useQueryClient(); 50 + 51 + 52 + const handleRefresh = () => { 53 + queryClient.removeQueries({queryKey: queryKey}); 54 + //queryClient.invalidateQueries(["infinite-feed", feedUri] as const); 55 + refetch(); 56 + }; 57 + 58 + const allPosts = React.useMemo(() => { 59 + const flattenedPosts = data?.pages.flatMap((page) => page?.feed) ?? []; 60 + 61 + const seenUris = new Set<string>(); 62 + 63 + return flattenedPosts.filter((item) => { 64 + if (!item?.post) return false; 65 + 66 + if (seenUris.has(item.post)) { 67 + return false; 68 + } 69 + 70 + seenUris.add(item.post); 71 + 72 + return true; 73 + }); 74 + }, [data]); 75 + 76 + //const { ref, inView } = useInView(); 77 + 78 + // React.useEffect(() => { 79 + // if (inView && hasNextPage && !isFetchingNextPage) { 80 + // fetchNextPage(); 81 + // } 82 + // }, [inView, hasNextPage, isFetchingNextPage, fetchNextPage]); 83 + 84 + if (isLoading) { 85 + return <div className="p-4 text-center text-gray-500">Loading feed...</div>; 86 + } 87 + 88 + if (isError) { 89 + return ( 90 + <div className="p-4 text-center text-red-500">Error: {error.message}</div> 91 + ); 92 + } 93 + 94 + // const allPosts = 95 + // data?.pages.flatMap((page) => { 96 + // if (page) return page.feed; 97 + // }) ?? []; 98 + 99 + if (!allPosts || typeof allPosts !== "object" || allPosts.length === 0) { 100 + return ( 101 + <div className="p-4 text-center text-gray-500"> 102 + No posts in this feed. 103 + </div> 104 + ); 105 + } 106 + 107 + return ( 108 + <> 109 + {allPosts.map((item, i) => { 110 + if (item) 111 + return ( 112 + <UniversalPostRendererATURILoader 113 + key={item.post || i} 114 + atUri={item.post} 115 + feedviewpost={true} 116 + repostedby={!!item.reason?.$type && (item.reason as any)?.repost} 117 + /> 118 + ); 119 + })} 120 + {/* allPosts?: {allPosts ? "true" : "false"} 121 + hasNextPage?: {hasNextPage ? "true" : "false"} 122 + isFetchingNextPage?: {isFetchingNextPage ? "true" : "false"} */} 123 + {isFetchingNextPage && ( 124 + <div className="p-4 text-center text-gray-500">Loading more...</div> 125 + )} 126 + {hasNextPage && !isFetchingNextPage && ( 127 + <button 128 + onClick={() => fetchNextPage()} 129 + className="w-[calc(100%-2rem)] mx-4 my-4 px-4 py-2 bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-gray-200 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-700 font-semibold" 130 + > 131 + Load More Posts 132 + </button> 133 + )} 134 + {!hasNextPage && ( 135 + <div className="p-4 text-center text-gray-500">End of feed.</div> 136 + )} 137 + <button 138 + onClick={handleRefresh} 139 + disabled={isRefetching} 140 + className="sticky lg:bottom-4 bottom-22 ml-4 w-[42px] h-[42px] z-10 bg-gray-200 dark:bg-gray-800 hover:bg-gray-300 dark:hover:bg-gray-700 text-gray-50 p-[9px] rounded-full shadow-lg transition-transform duration-200 ease-in-out hover:scale-110 disabled:dark:bg-gray-900 disabled:bg-gray-100 disabled:cursor-not-allowed" 141 + aria-label="Refresh feed" 142 + > 143 + <RefreshIcon 144 + className={`h-6 w-6 text-gray-600 dark:text-gray-400 ${isRefetching && "animate-spin"}`} 145 + /> 146 + </button> 147 + </> 148 + ); 149 + } 150 + 151 + const RefreshIcon = (props: React.SVGProps<SVGSVGElement>) => ( 152 + <svg 153 + xmlns="http://www.w3.org/2000/svg" 154 + //width={360} 155 + //height={360} 156 + viewBox="0 0 24 24" 157 + {...props} 158 + > 159 + <path 160 + fill="none" 161 + stroke="currentColor" 162 + strokeLinecap="round" 163 + strokeLinejoin="round" 164 + strokeWidth={2} 165 + d="M20 11A8.1 8.1 0 0 0 4.5 9M4 5v4h4m-4 4a8.1 8.1 0 0 0 15.5 2m.5 4v-4h-4" 166 + ></path> 167 + </svg> 168 + );
+326 -170
src/components/Login.tsx
··· 1 - import React, { useEffect, useState, useRef } from "react"; 2 - import { useAuth } from "~/providers/PassAuthProvider"; 1 + // src/components/Login.tsx 2 + import AtpAgent, { Agent } from "@atproto/api"; 3 + import { useAtom } from "jotai"; 4 + import React, { useEffect, useRef, useState } from "react"; 3 5 4 - interface LoginProps { 6 + import { useAuth } from "~/providers/UnifiedAuthProvider"; 7 + import { imgCDNAtom } from "~/utils/atoms"; 8 + import { useQueryIdentity, useQueryProfile } from "~/utils/useQuery"; 9 + 10 + import { Button } from "./radix-m3-rd/Button"; 11 + 12 + // --- 1. The Main Component (Orchestrator with `compact` prop) --- 13 + export default function Login({ 14 + compact = false, 15 + popup = false, 16 + }: { 5 17 compact?: boolean; 18 + popup?: boolean; 19 + }) { 20 + const { status, agent, logout } = useAuth(); 21 + 22 + // Loading state can be styled differently based on the prop 23 + if (status === "loading") { 24 + return ( 25 + <div 26 + className={ 27 + compact 28 + ? "flex items-center justify-center p-1" 29 + : "p-6 bg-gray-100 dark:bg-gray-900 rounded-xl shadow border border-gray-200 dark:border-gray-800 mt-4 mx-4 flex justify-center items-center h-[280px]" 30 + } 31 + > 32 + <span 33 + className={`border-t-transparent rounded-full animate-spin ${ 34 + compact 35 + ? "w-5 h-5 border-2 border-gray-400" 36 + : "w-8 h-8 border-4 border-gray-400" 37 + }`} 38 + /> 39 + </div> 40 + ); 41 + } 42 + 43 + // --- LOGGED IN STATE --- 44 + if (status === "signedIn") { 45 + // Large view 46 + if (!compact) { 47 + return ( 48 + <div className="p-4 bg-gray-100 dark:bg-gray-900 rounded-xl border-gray-200 dark:border-gray-800 mt-4 mx-4"> 49 + <div className="flex flex-col items-center justify-center text-center"> 50 + <p className="text-lg font-semibold mb-4 text-gray-800 dark:text-gray-100"> 51 + You are logged in! 52 + </p> 53 + <ProfileThing agent={agent} large /> 54 + <Button 55 + onClick={logout} 56 + className="mt-4" 57 + > 58 + Log out 59 + </Button> 60 + </div> 61 + </div> 62 + ); 63 + } 64 + // Compact view 65 + return ( 66 + <div className="flex items-center gap-4"> 67 + <ProfileThing agent={agent} /> 68 + <button 69 + onClick={logout} 70 + className="text-sm bg-gray-600 hover:bg-gray-700 text-white rounded px-3 py-1 font-medium transition-colors" 71 + > 72 + Log out 73 + </button> 74 + </div> 75 + ); 76 + } 77 + 78 + // --- LOGGED OUT STATE --- 79 + if (!compact) { 80 + // Large view renders the form directly in the card 81 + return ( 82 + <div className="p-4 bg-gray-100 dark:bg-gray-900 rounded-xl border-gray-200 dark:border-gray-800 mt-4 mx-4"> 83 + <UnifiedLoginForm /> 84 + </div> 85 + ); 86 + } 87 + 88 + // Compact view renders a button that toggles the form in a dropdown 89 + return <CompactLoginButton popup={popup} />; 6 90 } 7 91 8 - export default function Login({ compact = false }: LoginProps) { 9 - const { loginStatus, login, logout, loading, authed } = useAuth(); 10 - const [user, setUser] = useState(""); 11 - const [password, setPassword] = useState(""); 12 - const [serviceURL, setServiceURL] = useState("bsky.social"); 13 - const [showLoginForm, setShowLoginForm] = useState(false); 92 + // --- 2. The Reusable, Self-Contained Login Form Component --- 93 + export function UnifiedLoginForm() { 94 + const [mode, setMode] = useState<"oauth" | "password">("oauth"); 95 + 96 + return ( 97 + <div> 98 + <div className="flex bg-gray-300 rounded-full dark:bg-gray-700 mb-4"> 99 + <TabButton 100 + label="OAuth" 101 + active={mode === "oauth"} 102 + onClick={() => setMode("oauth")} 103 + /> 104 + <TabButton 105 + label="Password" 106 + active={mode === "password"} 107 + onClick={() => setMode("password")} 108 + /> 109 + </div> 110 + {mode === "oauth" ? <OAuthForm /> : <PasswordForm />} 111 + </div> 112 + ); 113 + } 114 + 115 + // --- 3. Helper components for layouts, forms, and UI --- 116 + 117 + // A new component to contain the logic for the compact dropdown 118 + const CompactLoginButton = ({ popup }: { popup?: boolean }) => { 119 + const [showForm, setShowForm] = useState(false); 14 120 const formRef = useRef<HTMLDivElement>(null); 15 121 16 122 useEffect(() => { 17 123 function handleClickOutside(event: MouseEvent) { 18 124 if (formRef.current && !formRef.current.contains(event.target as Node)) { 19 - setShowLoginForm(false); 125 + setShowForm(false); 20 126 } 21 127 } 22 - 23 - if (showLoginForm) { 128 + if (showForm) { 24 129 document.addEventListener("mousedown", handleClickOutside); 25 130 } 26 - 27 131 return () => { 28 132 document.removeEventListener("mousedown", handleClickOutside); 29 133 }; 30 - }, [showLoginForm]); 134 + }, [showForm]); 31 135 32 - if (loading) { 33 - return ( 34 - <div className="flex items-center justify-center p-6 text-gray-500 dark:text-gray-400"> 35 - Loading... 36 - </div> 37 - ); 38 - } 136 + return ( 137 + <div className="relative" ref={formRef}> 138 + <button 139 + onClick={() => setShowForm(!showForm)} 140 + className="text-sm bg-gray-600 hover:bg-gray-700 text-white rounded-full px-3 py-1 font-medium transition-colors" 141 + > 142 + Log in 143 + </button> 144 + {showForm && ( 145 + <div 146 + className={`absolute ${popup ? `bottom-[calc(100%)]` : `top-full`} right-0 mt-2 w-80 bg-white dark:bg-gray-900 rounded-lg shadow-lg border border-gray-200 dark:border-gray-700 p-4 z-50`} 147 + > 148 + <UnifiedLoginForm /> 149 + </div> 150 + )} 151 + </div> 152 + ); 153 + }; 39 154 40 - if (compact) { 41 - if (authed) { 42 - return ( 155 + const TabButton = ({ 156 + label, 157 + active, 158 + onClick, 159 + }: { 160 + label: string; 161 + active: boolean; 162 + onClick: () => void; 163 + }) => ( 164 + <button 165 + onClick={onClick} 166 + className={`px-4 py-2 text-sm font-medium transition-colors rounded-full flex-1 ${ 167 + active 168 + ? "text-gray-50 dark:text-gray-200 border-gray-500 bg-gray-400 dark:bg-gray-500" 169 + : "text-gray-600 dark:text-gray-300 hover:text-gray-700 dark:hover:text-gray-200" 170 + }`} 171 + > 172 + {label} 173 + </button> 174 + ); 175 + 176 + const OAuthForm = () => { 177 + const { loginWithOAuth } = useAuth(); 178 + const [handle, setHandle] = useState(""); 179 + 180 + useEffect(() => { 181 + const lastHandle = localStorage.getItem("lastHandle"); 182 + if (lastHandle) setHandle(lastHandle); 183 + }, []); 184 + 185 + const handleSubmit = (e: React.FormEvent) => { 186 + e.preventDefault(); 187 + if (handle.trim()) { 188 + localStorage.setItem("lastHandle", handle); 189 + loginWithOAuth(handle); 190 + } 191 + }; 192 + return ( 193 + <form onSubmit={handleSubmit} className="flex flex-col gap-3"> 194 + <p className="text-xs text-gray-500 dark:text-gray-400"> 195 + Sign in with AT. Your password is never shared. 196 + </p> 197 + {/* <input 198 + type="text" 199 + placeholder="handle.bsky.social" 200 + value={handle} 201 + onChange={(e) => setHandle(e.target.value)} 202 + className="px-3 py-2 rounded border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 text-sm focus:outline-none focus:ring-2 focus:ring-gray-500" 203 + /> */} 204 + <div className="flex flex-col gap-3"> 205 + <div className="m3input-field m3input-label m3input-border size-md flex-1"> 206 + <input 207 + type="text" 208 + placeholder=" " 209 + value={handle} 210 + onChange={(e) => setHandle(e.target.value)} 211 + /> 212 + <label>AT Handle</label> 213 + </div> 43 214 <button 44 - onClick={logout} 45 - className="text-sm bg-gray-600 hover:bg-gray-700 text-white rounded px-3 py-1 font-medium transition-colors" 215 + type="submit" 216 + className="bg-gray-600 hover:bg-gray-700 text-white rounded-full px-4 py-2 font-medium text-sm transition-colors" 46 217 > 47 - Log out 218 + Log in 48 219 </button> 49 - ); 50 - } else { 51 - return ( 52 - <div className="relative" ref={formRef}> 53 - <button 54 - onClick={() => setShowLoginForm(!showLoginForm)} 55 - className="text-sm bg-gray-600 hover:bg-gray-700 text-white rounded px-3 py-1 font-medium transition-colors" 56 - > 57 - Log in 58 - </button> 59 - {showLoginForm && ( 60 - <div className="absolute top-full right-0 mt-2 w-80 bg-white dark:bg-gray-900 rounded-lg shadow-lg border border-gray-200 dark:border-gray-700 p-4 z-50"> 61 - <form 62 - onSubmit={(e) => { 63 - e.preventDefault(); 64 - login(user, password, `https://${serviceURL}`); 65 - setShowLoginForm(false); 66 - }} 67 - className="flex flex-col gap-3" 68 - > 69 - <p className="text-xs text-gray-500 dark:text-gray-400"> 70 - sorry for the temporary login, 71 - <br /> 72 - oauth will come soon enough i swear 73 - </p> 74 - <input 75 - type="text" 76 - placeholder="Username" 77 - value={user} 78 - onChange={(e) => setUser(e.target.value)} 79 - className="px-3 py-2 rounded border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500" 80 - autoComplete="username" 81 - /> 82 - <input 83 - type="password" 84 - placeholder="Password" 85 - value={password} 86 - onChange={(e) => setPassword(e.target.value)} 87 - className="px-3 py-2 rounded border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500" 88 - autoComplete="current-password" 89 - /> 90 - <input 91 - type="text" 92 - placeholder="bsky.social" 93 - value={serviceURL} 94 - onChange={(e) => setServiceURL(e.target.value)} 95 - className="px-3 py-2 rounded border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500" 96 - /> 97 - <button 98 - type="submit" 99 - className="bg-gray-600 hover:bg-gray-700 text-white rounded px-4 py-2 font-medium text-sm transition-colors" 100 - > 101 - Log in 102 - </button> 103 - </form> 104 - </div> 105 - )} 106 - </div> 107 - ); 220 + </div> 221 + </form> 222 + ); 223 + }; 224 + 225 + const PasswordForm = () => { 226 + const { loginWithPassword } = useAuth(); 227 + const [user, setUser] = useState(""); 228 + const [password, setPassword] = useState(""); 229 + const [serviceURL, setServiceURL] = useState("bsky.social"); 230 + const [error, setError] = useState<string | null>(null); 231 + 232 + useEffect(() => { 233 + const lastHandle = localStorage.getItem("lastHandle"); 234 + if (lastHandle) setUser(lastHandle); 235 + }, []); 236 + 237 + const handleSubmit = async (e: React.FormEvent) => { 238 + e.preventDefault(); 239 + setError(null); 240 + try { 241 + localStorage.setItem("lastHandle", user); 242 + await loginWithPassword(user, password, `https://${serviceURL}`); 243 + } catch (err) { 244 + setError("Login failed. Check your handle and App Password."); 108 245 } 109 - } 246 + }; 110 247 111 248 return ( 112 - <div className="p-6 bg-gray-100 dark:bg-gray-900 rounded-xl shadow border border-gray-200 dark:border-gray-800 mt-6 mx-4"> 113 - {authed ? ( 114 - <div className="flex flex-col items-center justify-center text-center"> 115 - <p className="text-lg font-semibold mb-6 text-gray-800 dark:text-gray-100"> 116 - You are logged in! 117 - </p> 118 - <button 119 - onClick={logout} 120 - className="bg-gray-600 hover:bg-gray-700 text-white rounded px-6 py-2 font-semibold text-base transition-colors" 121 - > 122 - Log out 123 - </button> 124 - </div> 125 - ) : ( 126 - <form 127 - onSubmit={(e) => { 128 - e.preventDefault(); 129 - login(user, password, `https://${serviceURL}`); 130 - }} 131 - className="flex flex-col gap-4" 132 - > 133 - <p className="text-sm text-gray-500 dark:text-gray-400 mb-2"> 134 - sorry for the temporary login, 135 - <br /> 136 - oauth will come soon enough i swear 137 - </p> 249 + <form onSubmit={handleSubmit} className="flex flex-col gap-3"> 250 + <p className="text-xs text-red-500 dark:text-red-400"> 251 + Warning: Less secure. Use an App Password. 252 + </p> 253 + {/* <input 254 + type="text" 255 + placeholder="handle.bsky.social" 256 + value={user} 257 + onChange={(e) => setUser(e.target.value)} 258 + className="px-3 py-2 rounded border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 text-sm focus:outline-none focus:ring-2 focus:ring-gray-500" 259 + autoComplete="username" 260 + /> 261 + <input 262 + type="password" 263 + placeholder="App Password" 264 + value={password} 265 + onChange={(e) => setPassword(e.target.value)} 266 + className="px-3 py-2 rounded border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 text-sm focus:outline-none focus:ring-2 focus:ring-gray-500" 267 + autoComplete="current-password" 268 + /> 269 + <input 270 + type="text" 271 + placeholder="PDS (e.g., bsky.social)" 272 + value={serviceURL} 273 + onChange={(e) => setServiceURL(e.target.value)} 274 + className="px-3 py-2 rounded border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 text-sm focus:outline-none focus:ring-2 focus:ring-gray-500" 275 + /> */} 276 + <div className="m3input-field m3input-label m3input-border size-md flex-1"> 138 277 <input 139 278 type="text" 140 - placeholder="Username" 279 + placeholder=" " 141 280 value={user} 142 281 onChange={(e) => setUser(e.target.value)} 143 - className="px-3 py-2 rounded border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 text-base focus:outline-none focus:ring-2 focus:ring-blue-500" 144 - autoComplete="username" 145 282 /> 283 + <label>AT Handle</label> 284 + </div> 285 + <div className="m3input-field m3input-label m3input-border size-md flex-1"> 146 286 <input 147 - type="password" 148 - placeholder="Password" 287 + type="text" 288 + placeholder=" " 149 289 value={password} 150 290 onChange={(e) => setPassword(e.target.value)} 151 - className="px-3 py-2 rounded border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 text-base focus:outline-none focus:ring-2 focus:ring-blue-500" 152 - autoComplete="current-password" 153 291 /> 292 + <label>App Password</label> 293 + </div> 294 + <div className="m3input-field m3input-label m3input-border size-md flex-1"> 154 295 <input 155 296 type="text" 156 - placeholder="bsky.social" 297 + placeholder=" " 157 298 value={serviceURL} 158 299 onChange={(e) => setServiceURL(e.target.value)} 159 - className="px-3 py-2 rounded border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 text-base focus:outline-none focus:ring-2 focus:ring-blue-500" 160 300 /> 161 - <button 162 - type="submit" 163 - className="bg-gray-600 hover:bg-gray-700 text-white rounded px-6 py-2 font-semibold text-base transition-colors mt-2" 164 - > 165 - Log in 166 - </button> 167 - </form> 168 - )} 169 - </div> 301 + <label>PDS</label> 302 + </div> 303 + {error && <p className="text-xs text-red-500">{error}</p>} 304 + <button 305 + type="submit" 306 + className="bg-gray-600 hover:bg-gray-700 text-white rounded-full px-4 py-2 font-medium text-sm transition-colors" 307 + > 308 + Log in 309 + </button> 310 + </form> 170 311 ); 171 - } 312 + }; 172 313 173 - export const ProfileThing = () => { 174 - const { agent, loading, loginStatus, authed } = useAuth(); 175 - const [response, setResponse] = useState<any>(null); 314 + // --- Profile Component (now supports a `large` prop for styling) --- 315 + export const ProfileThing = ({ 316 + agent, 317 + large = false, 318 + }: { 319 + agent: Agent | null; 320 + large?: boolean; 321 + }) => { 322 + const did = ((agent as AtpAgent)?.session?.did ?? 323 + (agent as AtpAgent)?.assertDid ?? 324 + agent?.did) as string | undefined; 325 + const { data: identity } = useQueryIdentity(did); 326 + const { data: profiledata } = useQueryProfile( 327 + `at://${did}/app.bsky.actor.profile/self` 328 + ); 329 + const profile = profiledata?.value; 176 330 177 - useEffect(() => { 178 - if (loginStatus && agent && !loading && authed) { 179 - fetchUser(); 180 - } 181 - // eslint-disable-next-line 182 - }, [loginStatus, agent, loading, authed]); 183 - 184 - const fetchUser = async () => { 185 - if (!agent) { 186 - console.error("Agent is null or undefined"); 187 - return; 188 - } 189 - const res = await agent.app.bsky.actor.getProfile({ 190 - actor: agent.assertDid, 191 - }); 192 - setResponse(res.data); 193 - }; 331 + const [imgcdn] = useAtom(imgCDNAtom) 194 332 195 - if (!authed) { 196 - return ( 197 - <div className="inline-block"> 198 - <span className="text-gray-100 text-base font-medium px-1.5"> 199 - Login 200 - </span> 201 - </div> 202 - ); 333 + function getAvatarUrl(p: typeof profile) { 334 + const link = p?.avatar?.ref?.["$link"]; 335 + if (!link || !did) return null; 336 + return `https://${imgcdn}/img/avatar/plain/${did}/${link}@jpeg`; 203 337 } 204 338 205 - if (!response) { 339 + if (!profiledata) { 206 340 return ( 207 - <div className="flex flex-col items-start gap-1.5"> 208 - <span className="w-5 h-5 border-2 border-gray-200 dark:border-gray-600 border-t-transparent rounded-full animate-spin inline-block" /> 209 - <span className="text-gray-100">Loading... </span> 341 + // Skeleton loader 342 + <div 343 + className={`flex items-center gap-2.5 animate-pulse ${large ? "mb-1" : ""}`} 344 + > 345 + <div 346 + className={`rounded-full bg-gray-300 dark:bg-gray-700 ${large ? "w-10 h-10" : "w-[30px] h-[30px]"}`} 347 + /> 348 + <div className="flex flex-col gap-2"> 349 + <div 350 + className={`bg-gray-300 dark:bg-gray-700 rounded ${large ? "h-4 w-28" : "h-3 w-20"}`} 351 + /> 352 + <div 353 + className={`bg-gray-300 dark:bg-gray-700 rounded ${large ? "h-4 w-20" : "h-3 w-16"}`} 354 + /> 355 + </div> 210 356 </div> 211 357 ); 212 358 } 213 359 214 360 return ( 215 - <div className="flex flex-row items-start gap-1.5"> 361 + <div 362 + className={`flex flex-row items-center gap-2.5 ${large ? "mb-1" : ""}`} 363 + > 216 364 <img 217 - src={response?.avatar} 365 + src={getAvatarUrl(profile) ?? undefined} 218 366 alt="avatar" 219 - className="w-[30px] h-[30px] rounded-full object-cover" 367 + className={`object-cover rounded-full ${large ? "w-10 h-10" : "w-[30px] h-[30px]"}`} 220 368 /> 221 - <div> 222 - <div className="text-gray-100 text-xs">{response?.displayName}</div> 223 - <div className="text-gray-100 text-xs">@{response?.handle}</div> 369 + <div className="flex flex-col items-start text-left"> 370 + <div 371 + className={`font-medium ${large ? "text-gray-800 dark:text-gray-100 text-md" : "text-gray-800 dark:text-gray-100 text-sm"}`} 372 + > 373 + {profile?.displayName} 374 + </div> 375 + <div 376 + className={` ${large ? "text-gray-500 dark:text-gray-400 text-sm" : "text-gray-500 dark:text-gray-400 text-xs"}`} 377 + > 378 + @{identity?.handle} 379 + </div> 224 380 </div> 225 381 </div> 226 382 );
+6
src/components/Star.tsx
··· 1 + import type { SVGProps } from 'react'; 2 + import React from 'react'; 3 + 4 + export function FluentEmojiHighContrastGlowingStar(props: SVGProps<SVGSVGElement>) { 5 + return (<svg xmlns="http://www.w3.org/2000/svg" width={32} height={32} viewBox="0 0 32 32" {...props}><g fill="currentColor"><path d="m28.979 17.003l-3.108.214c-.834.06-1.178 1.079-.542 1.608l2.388 1.955c.521.428 1.314.204 1.523-.428l.709-2.127c.219-.632-.292-1.273-.97-1.222M21.75 2.691l-.72 2.9c-.2.78.66 1.41 1.34.98l2.54-1.58c.55-.34.58-1.14.05-1.52l-1.78-1.29a.912.912 0 0 0-1.43.51M6.43 4.995l2.53 1.58c.68.43 1.54-.19 1.35-.98l-.72-2.9a.92.92 0 0 0-1.43-.52l-1.78 1.29c-.53.4-.5 1.19.05 1.53M4.185 20.713l2.29-1.92c.62-.52.29-1.53-.51-1.58l-2.98-.21a.92.92 0 0 0-.94 1.2l.68 2.09c.2.62.97.84 1.46.42m13.61 7.292l-1.12-2.77c-.3-.75-1.36-.75-1.66 0l-1.12 2.77c-.24.6.2 1.26.85 1.26h2.2a.92.92 0 0 0 .85-1.26"></path><path d="m17.565 3.324l1.726 3.72c.326.694.967 1.18 1.717 1.29l4.056.624c1.835.278 2.575 2.53 1.293 3.859L23.268 16a2.28 2.28 0 0 0-.612 1.964l.71 4.374c.307 1.885-1.687 3.293-3.354 2.37l-3.405-1.894a2.25 2.25 0 0 0-2.21 0l-3.404 1.895c-1.668.922-3.661-.486-3.355-2.37l.71-4.375A2.28 2.28 0 0 0 7.736 16l-3.088-3.184c-1.293-1.34-.543-3.581 1.293-3.859l4.055-.625a2.3 2.3 0 0 0 1.717-1.29l1.727-3.719c.819-1.765 3.306-1.765 4.124 0"></path></g></svg>); 6 + }
+1359 -1143
src/components/UniversalPostRenderer.tsx
··· 1 - import * as React from "react"; 2 - import { usePersistentStore } from "~/providers/PersistentStoreProvider"; 3 1 import { useNavigate } from "@tanstack/react-router"; 2 + import DOMPurify from "dompurify"; 3 + import { useAtom } from "jotai"; 4 + import { DropdownMenu } from "radix-ui"; 5 + import { HoverCard } from "radix-ui"; 6 + import * as React from "react"; 4 7 import { type SVGProps } from "react"; 5 8 9 + import { 10 + composerAtom, 11 + constellationURLAtom, 12 + imgCDNAtom, 13 + likedPostsAtom, 14 + } from "~/utils/atoms"; 15 + import { useHydratedEmbed } from "~/utils/useHydrated"; 16 + import { 17 + useQueryConstellation, 18 + useQueryIdentity, 19 + useQueryPost, 20 + useQueryProfile, 21 + yknowIReallyHateThisButWhateverGuardedConstructConstellationInfiniteQueryLinks, 22 + } from "~/utils/useQuery"; 23 + 6 24 function asTyped<T extends { $type: string }>(obj: T): $Typed<T> { 7 25 return obj as $Typed<T>; 8 26 } ··· 16 34 detailed?: boolean; 17 35 bottomReplyLine?: boolean; 18 36 topReplyLine?: boolean; 19 - bottomBorder?:boolean; 20 - feedviewpost?:boolean; 37 + bottomBorder?: boolean; 38 + feedviewpost?: boolean; 39 + repostedby?: string; 40 + style?: React.CSSProperties; 41 + ref?: React.Ref<HTMLDivElement>; 42 + dataIndexPropPass?: number; 43 + nopics?: boolean; 44 + lightboxCallback?: (d: LightboxProps) => void; 45 + maxReplies?: number; 46 + isQuote?: boolean; 21 47 } 22 48 23 - export async function cachedGetRecord({ 24 - atUri, 25 - cacheTimeout = CACHE_TIMEOUT, 26 - get, 27 - set, 28 - }: { 29 - atUri: string; 30 - //resolved: { pdsUrl: string; did: string } | null | undefined; 31 - cacheTimeout?: number; 32 - get: (key: string) => any; 33 - set: (key: string, value: string) => void; 34 - }): Promise<any> { 35 - const cacheKey = `record:${atUri}`; 36 - const cached = get(cacheKey); 37 - const now = Date.now(); 38 - if ( 39 - cached && 40 - cached.value && 41 - cached.time && 42 - now - cached.time < cacheTimeout 43 - ) { 44 - try { 45 - return JSON.parse(cached.value); 46 - } catch { 47 - // fall through to fetch 48 - } 49 - } 50 - const parsed = parseAtUri(atUri); 51 - if (!parsed) return null; 52 - const resolved = await cachedResolveIdentity({ 53 - didOrHandle: parsed.did, 54 - get, 55 - set, 56 - }); 57 - if (!resolved?.pdsUrl || !resolved?.did) 58 - throw new Error("Missing resolved PDS info"); 49 + // export async function cachedGetRecord({ 50 + // atUri, 51 + // cacheTimeout = CACHE_TIMEOUT, 52 + // get, 53 + // set, 54 + // }: { 55 + // atUri: string; 56 + // //resolved: { pdsUrl: string; did: string } | null | undefined; 57 + // cacheTimeout?: number; 58 + // get: (key: string) => any; 59 + // set: (key: string, value: string) => void; 60 + // }): Promise<any> { 61 + // const cacheKey = `record:${atUri}`; 62 + // const cached = get(cacheKey); 63 + // const now = Date.now(); 64 + // if ( 65 + // cached && 66 + // cached.value && 67 + // cached.time && 68 + // now - cached.time < cacheTimeout 69 + // ) { 70 + // try { 71 + // return JSON.parse(cached.value); 72 + // } catch { 73 + // // fall through to fetch 74 + // } 75 + // } 76 + // const parsed = parseAtUri(atUri); 77 + // if (!parsed) return null; 78 + // const resolved = await cachedResolveIdentity({ 79 + // didOrHandle: parsed.did, 80 + // get, 81 + // set, 82 + // }); 83 + // if (!resolved?.pdsUrl || !resolved?.did) 84 + // throw new Error("Missing resolved PDS info"); 59 85 60 - if (!parsed) throw new Error("Invalid atUri"); 61 - const { collection, rkey } = parsed; 62 - const url = `${ 63 - resolved.pdsUrl 64 - }/xrpc/com.atproto.repo.getRecord?repo=${encodeURIComponent( 65 - resolved.did, 66 - )}&collection=${encodeURIComponent(collection)}&rkey=${encodeURIComponent( 67 - rkey, 68 - )}`; 69 - const res = await fetch(url); 70 - if (!res.ok) throw new Error("Failed to fetch base record"); 71 - const data = await res.json(); 72 - set(cacheKey, JSON.stringify(data)); 73 - return data; 74 - } 86 + // if (!parsed) throw new Error("Invalid atUri"); 87 + // const { collection, rkey } = parsed; 88 + // const url = `${ 89 + // resolved.pdsUrl 90 + // }/xrpc/com.atproto.repo.getRecord?repo=${encodeURIComponent( 91 + // resolved.did, 92 + // )}&collection=${encodeURIComponent(collection)}&rkey=${encodeURIComponent( 93 + // rkey, 94 + // )}`; 95 + // const res = await fetch(url); 96 + // if (!res.ok) throw new Error("Failed to fetch base record"); 97 + // const data = await res.json(); 98 + // set(cacheKey, JSON.stringify(data)); 99 + // return data; 100 + // } 75 101 76 - export async function cachedResolveIdentity({ 77 - didOrHandle, 78 - cacheTimeout = HANDLE_DID_CACHE_TIMEOUT, 79 - get, 80 - set, 81 - }: { 82 - didOrHandle: string; 83 - cacheTimeout?: number; 84 - get: (key: string) => any; 85 - set: (key: string, value: string) => void; 86 - }): Promise<any> { 87 - const isDidInput = didOrHandle.startsWith("did:"); 88 - const cacheKey = `handleDid:${didOrHandle}`; 89 - const now = Date.now(); 90 - const cached = get(cacheKey); 91 - if ( 92 - cached && 93 - cached.value && 94 - cached.time && 95 - now - cached.time < cacheTimeout 96 - ) { 97 - try { 98 - return JSON.parse(cached.value); 99 - } catch {} 100 - } 101 - const url = `https://free-fly-24.deno.dev/?${ 102 - isDidInput 103 - ? `did=${encodeURIComponent(didOrHandle)}` 104 - : `handle=${encodeURIComponent(didOrHandle)}` 105 - }`; 106 - const res = await fetch(url); 107 - if (!res.ok) throw new Error("Failed to resolve handle/did"); 108 - const data = await res.json(); 109 - set(cacheKey, JSON.stringify(data)); 110 - if (!isDidInput && data.did) { 111 - set(`handleDid:${data.did}`, JSON.stringify(data)); 112 - } 113 - return data; 114 - } 102 + // export async function cachedResolveIdentity({ 103 + // didOrHandle, 104 + // cacheTimeout = HANDLE_DID_CACHE_TIMEOUT, 105 + // get, 106 + // set, 107 + // }: { 108 + // didOrHandle: string; 109 + // cacheTimeout?: number; 110 + // get: (key: string) => any; 111 + // set: (key: string, value: string) => void; 112 + // }): Promise<any> { 113 + // const isDidInput = didOrHandle.startsWith("did:"); 114 + // const cacheKey = `handleDid:${didOrHandle}`; 115 + // const now = Date.now(); 116 + // const cached = get(cacheKey); 117 + // if ( 118 + // cached && 119 + // cached.value && 120 + // cached.time && 121 + // now - cached.time < cacheTimeout 122 + // ) { 123 + // try { 124 + // return JSON.parse(cached.value); 125 + // } catch {} 126 + // } 127 + // const url = `https://free-fly-24.deno.dev/?${ 128 + // isDidInput 129 + // ? `did=${encodeURIComponent(didOrHandle)}` 130 + // : `handle=${encodeURIComponent(didOrHandle)}` 131 + // }`; 132 + // const res = await fetch(url); 133 + // if (!res.ok) throw new Error("Failed to resolve handle/did"); 134 + // const data = await res.json(); 135 + // set(cacheKey, JSON.stringify(data)); 136 + // if (!isDidInput && data.did) { 137 + // set(`handleDid:${data.did}`, JSON.stringify(data)); 138 + // } 139 + // return data; 140 + // } 115 141 116 142 export function UniversalPostRendererATURILoader({ 117 143 atUri, ··· 119 145 detailed = false, 120 146 bottomReplyLine, 121 147 topReplyLine, 122 - bottomBorder= true, 148 + bottomBorder = true, 123 149 feedviewpost = false, 150 + repostedby, 151 + style, 152 + ref, 153 + dataIndexPropPass, 154 + nopics, 155 + lightboxCallback, 156 + maxReplies, 157 + isQuote, 124 158 }: UniversalPostRendererATURILoaderProps) { 125 - console.log("atUri", atUri); 126 - const { get, set } = usePersistentStore(); 127 - const [record, setRecord] = React.useState<any>(null); 128 - const [links, setLinks] = React.useState<any>(null); 159 + // todo remove this once tree rendering is implemented, use a prop like isTree 160 + const TEMPLINEAR = true; 161 + // /*mass comment*/ console.log("atUri", atUri); 162 + //const { get, set } = usePersistentStore(); 163 + //const [record, setRecord] = React.useState<any>(null); 164 + //const [links, setLinks] = React.useState<any>(null); 129 165 //const [error, setError] = React.useState<string | null>(null); 130 166 //const [cacheTime, setCacheTime] = React.useState<number | null>(null); 131 - const [resolved, setResolved] = React.useState<any>(null); // { did, pdsUrl, bskyPds, handle } 132 - const [opProfile, setOpProfile] = React.useState<any>(null); 167 + //const [resolved, setResolved] = React.useState<any>(null); // { did, pdsUrl, bskyPds, handle } 168 + //const [opProfile, setOpProfile] = React.useState<any>(null); 133 169 // const [opProfileCacheTime, setOpProfileCacheTime] = React.useState< 134 170 // number | null 135 171 // >(null); 136 172 //const router = useRouter(); 137 173 138 - const parsed = React.useMemo(() => parseAtUri(atUri), [atUri]); 139 - const did = parsed?.did; 174 + //const parsed = React.useMemo(() => parseAtUri(atUri), [atUri]); 175 + const parsed = new AtUri(atUri); 176 + const did = parsed?.host; 140 177 const rkey = parsed?.rkey; 141 - console.log("did", did); 142 - console.log("rkey", rkey); 178 + // /*mass comment*/ console.log("did", did); 179 + // /*mass comment*/ console.log("rkey", rkey); 143 180 144 - React.useEffect(() => { 145 - const checkCache = async () => { 146 - const postUri = atUri; 147 - const cacheKey = `record:${postUri}`; 148 - const cached = await get(cacheKey); 149 - const now = Date.now(); 150 - console.log( 151 - "UniversalPostRenderer checking cache for", 152 - cacheKey, 153 - "cached:", 154 - !!cached, 155 - ); 156 - if ( 157 - cached && 158 - cached.value && 159 - cached.time && 160 - now - cached.time < CACHE_TIMEOUT 161 - ) { 162 - try { 163 - console.log("UniversalPostRenderer found cached data for", cacheKey); 164 - setRecord(JSON.parse(cached.value)); 165 - } catch { 166 - setRecord(null); 167 - } 168 - } 169 - }; 170 - checkCache(); 171 - }, [atUri, get]); 181 + // React.useEffect(() => { 182 + // const checkCache = async () => { 183 + // const postUri = atUri; 184 + // const cacheKey = `record:${postUri}`; 185 + // const cached = await get(cacheKey); 186 + // const now = Date.now(); 187 + // // /*mass comment*/ console.log( 188 + // "UniversalPostRenderer checking cache for", 189 + // cacheKey, 190 + // "cached:", 191 + // !!cached, 192 + // ); 193 + // if ( 194 + // cached && 195 + // cached.value && 196 + // cached.time && 197 + // now - cached.time < CACHE_TIMEOUT 198 + // ) { 199 + // try { 200 + // // /*mass comment*/ console.log("UniversalPostRenderer found cached data for", cacheKey); 201 + // setRecord(JSON.parse(cached.value)); 202 + // } catch { 203 + // setRecord(null); 204 + // } 205 + // } 206 + // }; 207 + // checkCache(); 208 + // }, [atUri, get]); 172 209 173 - React.useEffect(() => { 174 - if (!did || record) return; 175 - (async () => { 176 - try { 177 - const resolvedData = await cachedResolveIdentity({ 178 - didOrHandle: did, 179 - get, 180 - set, 181 - }); 182 - setResolved(resolvedData); 183 - } catch (e: any) { 184 - //setError("Failed to resolve handle/did: " + e?.message); 185 - } 186 - })(); 187 - }, [did, get, set, record]); 210 + const { 211 + data: postQuery, 212 + isLoading: isPostLoading, 213 + isError: isPostError, 214 + } = useQueryPost(atUri); 215 + //const record = postQuery?.value; 216 + 217 + // React.useEffect(() => { 218 + // if (!did || record) return; 219 + // (async () => { 220 + // try { 221 + // const resolvedData = await cachedResolveIdentity({ 222 + // didOrHandle: did, 223 + // get, 224 + // set, 225 + // }); 226 + // setResolved(resolvedData); 227 + // } catch (e: any) { 228 + // //setError("Failed to resolve handle/did: " + e?.message); 229 + // } 230 + // })(); 231 + // }, [did, get, set, record]); 232 + 233 + const { data: resolved } = useQueryIdentity(did || ""); 234 + 235 + // React.useEffect(() => { 236 + // if (!resolved || !resolved.pdsUrl || !resolved.did || !rkey || record) 237 + // return; 238 + // let ignore = false; 239 + // (async () => { 240 + // try { 241 + // const data = await cachedGetRecord({ 242 + // atUri, 243 + // get, 244 + // set, 245 + // }); 246 + // if (!ignore) setRecord(data); 247 + // } catch (e: any) { 248 + // //if (!ignore) setError("Failed to fetch base record: " + e?.message); 249 + // } 250 + // })(); 251 + // return () => { 252 + // ignore = true; 253 + // }; 254 + // }, [resolved, rkey, atUri, record]); 255 + 256 + // React.useEffect(() => { 257 + // if (!resolved || !resolved.did || !rkey) return; 258 + // const fetchLinks = async () => { 259 + // const postUri = atUri; 260 + // const cacheKey = `constellation:${postUri}`; 261 + // const cached = await get(cacheKey); 262 + // const now = Date.now(); 263 + // if ( 264 + // cached && 265 + // cached.value && 266 + // cached.time && 267 + // now - cached.time < CACHE_TIMEOUT 268 + // ) { 269 + // try { 270 + // const data = JSON.parse(cached.value); 271 + // setLinks(data); 272 + // if (onConstellation) onConstellation(data); 273 + // } catch { 274 + // setLinks(null); 275 + // } 276 + // //setCacheTime(cached.time); 277 + // return; 278 + // } 279 + // try { 280 + // const url = `https://constellation.microcosm.blue/links/all?target=${encodeURIComponent( 281 + // atUri, 282 + // )}`; 283 + // const res = await fetch(url); 284 + // if (!res.ok) throw new Error("Failed to fetch constellation links"); 285 + // const data = await res.json(); 286 + // setLinks(data); 287 + // //setCacheTime(now); 288 + // set(cacheKey, JSON.stringify(data)); 289 + // if (onConstellation) onConstellation(data); 290 + // } catch (e: any) { 291 + // //setError("Failed to fetch constellation links: " + e?.message); 292 + // } 293 + // }; 294 + // fetchLinks(); 295 + // }, [resolved, rkey, get, set, atUri, onConstellation]); 188 296 189 - React.useEffect(() => { 190 - if (!resolved || !resolved.pdsUrl || !resolved.did || !rkey || record) 191 - return; 192 - let ignore = false; 193 - (async () => { 194 - try { 195 - const data = await cachedGetRecord({ 196 - atUri, 197 - get, 198 - set, 199 - }); 200 - if (!ignore) setRecord(data); 201 - } catch (e: any) { 202 - //if (!ignore) setError("Failed to fetch base record: " + e?.message); 203 - } 204 - })(); 205 - return () => { 206 - ignore = true; 207 - }; 208 - }, [resolved, rkey, atUri, record]); 297 + const { data: links } = useQueryConstellation({ 298 + method: "/links/all", 299 + target: atUri, 300 + }); 209 301 210 - React.useEffect(() => { 211 - if (!resolved || !resolved.did || !rkey) return; 212 - const fetchLinks = async () => { 213 - const postUri = atUri; 214 - const cacheKey = `constellation:${postUri}`; 215 - const cached = await get(cacheKey); 216 - const now = Date.now(); 217 - if ( 218 - cached && 219 - cached.value && 220 - cached.time && 221 - now - cached.time < CACHE_TIMEOUT 222 - ) { 223 - try { 224 - const data = JSON.parse(cached.value); 225 - setLinks(data); 226 - if (onConstellation) onConstellation(data); 227 - } catch { 228 - setLinks(null); 229 - } 230 - //setCacheTime(cached.time); 231 - return; 232 - } 233 - try { 234 - const url = `https://constellation.microcosm.blue/links/all?target=${encodeURIComponent( 235 - atUri, 236 - )}`; 237 - const res = await fetch(url); 238 - if (!res.ok) throw new Error("Failed to fetch constellation links"); 239 - const data = await res.json(); 240 - setLinks(data); 241 - //setCacheTime(now); 242 - set(cacheKey, JSON.stringify(data)); 243 - if (onConstellation) onConstellation(data); 244 - } catch (e: any) { 245 - //setError("Failed to fetch constellation links: " + e?.message); 246 - } 247 - }; 248 - fetchLinks(); 249 - }, [resolved, rkey, get, set, atUri, onConstellation]); 302 + // React.useEffect(() => { 303 + // if (!record || !resolved || !resolved.did) return; 304 + // const fetchOpProfile = async () => { 305 + // const opDid = resolved.did; 306 + // const postUri = atUri; 307 + // const cacheKey = `profile:${postUri}`; 308 + // const cached = await get(cacheKey); 309 + // const now = Date.now(); 310 + // if ( 311 + // cached && 312 + // cached.value && 313 + // cached.time && 314 + // now - cached.time < CACHE_TIMEOUT 315 + // ) { 316 + // try { 317 + // setOpProfile(JSON.parse(cached.value)); 318 + // } catch { 319 + // setOpProfile(null); 320 + // } 321 + // //setOpProfileCacheTime(cached.time); 322 + // return; 323 + // } 324 + // try { 325 + // let opResolvedRaw = await get(`handleDid:${opDid}`); 326 + // let opResolved: any = null; 327 + // if ( 328 + // opResolvedRaw && 329 + // opResolvedRaw.value && 330 + // opResolvedRaw.time && 331 + // now - opResolvedRaw.time < HANDLE_DID_CACHE_TIMEOUT 332 + // ) { 333 + // try { 334 + // opResolved = JSON.parse(opResolvedRaw.value); 335 + // } catch { 336 + // opResolved = null; 337 + // } 338 + // } else { 339 + // const url = `https://free-fly-24.deno.dev/?did=${encodeURIComponent( 340 + // opDid, 341 + // )}`; 342 + // const res = await fetch(url); 343 + // if (!res.ok) throw new Error("Failed to resolve OP did"); 344 + // opResolved = await res.json(); 345 + // set(`handleDid:${opDid}`, JSON.stringify(opResolved)); 346 + // } 347 + // if (!opResolved || !opResolved.pdsUrl) 348 + // throw new Error("OP did resolution failed or missing pdsUrl"); 349 + // const profileUrl = `${ 350 + // opResolved.pdsUrl 351 + // }/xrpc/com.atproto.repo.getRecord?repo=${encodeURIComponent( 352 + // opDid, 353 + // )}&collection=app.bsky.actor.profile&rkey=self`; 354 + // const profileRes = await fetch(profileUrl); 355 + // if (!profileRes.ok) throw new Error("Failed to fetch OP profile"); 356 + // const profileData = await profileRes.json(); 357 + // setOpProfile(profileData); 358 + // //setOpProfileCacheTime(now); 359 + // set(cacheKey, JSON.stringify(profileData)); 360 + // } catch (e: any) { 361 + // //setError("Failed to fetch OP profile: " + e?.message); 362 + // } 363 + // }; 364 + // fetchOpProfile(); 365 + // }, [record, get, set, rkey, resolved, atUri]); 250 366 251 - React.useEffect(() => { 252 - if (!record || !resolved || !resolved.did) return; 253 - const fetchOpProfile = async () => { 254 - const opDid = resolved.did; 255 - const postUri = atUri; 256 - const cacheKey = `profile:${postUri}`; 257 - const cached = await get(cacheKey); 258 - const now = Date.now(); 259 - if ( 260 - cached && 261 - cached.value && 262 - cached.time && 263 - now - cached.time < CACHE_TIMEOUT 264 - ) { 265 - try { 266 - setOpProfile(JSON.parse(cached.value)); 267 - } catch { 268 - setOpProfile(null); 269 - } 270 - //setOpProfileCacheTime(cached.time); 271 - return; 272 - } 273 - try { 274 - let opResolvedRaw = await get(`handleDid:${opDid}`); 275 - let opResolved: any = null; 276 - if ( 277 - opResolvedRaw && 278 - opResolvedRaw.value && 279 - opResolvedRaw.time && 280 - now - opResolvedRaw.time < HANDLE_DID_CACHE_TIMEOUT 281 - ) { 282 - try { 283 - opResolved = JSON.parse(opResolvedRaw.value); 284 - } catch { 285 - opResolved = null; 286 - } 287 - } else { 288 - const url = `https://free-fly-24.deno.dev/?did=${encodeURIComponent( 289 - opDid, 290 - )}`; 291 - const res = await fetch(url); 292 - if (!res.ok) throw new Error("Failed to resolve OP did"); 293 - opResolved = await res.json(); 294 - set(`handleDid:${opDid}`, JSON.stringify(opResolved)); 295 - } 296 - if (!opResolved || !opResolved.pdsUrl) 297 - throw new Error("OP did resolution failed or missing pdsUrl"); 298 - const profileUrl = `${ 299 - opResolved.pdsUrl 300 - }/xrpc/com.atproto.repo.getRecord?repo=${encodeURIComponent( 301 - opDid, 302 - )}&collection=app.bsky.actor.profile&rkey=self`; 303 - const profileRes = await fetch(profileUrl); 304 - if (!profileRes.ok) throw new Error("Failed to fetch OP profile"); 305 - const profileData = await profileRes.json(); 306 - setOpProfile(profileData); 307 - //setOpProfileCacheTime(now); 308 - set(cacheKey, JSON.stringify(profileData)); 309 - } catch (e: any) { 310 - //setError("Failed to fetch OP profile: " + e?.message); 311 - } 312 - }; 313 - fetchOpProfile(); 314 - }, [record, get, set, rkey, resolved, atUri]); 367 + const { data: opProfile } = useQueryProfile( 368 + resolved ? `at://${resolved?.did}/app.bsky.actor.profile/self` : undefined 369 + ); 315 370 316 371 // const displayName = 317 372 // opProfile?.value?.displayName || resolved?.handle || resolved?.did; ··· 328 383 const [replies, setReplies] = React.useState<number | null>(null); 329 384 330 385 React.useEffect(() => { 331 - console.log(JSON.stringify(links, null, 2)); 386 + // /*mass comment*/ console.log(JSON.stringify(links, null, 2)); 332 387 setLikes( 333 388 links 334 389 ? links?.links?.["app.bsky.feed.like"]?.[".subject.uri"]?.records || 0 335 - : null, 390 + : null 336 391 ); 337 392 setReposts( 338 393 links 339 394 ? links?.links?.["app.bsky.feed.repost"]?.[".subject.uri"]?.records || 0 340 - : null, 395 + : null 341 396 ); 342 397 setReplies( 343 398 links 344 399 ? links?.links?.["app.bsky.feed.post"]?.[".reply.parent.uri"] 345 400 ?.records || 0 346 - : null, 401 + : null 347 402 ); 348 403 }, [links]); 349 404 405 + // const { data: repliesData } = useQueryConstellation({ 406 + // method: "/links", 407 + // target: atUri, 408 + // collection: "app.bsky.feed.post", 409 + // path: ".reply.parent.uri", 410 + // }); 411 + 412 + const [constellationurl] = useAtom(constellationURLAtom); 413 + 414 + const infinitequeryresults = useInfiniteQuery({ 415 + ...yknowIReallyHateThisButWhateverGuardedConstructConstellationInfiniteQueryLinks( 416 + { 417 + constellation: constellationurl, 418 + method: "/links", 419 + target: atUri, 420 + collection: "app.bsky.feed.post", 421 + path: ".reply.parent.uri", 422 + } 423 + ), 424 + enabled: !!atUri && !!maxReplies && !isQuote, 425 + }); 426 + 427 + const { 428 + data: repliesData, 429 + // fetchNextPage, 430 + // hasNextPage, 431 + // isFetchingNextPage, 432 + } = infinitequeryresults; 433 + 434 + // auto-fetch all pages 435 + useEffect(() => { 436 + if (!maxReplies || isQuote || TEMPLINEAR) return; 437 + if ( 438 + infinitequeryresults.hasNextPage && 439 + !infinitequeryresults.isFetchingNextPage 440 + ) { 441 + console.log("Fetching the next page..."); 442 + infinitequeryresults.fetchNextPage(); 443 + } 444 + }, [TEMPLINEAR, infinitequeryresults, isQuote, maxReplies]); 445 + 446 + const replyAturis = repliesData 447 + ? repliesData.pages.flatMap((page) => 448 + page 449 + ? page.linking_records.map((record) => { 450 + const aturi = `at://${record.did}/${record.collection}/${record.rkey}`; 451 + return aturi; 452 + }) 453 + : [] 454 + ) 455 + : []; 456 + 457 + //const [oldestOpsReply, setOldestOpsReply] = useState<string | undefined>(undefined); 458 + 459 + const { oldestOpsReply, oldestOpsReplyElseNewestNonOpsReply } = (() => { 460 + if (isQuote || !replyAturis || replyAturis.length === 0 || !maxReplies) 461 + return { 462 + oldestOpsReply: undefined, 463 + oldestOpsReplyElseNewestNonOpsReply: undefined, 464 + }; 465 + 466 + const opdid = new AtUri( 467 + //postQuery?.value.reply?.root.uri ?? postQuery?.uri ?? atUri 468 + atUri 469 + ).host; 470 + 471 + const opReplies = replyAturis.filter( 472 + (aturi) => new AtUri(aturi).host === opdid 473 + ); 474 + 475 + if (opReplies.length > 0) { 476 + const opreply = opReplies[opReplies.length - 1]; 477 + //setOldestOpsReply(opreply); 478 + return { 479 + oldestOpsReply: opreply, 480 + oldestOpsReplyElseNewestNonOpsReply: opreply, 481 + }; 482 + } else { 483 + return { 484 + oldestOpsReply: undefined, 485 + oldestOpsReplyElseNewestNonOpsReply: replyAturis[0], 486 + }; 487 + } 488 + })(); 489 + 350 490 // const navigateToProfile = (e: React.MouseEvent) => { 351 491 // e.stopPropagation(); 352 492 // if (resolved?.did) { ··· 356 496 // }); 357 497 // } 358 498 // }; 499 + if (!postQuery?.value) { 500 + // deleted post more often than a non-resolvable post 501 + return <></>; 502 + } 359 503 360 504 return ( 361 - <UniversalPostRendererRawRecordShim 362 - detailed={detailed} 363 - postRecord={record} 364 - profileRecord={opProfile} 365 - aturi={atUri} 366 - resolved={resolved} 367 - likesCount={likes} 368 - repostsCount={reposts} 369 - repliesCount={replies} 370 - bottomReplyLine={bottomReplyLine} 371 - topReplyLine={topReplyLine} 372 - bottomBorder={bottomBorder} 373 - feedviewpost={feedviewpost} 374 - /> 505 + <> 506 + {/* <span>uprrs {maxReplies} {!!maxReplies&&!!oldestOpsReplyElseNewestNonOpsReply ? "true" : "false"}</span> */} 507 + <UniversalPostRendererRawRecordShim 508 + detailed={detailed} 509 + postRecord={postQuery} 510 + profileRecord={opProfile} 511 + aturi={atUri} 512 + resolved={resolved} 513 + likesCount={likes} 514 + repostsCount={reposts} 515 + repliesCount={replies} 516 + bottomReplyLine={ 517 + maxReplies && oldestOpsReplyElseNewestNonOpsReply 518 + ? true 519 + : maxReplies && !oldestOpsReplyElseNewestNonOpsReply 520 + ? false 521 + : (maxReplies === 0 && (!replies || (!!replies && replies === 0))) ? false : bottomReplyLine 522 + } 523 + topReplyLine={topReplyLine} 524 + //bottomBorder={maxReplies&&oldestOpsReplyElseNewestNonOpsReply ? false : bottomBorder} 525 + bottomBorder={ 526 + maxReplies && oldestOpsReplyElseNewestNonOpsReply 527 + ? false 528 + : maxReplies === 0 529 + ? false 530 + : bottomBorder 531 + } 532 + feedviewpost={feedviewpost} 533 + repostedby={repostedby} 534 + //style={{...style, background: oldestOpsReply === atUri ? "Red" : undefined}} 535 + style={style} 536 + ref={ref} 537 + dataIndexPropPass={dataIndexPropPass} 538 + nopics={nopics} 539 + lightboxCallback={lightboxCallback} 540 + maxReplies={maxReplies} 541 + isQuote={isQuote} 542 + /> 543 + <> 544 + {(maxReplies && maxReplies === 0 && replies && replies > 0) ? ( 545 + <> 546 + {/* <div>hello</div> */} 547 + <MoreReplies atUri={atUri} /> 548 + </> 549 + ) : (<></>)} 550 + </> 551 + {!isQuote && oldestOpsReplyElseNewestNonOpsReply && ( 552 + <> 553 + {/* <span>hello {maxReplies}</span> */} 554 + <UniversalPostRendererATURILoader 555 + //detailed={detailed} 556 + atUri={oldestOpsReplyElseNewestNonOpsReply} 557 + bottomReplyLine={(maxReplies ?? 0) > 0} 558 + topReplyLine={ 559 + (!!(maxReplies && maxReplies - 1 === 0) && 560 + !!(replies && replies > 0)) || 561 + !!((maxReplies ?? 0) > 1) 562 + } 563 + bottomBorder={bottomBorder} 564 + feedviewpost={feedviewpost} 565 + repostedby={repostedby} 566 + style={style} 567 + ref={ref} 568 + dataIndexPropPass={dataIndexPropPass} 569 + nopics={nopics} 570 + lightboxCallback={lightboxCallback} 571 + maxReplies={ 572 + maxReplies && maxReplies > 0 ? maxReplies - 1 : undefined 573 + } 574 + /> 575 + </> 576 + )} 577 + </> 578 + ); 579 + } 580 + 581 + function MoreReplies({ atUri }: { atUri: string }) { 582 + const navigate = useNavigate(); 583 + const aturio = new AtUri(atUri); 584 + return ( 585 + <div 586 + onClick={() => 587 + navigate({ 588 + to: "/profile/$did/post/$rkey", 589 + params: { did: aturio.host, rkey: aturio.rkey }, 590 + }) 591 + } 592 + className="border-b border-gray-300 dark:border-gray-800 flex flex-row px-4 cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-900 transition-colors" 593 + > 594 + <div className="w-[42px] h-12 flex flex-col items-center justify-center"> 595 + <div 596 + style={{ 597 + width: 2, 598 + height: "100%", 599 + backgroundImage: 600 + "repeating-linear-gradient(to bottom, var(--color-gray-500) 0, var(--color-gray-500) 4px, transparent 4px, transparent 8px)", 601 + opacity: 0.5, 602 + }} 603 + className="dark:bg-[repeating-linear-gradient(to_bottom,var(--color-gray-500)_0,var(--color-gray-400)_4px,transparent_4px,transparent_8px)]" 604 + //className="border-gray-400 dark:border-gray-500" 605 + /> 606 + </div> 607 + 608 + <div className="flex items-center pl-3 text-sm text-gray-500 dark:text-gray-400 select-none"> 609 + More Replies 610 + </div> 611 + </div> 375 612 ); 376 613 } 377 614 615 + function getAvatarUrl(opProfile: any, did: string, cdn: string) { 616 + const link = opProfile?.value?.avatar?.ref?.["$link"]; 617 + if (!link) return null; 618 + return `https://${cdn}/img/avatar/plain/${did}/${link}@jpeg`; 619 + } 620 + 378 621 export function UniversalPostRendererRawRecordShim({ 379 622 postRecord, 380 623 profileRecord, ··· 386 629 detailed = false, 387 630 bottomReplyLine = false, 388 631 topReplyLine = false, 389 - bottomBorder= true, 390 - feedviewpost= false, 632 + bottomBorder = true, 633 + feedviewpost = false, 634 + repostedby, 635 + style, 636 + ref, 637 + dataIndexPropPass, 638 + nopics, 639 + lightboxCallback, 640 + maxReplies, 641 + isQuote, 391 642 }: { 392 643 postRecord: any; 393 644 profileRecord: any; ··· 401 652 topReplyLine?: boolean; 402 653 bottomBorder?: boolean; 403 654 feedviewpost?: boolean; 655 + repostedby?: string; 656 + style?: React.CSSProperties; 657 + ref?: React.Ref<HTMLDivElement>; 658 + dataIndexPropPass?: number; 659 + nopics?: boolean; 660 + lightboxCallback?: (d: LightboxProps) => void; 661 + maxReplies?: number; 662 + isQuote?: boolean; 404 663 }) { 664 + // /*mass comment*/ console.log(`received aturi: ${aturi} of post content: ${postRecord}`); 405 665 const navigate = useNavigate(); 406 666 407 - const { get, set } = usePersistentStore(); 408 - function getAvatarUrl(opProfile: any) { 409 - const link = opProfile?.value?.avatar?.ref?.["$link"]; 410 - if (!link) return null; 411 - return `https://cdn.bsky.app/img/avatar/plain/${resolved?.did}/${link}@jpeg`; 412 - } 667 + //const { get, set } = usePersistentStore(); 668 + // const [hydratedEmbed, setHydratedEmbed] = useState<any>(undefined); 413 669 414 - const [hydratedEmbed, setHydratedEmbed] = useState<any>(undefined); 670 + // useEffect(() => { 671 + // const run = async () => { 672 + // if (!postRecord?.value?.embed) return; 673 + // const embed = postRecord?.value?.embed; 674 + // if (!embed || !embed.$type) { 675 + // setHydratedEmbed(undefined); 676 + // return; 677 + // } 415 678 416 - useEffect(() => { 417 - const run = async () => { 418 - if (!postRecord?.value?.embed) return; 419 - const embed = postRecord?.value?.embed; 420 - if (!embed || !embed.$type) { 421 - setHydratedEmbed(undefined); 422 - return; 423 - } 679 + // try { 680 + // let result: any; 424 681 425 - try { 426 - let result: any; 682 + // if (embed?.$type === "app.bsky.embed.recordWithMedia") { 683 + // const mediaEmbed = embed.media; 427 684 428 - if (embed?.$type === "app.bsky.embed.recordWithMedia") { 429 - const mediaEmbed = embed.media; 685 + // let hydratedMedia; 686 + // if (mediaEmbed?.$type === "app.bsky.embed.images") { 687 + // hydratedMedia = hydrateEmbedImages(mediaEmbed, resolved?.did); 688 + // } else if (mediaEmbed?.$type === "app.bsky.embed.external") { 689 + // hydratedMedia = hydrateEmbedExternal(mediaEmbed, resolved?.did); 690 + // } else if (mediaEmbed?.$type === "app.bsky.embed.video") { 691 + // hydratedMedia = hydrateEmbedVideo(mediaEmbed, resolved?.did); 692 + // } else { 693 + // throw new Error("idiot"); 694 + // } 695 + // if (!hydratedMedia) throw new Error("idiot"); 430 696 431 - let hydratedMedia; 432 - if (mediaEmbed?.$type === "app.bsky.embed.images") { 433 - hydratedMedia = hydrateEmbedImages(mediaEmbed, resolved?.did); 434 - } else if (mediaEmbed?.$type === "app.bsky.embed.external") { 435 - hydratedMedia = hydrateEmbedExternal(mediaEmbed, resolved?.did); 436 - } else if (mediaEmbed?.$type === "app.bsky.embed.video") { 437 - hydratedMedia = hydrateEmbedVideo(mediaEmbed, resolved?.did); 438 - } else { 439 - throw new Error("idiot"); 440 - } 441 - if (!hydratedMedia) throw new Error("idiot"); 697 + // // hydrate the outer recordWithMedia now using the hydrated media 698 + // result = await hydrateEmbedRecordWithMedia( 699 + // embed, 700 + // resolved?.did, 701 + // hydratedMedia, 702 + // get, 703 + // set, 704 + // ); 705 + // } else { 706 + // const hydrated = 707 + // embed?.$type === "app.bsky.embed.images" 708 + // ? hydrateEmbedImages(embed, resolved?.did) 709 + // : embed?.$type === "app.bsky.embed.external" 710 + // ? hydrateEmbedExternal(embed, resolved?.did) 711 + // : embed?.$type === "app.bsky.embed.video" 712 + // ? hydrateEmbedVideo(embed, resolved?.did) 713 + // : embed?.$type === "app.bsky.embed.record" 714 + // ? hydrateEmbedRecord(embed, resolved?.did, get, set) 715 + // : undefined; 442 716 443 - // hydrate the outer recordWithMedia now using the hydrated media 444 - result = await hydrateEmbedRecordWithMedia( 445 - embed, 446 - resolved?.did, 447 - hydratedMedia, 448 - get, 449 - set, 450 - ); 451 - } else { 452 - const hydrated = 453 - embed?.$type === "app.bsky.embed.images" 454 - ? hydrateEmbedImages(embed, resolved?.did) 455 - : embed?.$type === "app.bsky.embed.external" 456 - ? hydrateEmbedExternal(embed, resolved?.did) 457 - : embed?.$type === "app.bsky.embed.video" 458 - ? hydrateEmbedVideo(embed, resolved?.did) 459 - : embed?.$type === "app.bsky.embed.record" 460 - ? hydrateEmbedRecord(embed, resolved?.did, get, set) 461 - : undefined; 717 + // result = hydrated instanceof Promise ? await hydrated : hydrated; 718 + // } 719 + 720 + // // /*mass comment*/ console.log( 721 + // String(result) + " hydrateEmbedRecordWithMedia hey hyeh ye", 722 + // ); 723 + // setHydratedEmbed(result); 724 + // } catch (e) { 725 + // console.error("Error hydrating embed", e); 726 + // setHydratedEmbed(undefined); 727 + // } 728 + // }; 462 729 463 - result = hydrated instanceof Promise ? await hydrated : hydrated; 464 - } 730 + // run(); 731 + // }, [postRecord, resolved?.did]); 465 732 466 - console.log( 467 - String(result) + " hydrateEmbedRecordWithMedia hey hyeh ye", 468 - ); 469 - setHydratedEmbed(result); 470 - } catch (e) { 471 - console.error("Error hydrating embed", e); 472 - setHydratedEmbed(undefined); 473 - } 474 - }; 733 + const { 734 + data: hydratedEmbed, 735 + isLoading: isEmbedLoading, 736 + error: embedError, 737 + } = useHydratedEmbed(postRecord?.value?.embed, resolved?.did); 475 738 476 - run(); 477 - }, [postRecord, resolved?.did]); 739 + const [imgcdn] = useAtom(imgCDNAtom); 478 740 479 - const parsedaturi = parseAtUri(aturi); 741 + const parsedaturi = new AtUri(aturi); //parseAtUri(aturi); 480 742 481 - const fakepost = React.useMemo<AppBskyFeedDefs.PostView>(() => ({ 482 - $type: "app.bsky.feed.defs#postView", 483 - uri: aturi, 484 - cid: postRecord?.cid || "", 485 - author: { 743 + const fakeprofileviewbasic = React.useMemo<AppBskyActorDefs.ProfileViewBasic>( 744 + () => ({ 486 745 did: resolved?.did || "", 487 746 handle: resolved?.handle || "", 488 747 displayName: profileRecord?.value?.displayName || "", 489 - avatar: getAvatarUrl(profileRecord) || "", 748 + avatar: getAvatarUrl(profileRecord, resolved?.did, imgcdn) || "", 490 749 viewer: undefined, 491 750 labels: profileRecord?.labels || undefined, 492 751 verification: undefined, 493 - }, 494 - record: postRecord?.value || {}, 495 - embed: hydratedEmbed ?? undefined, 496 - replyCount: repliesCount ?? 0, 497 - repostCount: repostsCount ?? 0, 498 - likeCount: likesCount ?? 0, 499 - quoteCount: 0, 500 - indexedAt: postRecord?.value?.createdAt || "", 501 - viewer: undefined, 502 - labels: postRecord?.labels || undefined, 503 - threadgate: undefined, 504 - }), [ 505 - aturi, 506 - postRecord, 507 - profileRecord, 508 - hydratedEmbed, 509 - repliesCount, 510 - repostsCount, 511 - likesCount, 512 - resolved, 513 - ]); 752 + }), 753 + [imgcdn, profileRecord, resolved?.did, resolved?.handle] 754 + ); 514 755 515 - const [feedviewpostreplyhandle, setFeedviewpostreplyhandle] = useState<string | undefined>(undefined); 756 + const fakeprofileviewdetailed = 757 + React.useMemo<AppBskyActorDefs.ProfileViewDetailed>( 758 + () => ({ 759 + ...fakeprofileviewbasic, 760 + $type: "app.bsky.actor.defs#profileViewDetailed", 761 + description: profileRecord?.value?.description || undefined, 762 + }), 763 + [fakeprofileviewbasic, profileRecord?.value?.description] 764 + ); 516 765 517 - useEffect(() => { 518 - if(!feedviewpost) return; 519 - let cancelled = false; 766 + const fakepost = React.useMemo<AppBskyFeedDefs.PostView>( 767 + () => ({ 768 + $type: "app.bsky.feed.defs#postView", 769 + uri: aturi, 770 + cid: postRecord?.cid || "", 771 + author: fakeprofileviewbasic, 772 + record: postRecord?.value || {}, 773 + embed: hydratedEmbed ?? undefined, 774 + replyCount: repliesCount ?? 0, 775 + repostCount: repostsCount ?? 0, 776 + likeCount: likesCount ?? 0, 777 + quoteCount: 0, 778 + indexedAt: postRecord?.value?.createdAt || "", 779 + viewer: undefined, 780 + labels: postRecord?.labels || undefined, 781 + threadgate: undefined, 782 + }), 783 + [ 784 + aturi, 785 + postRecord?.cid, 786 + postRecord?.value, 787 + postRecord?.labels, 788 + fakeprofileviewbasic, 789 + hydratedEmbed, 790 + repliesCount, 791 + repostsCount, 792 + likesCount, 793 + ] 794 + ); 520 795 521 - const run = async () => { 522 - const thereply = (fakepost?.record as AppBskyFeedPost.Record)?.reply?.parent?.uri; 523 - const feedviewpostreplydid = thereply ? new AtUri(thereply).host : undefined; 796 + //const [feedviewpostreplyhandle, setFeedviewpostreplyhandle] = useState<string | undefined>(undefined); 524 797 525 - if (feedviewpostreplydid) { 526 - const opi = await cachedResolveIdentity({ 527 - didOrHandle: feedviewpostreplydid, 528 - get, 529 - set, 530 - }); 798 + // useEffect(() => { 799 + // if(!feedviewpost) return; 800 + // let cancelled = false; 531 801 532 - if (!cancelled) { 533 - setFeedviewpostreplyhandle(opi?.handle); 534 - } 535 - } 536 - }; 802 + // const run = async () => { 803 + // const thereply = (fakepost?.record as AppBskyFeedPost.Record)?.reply?.parent?.uri; 804 + // const feedviewpostreplydid = thereply ? new AtUri(thereply).host : undefined; 537 805 538 - run(); 806 + // if (feedviewpostreplydid) { 807 + // const opi = await cachedResolveIdentity({ 808 + // didOrHandle: feedviewpostreplydid, 809 + // get, 810 + // set, 811 + // }); 812 + 813 + // if (!cancelled) { 814 + // setFeedviewpostreplyhandle(opi?.handle); 815 + // } 816 + // } 817 + // }; 539 818 540 - return () => { 541 - cancelled = true; 542 - }; 543 - }, [fakepost, get, set]); 819 + // run(); 544 820 821 + // return () => { 822 + // cancelled = true; 823 + // }; 824 + // }, [fakepost, get, set]); 825 + const thereply = (fakepost?.record as AppBskyFeedPost.Record)?.reply?.parent 826 + ?.uri; 827 + const feedviewpostreplydid = thereply ? new AtUri(thereply).host : undefined; 828 + const replyhookvalue = useQueryIdentity( 829 + feedviewpost ? feedviewpostreplydid : undefined 830 + ); 831 + const feedviewpostreplyhandle = replyhookvalue?.data?.handle; 832 + 833 + const aturirepostbydid = repostedby ? new AtUri(repostedby).host : undefined; 834 + const repostedbyhookvalue = useQueryIdentity( 835 + repostedby ? aturirepostbydid : undefined 836 + ); 837 + const feedviewpostrepostedbyhandle = repostedbyhookvalue?.data?.handle; 545 838 return ( 546 839 <> 547 840 {/* <p> ··· 553 846 parsedaturi && 554 847 navigate({ 555 848 to: "/profile/$did/post/$rkey", 556 - params: { did: parsedaturi.did, rkey: parsedaturi.rkey }, 849 + params: { did: parsedaturi.host, rkey: parsedaturi.rkey }, 557 850 }) 558 851 } 559 852 // onProfileClick={() => parsedaturi && navigate({to: "/profile/$did", ··· 564 857 if (parsedaturi) { 565 858 navigate({ 566 859 to: "/profile/$did", 567 - params: { did: parsedaturi.did }, 860 + params: { did: parsedaturi.host }, 568 861 }); 569 862 } 570 863 }} 571 864 post={fakepost} 865 + uprrrsauthor={fakeprofileviewdetailed} 572 866 salt={aturi} 573 867 bottomReplyLine={bottomReplyLine} 574 868 topReplyLine={topReplyLine} 575 869 bottomBorder={bottomBorder} 576 870 //extraOptionalItemInfo={{reply: postRecord?.value?.reply as AppBskyFeedDefs.ReplyRef, post: fakepost}} 577 871 feedviewpostreplyhandle={feedviewpostreplyhandle} 872 + repostedby={feedviewpostrepostedbyhandle} 873 + style={style} 874 + ref={ref} 875 + dataIndexPropPass={dataIndexPropPass} 876 + nopics={nopics} 877 + lightboxCallback={lightboxCallback} 878 + maxReplies={maxReplies} 879 + isQuote={isQuote} 578 880 /> 579 881 </> 580 882 ); 581 883 } 582 884 583 - function hydrateEmbedImages( 584 - embed: any, 585 - did: string, 586 - ): $Typed<AppBskyEmbedImages.View> | undefined { 587 - if (!embed || embed.$type !== "app.bsky.embed.images") return undefined; 588 - if (!Array.isArray(embed.images)) return undefined; 589 - return asTyped({ 590 - $type: "app.bsky.embed.images#view" as const, // <-- literal type 591 - images: embed.images 592 - .map((img: any) => { 593 - const link = img?.image?.ref?.["$link"]; 594 - if (!link) return null; 595 - return { 596 - thumb: `https://cdn.bsky.app/img/feed_thumbnail/plain/${did}/${link}@jpeg`, 597 - fullsize: `https://cdn.bsky.app/img/feed_fullsize/plain/${did}/${link}@jpeg`, 598 - alt: img.alt || "", 599 - aspectRatio: img.aspectRatio, 600 - }; 601 - }) 602 - .filter(Boolean), 603 - }); 604 - } 605 - 606 - function hydrateEmbedExternal( 607 - /*{embed, did} : {*/ embed: any, 608 - did: string, //} 609 - ): $Typed<AppBskyEmbedExternal.View> | undefined { 610 - if (!embed || embed.$type !== "app.bsky.embed.external") return undefined; 611 - if (!embed.external) return undefined; 612 - return asTyped({ 613 - $type: "app.bsky.embed.external#view" as const, 614 - external: { 615 - uri: embed.external.uri, 616 - title: embed.external.title, 617 - description: embed.external.description, 618 - thumb: embed?.external?.thumb?.ref?.$link 619 - ? `https://cdn.bsky.app/img/feed_thumbnail/plain/${did}/${embed.external.thumb.ref.$link}@jpeg` 620 - : undefined, 621 - }, 622 - }); 623 - } 624 - 625 - function hydrateEmbedVideo( 626 - embed: any, 627 - did: string, 628 - ): $Typed<AppBskyEmbedVideo.View> | undefined { 629 - if (!embed || embed.$type !== "app.bsky.embed.video") return undefined; 630 - if (!embed.video || !embed.video.ref?.$link) return undefined; 631 - 632 - const videoLink = embed.video.ref.$link; 633 - 634 - return asTyped({ 635 - $type: "app.bsky.embed.video#view" as const, 636 - playlist: `https://video.bsky.app/watch/${did}/${videoLink}/playlist.m3u8`, 637 - thumbnail: `https://video.bsky.app/watch/${did}/${videoLink}/thumbnail.jpg`, 638 - aspectRatio: embed.aspectRatio, 639 - cid: videoLink, 640 - }); 641 - } 642 - async function hydrateEmbedRecordWithMedia( 643 - embed: any, 644 - did: string, 645 - mediaHydratedEmbed: 646 - | $Typed<AppBskyEmbedImages.View> 647 - | $Typed<AppBskyEmbedVideo.View> 648 - | $Typed<AppBskyEmbedExternal.View> 649 - | { $type: string }, 650 - get: (key: string) => any, 651 - set: (key: string, value: string) => void, 652 - ): Promise<$Typed<AppBskyEmbedRecordWithMedia.View> | undefined> { 653 - //return({"hello": "wow"} as any) 654 - console.log("hydrateEmbedRecordWithMedia called!!"); 655 - if (!embed || embed.$type !== "app.bsky.embed.recordWithMedia") 656 - return undefined; 657 - console.log("hydrateEmbedRecordWithMedia 1!!"); 658 - async function deferredrecordget(): Promise< 659 - $Typed<AppBskyEmbedRecord.ViewRecord> 660 - > { 661 - console.log("hydrateEmbedRecordWithMedia 3!!"); 662 - const quoterr = await cachedGetRecord({ 663 - atUri: embed.record.record.uri, 664 - get, 665 - set, 666 - }); 667 - async function defferedQuotedRecordget(): Promise<{ 668 - [_ in string]: unknown; 669 - }> { 670 - console.log("hydrateEmbedRecordWithMedia 4!!"); 671 - return quoterr.value; 672 - } 673 - async function defferedOPRecordget(): Promise< 674 - $Typed<AppBskyActorDefs.ProfileViewBasic> 675 - > { 676 - const parseduri = parseAtUri(embed.record.record.uri); 677 - if (!parseduri) throw new Error("invalid uri"); 678 - console.log("deep- hydrateEmbedRecordWithMedia " + parseduri.did); 679 - const didwhat = parseduri?.did; 680 - console.log("hydrateEmbedRecordWithMedia 4.97!!"); 681 - const opr = await cachedGetRecord({ 682 - atUri: `at://${didwhat}/app.bsky.actor.profile/self`, 683 - get, 684 - set, 685 - }); 686 - console.log("hydrateEmbedRecordWithMedia 4.98!! opr:" + opr); 687 - const opi = await cachedResolveIdentity({ 688 - didOrHandle: didwhat, 689 - get, 690 - set, 691 - }); 692 - console.log("hydrateEmbedRecordWithMedia 4.99!!"); 693 - console.log("hydrateEmbedRecordWithMedia 5!!"); 694 - const thedid = didwhat; 695 - console.log("hydrateEmbedRecordWithMedia 5.01!! " + thedid); 696 - const thehandle = opi?.handle || ""; 697 - console.log("hydrateEmbedRecordWithMedia 5.02!! " + thehandle); 698 - const thedisplayname = (opr.value?.displayName ?? opi?.handle) || ""; 699 - console.log("hydrateEmbedRecordWithMedia 5.03!! " + thedisplayname); 700 - const theavatar = opr.value?.avatar?.ref?.$link 701 - ? `https://cdn.bsky.app/img/avatar/plain/${didwhat}/${opr.value?.avatar?.ref?.$link}@jpeg` 702 - : undefined; 703 - console.log("hydrateEmbedRecordWithMedia 5.04!! " + theavatar); 704 - console.log("hydrateEmbedRecordWithMedia 5.05!!"); 705 - const thecreatedat = opr.value?.createdAt ?? undefined; 706 - console.log("hydrateEmbedRecordWithMedia 5.06!! " + thecreatedat); 707 - console.log("hydrateEmbedRecordWithMedia 5.07!!"); 708 - console.log("hydrateEmbedRecordWithMedia 5.08!!"); 709 - const crying = { 710 - $type: "app.bsky.actor.defs#profileViewBasic" as const, 711 - did: thedid, 712 - handle: thehandle, 713 - displayName: thedisplayname, 714 - avatar: theavatar, 715 - associated: { 716 - chat: { 717 - allowIncoming: "all", 718 - }, 719 - }, 720 - labels: [], 721 - createdAt: thecreatedat, 722 - }; 723 - return asTyped(crying); 724 - } 885 + // export function parseAtUri( 886 + // atUri: string 887 + // ): { did: string; collection: string; rkey: string } | null { 888 + // const PREFIX = "at://"; 889 + // if (!atUri.startsWith(PREFIX)) { 890 + // return null; 891 + // } 725 892 726 - const record = await defferedQuotedRecordget(); 727 - const OP = await defferedOPRecordget(); 893 + // const parts = atUri.slice(PREFIX.length).split("/"); 728 894 729 - console.log("hydrateEmbedRecordWithMedia victory-lap 6!!"); 730 - return asTyped({ 731 - $type: "app.bsky.embed.record#viewRecord" as const, 732 - uri: embed.record.record.uri, 733 - cid: embed.record.record.cid, 734 - indexedAt: String(record.createdAt || "") || "", 735 - author: OP, 736 - value: record, 737 - }); 738 - } 739 - console.log("hydrateEmbedRecordWithMedia 2!!"); 895 + // if (parts.length !== 3) { 896 + // return null; 897 + // } 740 898 741 - const recordion = await deferredrecordget(); 742 - console.log("hydrateEmbedRecordWithMedia victory-lap 7!!"); 899 + // const [did, collection, rkey] = parts; 743 900 744 - const final = asTyped({ 745 - $type: "app.bsky.embed.recordWithMedia#view" as const, 746 - record: { 747 - //$type: "app.bsky.embed.record#view" as const, 748 - record: recordion, 749 - }, 750 - media: mediaHydratedEmbed, 751 - // media: asTyped({ 752 - // $type: "app.bsky.embed.images" as const, 753 - // images: embed.media.images 754 - // ? embed.media.images 755 - // .map((img: any) => { 756 - // const link = img?.image?.ref?.["$link"]; 757 - // if (!link) return null; 758 - // return { 759 - // thumb: `https://cdn.bsky.app/img/feed_thumbnail/plain/${did}/${link}@jpeg`, 760 - // fullsize: `https://cdn.bsky.app/img/feed_fullsize/plain/${did}/${link}@jpeg`, 761 - // alt: img.alt || "", 762 - // aspectRatio: img.aspectRatio, 763 - // }; 764 - // }) 765 - // .filter(Boolean) 766 - // : undefined, 767 - // }), 768 - }); 769 - console.log("hydrateEmbedRecordWithMedia final " + final); 770 - return final; 771 - } 901 + // if (!did || !collection || !rkey) { 902 + // return null; 903 + // } 772 904 773 - async function hydrateEmbedRecord( 774 - embed: any, 775 - did: string, 776 - get: (key: string) => any, 777 - set: (key: string, value: string) => void, 778 - ): Promise<$Typed<AppBskyEmbedRecord.View> | undefined> { 779 - if (!embed || embed.$type !== "app.bsky.embed.record") return undefined; 780 - 781 - const recordRef = embed.record?.record?.uri 782 - ? embed.record.record 783 - : embed.record; 784 - 785 - const quoted = await cachedGetRecord({ 786 - atUri: recordRef.uri, 787 - get, 788 - set, 789 - }); 790 - 791 - const parseduri = parseAtUri(recordRef.uri); 792 - if (!parseduri) throw new Error("invalid uri"); 793 - const didwhat = parseduri.did; 794 - 795 - const opr = await cachedGetRecord({ 796 - atUri: `at://${didwhat}/app.bsky.actor.profile/self`, 797 - get, 798 - set, 799 - }); 800 - const opi = await cachedResolveIdentity({ 801 - didOrHandle: didwhat, 802 - get, 803 - set, 804 - }); 805 - 806 - const author = { 807 - $type: "app.bsky.actor.defs#profileViewBasic" as const, 808 - did: didwhat, 809 - handle: opi?.handle || "", 810 - displayName: (opr.value?.displayName ?? opi?.handle) || "", 811 - avatar: opr.value?.avatar?.ref?.$link 812 - ? `https://cdn.bsky.app/img/avatar/plain/${didwhat}/${opr.value?.avatar?.ref?.$link}@jpeg` 813 - : undefined, 814 - associated: { 815 - chat: { 816 - allowIncoming: "all", 817 - }, 818 - }, 819 - labels: [], 820 - createdAt: opr.value?.createdAt ?? undefined, 821 - }; 822 - 823 - const viewRecord: $Typed<AppBskyEmbedRecord.ViewRecord> = asTyped({ 824 - $type: "app.bsky.embed.record#viewRecord" as const, 825 - uri: recordRef.uri, 826 - cid: recordRef.cid, 827 - indexedAt: String(quoted.value.createdAt || "") || "", 828 - author, 829 - value: quoted.value, 830 - replyCount: quoted.value.replyCount, 831 - repostCount: quoted.value.repostCount, 832 - likeCount: quoted.value.likeCount, 833 - quoteCount: quoted.value.quoteCount, 834 - labels: quoted.value.labels, 835 - embeds: quoted.value.embed ? [quoted.value.embed] : undefined, 836 - }); 837 - 838 - return asTyped({ 839 - $type: "app.bsky.embed.record#view" as const, 840 - record: viewRecord, 841 - }); 842 - } 843 - 844 - export function parseAtUri( 845 - atUri: string, 846 - ): { did: string; collection: string; rkey: string } | null { 847 - const PREFIX = "at://"; 848 - if (!atUri.startsWith(PREFIX)) { 849 - return null; 850 - } 851 - 852 - const parts = atUri.slice(PREFIX.length).split("/"); 853 - 854 - if (parts.length !== 3) { 855 - return null; 856 - } 857 - 858 - const [did, collection, rkey] = parts; 859 - 860 - if (!did || !collection || !rkey) { 861 - return null; 862 - } 863 - 864 - return { did, collection, rkey }; 865 - } 905 + // return { did, collection, rkey }; 906 + // } 866 907 867 908 export function MdiCommentOutline(props: SVGProps<SVGSVGElement>) { 868 909 return ( ··· 874 915 {...props} 875 916 > 876 917 <path 877 - fill="oklch(0.704 0.05 28)" 918 + fill="var(--color-gray-400)" 878 919 d="M9 22a1 1 0 0 1-1-1v-3H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2h-6.1l-3.7 3.71c-.2.19-.45.29-.7.29zm1-6v3.08L13.08 16H20V4H4v12z" 879 920 ></path> 880 921 </svg> ··· 891 932 {...props} 892 933 > 893 934 <path 894 - fill="oklch(0.704 0.05 28)" 935 + fill="var(--color-gray-400)" 895 936 d="M17 17H7v-3l-4 4l4 4v-3h12v-6h-2M7 7h10v3l4-4l-4-4v3H5v6h2z" 896 937 ></path> 897 938 </svg> ··· 942 983 {...props} 943 984 > 944 985 <path 945 - fill="oklch(0.704 0.05 28)" 986 + fill="var(--color-gray-400)" 946 987 d="m12.1 18.55l-.1.1l-.11-.1C7.14 14.24 4 11.39 4 8.5C4 6.5 5.5 5 7.5 5c1.54 0 3.04 1 3.57 2.36h1.86C13.46 6 14.96 5 16.5 5c2 0 3.5 1.5 3.5 3.5c0 2.89-3.14 5.74-7.9 10.05M16.5 3c-1.74 0-3.41.81-4.5 2.08C10.91 3.81 9.24 3 7.5 3C4.42 3 2 5.41 2 8.5c0 3.77 3.4 6.86 8.55 11.53L12 21.35l1.45-1.32C18.6 15.36 22 12.27 22 8.5C22 5.41 19.58 3 16.5 3" 947 988 ></path> 948 989 </svg> ··· 959 1000 {...props} 960 1001 > 961 1002 <path 962 - fill="oklch(0.704 0.05 28)" 1003 + fill="var(--color-gray-400)" 963 1004 d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81a3 3 0 0 0 3-3a3 3 0 0 0-3-3a3 3 0 0 0-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9a3 3 0 0 0-3 3a3 3 0 0 0 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.15c-.05.21-.08.43-.08.66c0 1.61 1.31 2.91 2.92 2.91s2.92-1.3 2.92-2.91A2.92 2.92 0 0 0 18 16.08" 964 1005 ></path> 965 1006 </svg> ··· 976 1017 {...props} 977 1018 > 978 1019 <path 979 - fill="oklch(0.704 0.05 28)" 1020 + fill="var(--color-gray-400)" 980 1021 d="M16 12a2 2 0 0 1 2-2a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2m-6 0a2 2 0 0 1 2-2a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2m-6 0a2 2 0 0 1 2-2a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2" 981 1022 ></path> 982 1023 </svg> ··· 993 1034 {...props} 994 1035 > 995 1036 <path 996 - fill="oklch(0.704 0.05 28)" 1037 + fill="var(--color-gray-400)" 997 1038 d="M17.9 17.39c-.26-.8-1.01-1.39-1.9-1.39h-1v-3a1 1 0 0 0-1-1H8v-2h2a1 1 0 0 0 1-1V7h2a2 2 0 0 0 2-2v-.41a7.984 7.984 0 0 1 2.9 12.8M11 19.93c-3.95-.49-7-3.85-7-7.93c0-.62.08-1.22.21-1.79L9 15v1a2 2 0 0 0 2 2m1-16A10 10 0 0 0 2 12a10 10 0 0 0 10 10a10 10 0 0 0 10-10A10 10 0 0 0 12 2" 998 1039 ></path> 999 1040 </svg> ··· 1027 1068 {...props} 1028 1069 > 1029 1070 <path 1030 - fill="oklch(0.704 0.05 28)" 1071 + fill="var(--color-gray-400)" 1031 1072 d="M10 9V5l-7 7l7 7v-4.1c5 0 8.5 1.6 11 5.1c-1-5-4-10-11-11" 1032 1073 ></path> 1033 1074 </svg> ··· 1081 1122 {...props} 1082 1123 > 1083 1124 <path 1084 - fill="oklch(0.704 0.05 28)" 1125 + fill="var(--color-gray-400)" 1085 1126 d="M17 17H7v-3l-4 4l4 4v-3h12v-6h-2M7 7h10v3l4-4l-4-4v3H5v6h2z" 1086 1127 ></path> 1087 1128 </svg> ··· 1098 1139 {...props} 1099 1140 > 1100 1141 <path 1101 - fill="oklch(0.704 0.05 28)" 1142 + fill="var(--color-gray-400)" 1102 1143 d="M6 5.75L10.25 10H7v6h6.5l2 2H7a2 2 0 0 1-2-2v-6H1.75zm12 12.5L13.75 14H17V8h-6.5l-2-2H17a2 2 0 0 1 2 2v6h3.25z" 1103 1144 ></path> 1104 1145 </svg> ··· 1123 1164 } 1124 1165 1125 1166 /* what imported from testfront */ 1126 - import defaultpfp from "~/../public/favicon.png"; 1127 - 1128 1167 //import Masonry from "@mui/lab/Masonry"; 1129 1168 import { 1169 + type $Typed, 1130 1170 AppBskyActorDefs, 1131 1171 AppBskyEmbedDefs, 1132 1172 AppBskyEmbedExternal, ··· 1138 1178 AppBskyFeedPost, 1139 1179 AppBskyGraphDefs, 1140 1180 AtUri, 1181 + type Facet, 1141 1182 //AppBskyLabelerDefs, 1142 1183 //AtUri, 1143 1184 //ComAtprotoRepoStrongRef, 1144 1185 ModerationDecision, 1145 - type $Typed, 1146 - type Facet, 1147 1186 } from "@atproto/api"; 1148 1187 import type { 1149 1188 //BlockedPost, ··· 1152 1191 PostView, 1153 1192 //ThreadViewPost, 1154 1193 } from "@atproto/api/dist/client/types/app/bsky/feed/defs"; 1194 + import { useInfiniteQuery } from "@tanstack/react-query"; 1155 1195 import { useEffect, useRef, useState } from "react"; 1156 1196 import ReactPlayer from "react-player"; 1157 - import { useAuth } from "~/providers/PassAuthProvider"; 1197 + 1198 + import defaultpfp from "~/../public/favicon.png"; 1199 + import { useAuth } from "~/providers/UnifiedAuthProvider"; 1200 + import { FollowButton, Mutual } from "~/routes/profile.$did"; 1201 + import type { LightboxProps } from "~/routes/profile.$did/post.$rkey.image.$i"; 1158 1202 // import type { OutputSchema } from "@atproto/api/dist/client/types/app/bsky/feed/getFeed"; 1159 1203 // import type { 1160 1204 // ViewRecord, ··· 1256 1300 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; 1257 1301 return Array.from( 1258 1302 { length }, 1259 - () => chars[Math.floor(Math.random() * chars.length)], 1303 + () => chars[Math.floor(Math.random() * chars.length)] 1260 1304 ).join(""); 1261 1305 } 1262 1306 1263 1307 function UniversalPostRenderer({ 1264 1308 post, 1309 + uprrrsauthor, 1265 1310 //setMainItem, 1266 1311 //isMainItem, 1267 1312 onPostClick, ··· 1276 1321 salt, 1277 1322 bottomBorder = true, 1278 1323 feedviewpostreplyhandle, 1324 + depth = 0, 1325 + repostedby, 1326 + style, 1327 + ref, 1328 + dataIndexPropPass, 1329 + nopics, 1330 + lightboxCallback, 1331 + maxReplies, 1279 1332 }: { 1280 1333 post: PostView; 1334 + uprrrsauthor?: AppBskyActorDefs.ProfileViewDetailed; 1281 1335 // optional for now because i havent ported every use to this yet 1282 1336 // setMainItem?: React.Dispatch< 1283 1337 // React.SetStateAction<AppBskyFeedDefs.FeedViewPost> ··· 1293 1347 salt: string; 1294 1348 bottomBorder?: boolean; 1295 1349 feedviewpostreplyhandle?: string; 1350 + depth?: number; 1351 + repostedby?: string; 1352 + style?: React.CSSProperties; 1353 + ref?: React.Ref<HTMLDivElement>; 1354 + dataIndexPropPass?: number; 1355 + nopics?: boolean; 1356 + lightboxCallback?: (d: LightboxProps) => void; 1357 + maxReplies?: number; 1296 1358 }) { 1359 + const parsed = new AtUri(post.uri); 1297 1360 const navigate = useNavigate(); 1298 - const [hasRetweeted, setHasRetweeted] = useState<Boolean>( 1299 - post.viewer?.repost ? true : false, 1361 + const [likedPosts, setLikedPosts] = useAtom(likedPostsAtom); 1362 + const [hasRetweeted, setHasRetweeted] = useState<boolean>( 1363 + post.viewer?.repost ? true : false 1300 1364 ); 1301 - const [hasLiked, setHasLiked] = useState<Boolean>( 1302 - post.viewer?.like ? true : false, 1365 + const [hasLiked, setHasLiked] = useState<boolean>( 1366 + post.uri in likedPosts || post.viewer?.like ? true : false 1303 1367 ); 1368 + const [, setComposerPost] = useAtom(composerAtom); 1304 1369 const { agent } = useAuth(); 1305 1370 const [likeUri, setLikeUri] = useState<string | undefined>(post.viewer?.like); 1306 1371 const [retweetUri, setRetweetUri] = useState<string | undefined>( 1307 - post.viewer?.repost, 1372 + post.viewer?.repost 1308 1373 ); 1309 1374 1310 1375 const likeOrUnlikePost = async () => { 1376 + const newLikedPosts = { ...likedPosts }; 1311 1377 if (!agent) { 1312 1378 console.error("Agent is null or undefined"); 1313 1379 return; 1314 1380 } 1315 1381 if (hasLiked) { 1382 + if (post.uri in likedPosts) { 1383 + const likeUri = likedPosts[post.uri]; 1384 + setLikeUri(likeUri); 1385 + } 1316 1386 if (likeUri) { 1317 1387 await agent.deleteLike(likeUri); 1318 1388 setHasLiked(false); 1389 + delete newLikedPosts[post.uri]; 1319 1390 } 1320 1391 } else { 1321 1392 const { uri } = await agent.like(post.uri, post.cid); 1322 1393 setLikeUri(uri); 1323 1394 setHasLiked(true); 1395 + newLikedPosts[post.uri] = uri; 1324 1396 } 1397 + setLikedPosts(newLikedPosts); 1325 1398 }; 1326 1399 1327 1400 const repostOrUnrepostPost = async () => { ··· 1341 1414 } 1342 1415 }; 1343 1416 1344 - const isRepost = extraOptionalItemInfo 1345 - ? AppBskyFeedDefs.isReasonRepost(extraOptionalItemInfo.reason) 1346 - ? extraOptionalItemInfo.reason?.by.displayName 1347 - : undefined 1348 - : undefined; 1417 + const isRepost = repostedby 1418 + ? repostedby 1419 + : extraOptionalItemInfo 1420 + ? AppBskyFeedDefs.isReasonRepost(extraOptionalItemInfo.reason) 1421 + ? extraOptionalItemInfo.reason?.by.displayName 1422 + : undefined 1423 + : undefined; 1349 1424 const isReply = extraOptionalItemInfo 1350 1425 ? extraOptionalItemInfo.reply 1351 1426 : undefined; 1352 1427 1353 1428 const emergencySalt = randomString(); 1429 + const fedi = (post.record as { bridgyOriginalText?: string }) 1430 + .bridgyOriginalText; 1354 1431 1355 1432 /* fuck you */ 1356 1433 const isMainItem = false; 1357 1434 const setMainItem = (any: any) => {}; 1435 + // eslint-disable-next-line react-hooks/refs 1436 + console.log("Received ref in UniversalPostRenderer:", ref); 1358 1437 return ( 1359 - <div 1360 - key={salt + "-" + (post.uri || emergencySalt)} 1361 - onClick={ 1362 - isMainItem 1363 - ? onPostClick 1364 - : setMainItem 1365 - ? onPostClick 1366 - ? (e) => { 1367 - setMainItem({ post: post }); 1368 - onPostClick(e); 1369 - } 1370 - : () => { 1371 - setMainItem({ post: post }); 1372 - } 1373 - : undefined 1374 - } 1375 - style={{ 1376 - //border: "1px solid #e1e8ed", 1377 - //borderRadius: 12, 1378 - opacity: "1 !important", 1379 - background: "transparent", 1380 - paddingLeft: isQuote ? 12 : 16, 1381 - paddingRight: isQuote ? 12 : 16, 1382 - //paddingTop: 16, 1383 - paddingTop: isRepost ? 10 : isQuote ? 12 : 16, 1384 - //paddingBottom: bottomReplyLine ? 0 : 16, 1385 - paddingBottom: 0, 1386 - fontFamily: "system-ui, sans-serif", 1387 - //boxShadow: "0 2px 8px rgba(0,0,0,0.04)", 1388 - position: "relative", 1389 - // dont cursor: "pointer", 1390 - borderBottomWidth: bottomBorder ? isQuote ? 0 : 1 : 0, 1391 - }} 1392 - className="border-gray-300 dark:border-gray-600" 1393 - > 1394 - {isRepost && ( 1395 - <div 1396 - style={{ 1397 - marginLeft: 36, 1398 - display: "flex", 1399 - borderRadius: 12, 1400 - paddingBottom: "calc(22px - 1rem)", 1401 - fontSize: 14, 1402 - maxHeight: "1rem", 1403 - justifyContent: "flex-start", 1404 - //color: theme.textSecondary, 1405 - gap: 4, 1406 - alignItems: "center", 1407 - }} 1408 - className="text-gray-500 dark:text-gray-400" 1409 - > 1410 - <MdiRepost /> Reposted by {isRepost}{" "} 1411 - </div> 1412 - )} 1413 - {!isQuote && ( 1414 - <div 1415 - style={{ 1416 - opacity: topReplyLine || (isReply && (true || expanded)) ? 0.5 : 0, 1417 - position: "absolute", 1418 - top: 0, 1419 - left: 36, // why 36 ??? 1420 - //left: 16 + (42 / 2), 1421 - width: 2, 1422 - //height: "100%", 1423 - height: isRepost ? "calc(16px + 1rem - 6px)" : 16 - 6, 1424 - // background: theme.textSecondary, 1425 - //opacity: 0.5, 1426 - // no flex here 1427 - }} 1428 - className="bg-gray-500 dark:bg-gray-400" 1429 - /> 1430 - )} 1438 + <div ref={ref} style={style} data-index={dataIndexPropPass}> 1431 1439 <div 1440 + //ref={ref} 1441 + key={salt + "-" + (post.uri || emergencySalt)} 1442 + onClick={ 1443 + isMainItem 1444 + ? onPostClick 1445 + : setMainItem 1446 + ? onPostClick 1447 + ? (e) => { 1448 + setMainItem({ post: post }); 1449 + onPostClick(e); 1450 + } 1451 + : () => { 1452 + setMainItem({ post: post }); 1453 + } 1454 + : undefined 1455 + } 1432 1456 style={{ 1433 - position: "absolute", 1434 - //top: isRepost ? "calc(16px + 1rem)" : 16, 1435 - //left: 16, 1436 - zIndex: 1, 1437 - top: isRepost ? "calc(16px + 1rem)" : isQuote ? 12 : 16, 1438 - left: isQuote ? 12 : 16, 1457 + //...style, 1458 + //border: "1px solid #e1e8ed", 1459 + //borderRadius: 12, 1460 + opacity: "1 !important", 1461 + background: "transparent", 1462 + paddingLeft: isQuote ? 12 : 16, 1463 + paddingRight: isQuote ? 12 : 16, 1464 + //paddingTop: 16, 1465 + paddingTop: isRepost ? 10 : isQuote ? 12 : topReplyLine ? 8 : 16, 1466 + //paddingBottom: bottomReplyLine ? 0 : 16, 1467 + paddingBottom: 0, 1468 + fontFamily: "system-ui, sans-serif", 1469 + //boxShadow: "0 2px 8px rgba(0,0,0,0.04)", 1470 + position: "relative", 1471 + // dont cursor: "pointer", 1472 + borderBottomWidth: bottomBorder ? (isQuote ? 0 : 1) : 0, 1439 1473 }} 1440 - onClick={onProfileClick} 1474 + className="border-gray-300 dark:border-gray-800" 1441 1475 > 1442 - <img 1443 - src={post.author.avatar || defaultpfp} 1444 - alt="avatar" 1445 - // transition={{ 1446 - // type: "spring", 1447 - // stiffness: 260, 1448 - // damping: 20, 1449 - // }} 1450 - style={{ 1451 - borderRadius: "50%", 1452 - marginRight: 12, 1453 - objectFit: "cover", 1454 - //background: theme.border, 1455 - //border: `1px solid ${theme.border}`, 1456 - width: isQuote ? 16 : 42, 1457 - height: isQuote ? 16 : 42, 1458 - }} 1459 - className="border border-gray-300 dark:border-gray-600 bg-gray-300 dark:bg-gray-600" 1460 - /> 1461 - </div> 1462 - <div style={{ display: "flex", alignItems: "flex-start", zIndex: 2 }}> 1463 - <div 1464 - style={{ 1465 - display: "flex", 1466 - flexDirection: "column", 1467 - alignSelf: "stretch", 1468 - alignItems: "center", 1469 - overflow: "hidden", 1470 - width: expanded || isQuote ? 0 : "auto", 1471 - marginRight: expanded || isQuote ? 0 : 12, 1472 - }} 1473 - > 1474 - {/* dummy for later use */} 1475 - <div style={{ width: 42, height: 42 + 8, minHeight: 42 + 8 }} /> 1476 - {/* reply line !!!! bottomReplyLine */} 1477 - {bottomReplyLine && ( 1476 + {isRepost && ( 1477 + <div 1478 + style={{ 1479 + marginLeft: 36, 1480 + display: "flex", 1481 + borderRadius: 12, 1482 + paddingBottom: "calc(22px - 1rem)", 1483 + fontSize: 14, 1484 + maxHeight: "1rem", 1485 + justifyContent: "flex-start", 1486 + //color: theme.textSecondary, 1487 + gap: 4, 1488 + alignItems: "center", 1489 + }} 1490 + className="text-gray-500 dark:text-gray-400" 1491 + > 1492 + <MdiRepost /> Reposted by @{isRepost}{" "} 1493 + </div> 1494 + )} 1495 + {!isQuote && ( 1496 + <div 1497 + style={{ 1498 + opacity: 1499 + topReplyLine || isReply /*&& (true || expanded)*/ ? 0.5 : 0, 1500 + position: "absolute", 1501 + top: 0, 1502 + left: 36, // why 36 ??? 1503 + //left: 16 + (42 / 2), 1504 + width: 2, 1505 + //height: "100%", 1506 + height: isRepost 1507 + ? "calc(16px + 1rem - 6px)" 1508 + : topReplyLine 1509 + ? 8 - 6 1510 + : 16 - 6, 1511 + // background: theme.textSecondary, 1512 + //opacity: 0.5, 1513 + // no flex here 1514 + }} 1515 + className="bg-gray-500 dark:bg-gray-400" 1516 + /> 1517 + )} 1518 + <HoverCard.Root> 1519 + <HoverCard.Trigger asChild> 1478 1520 <div 1521 + className={`absolute`} 1479 1522 style={{ 1480 - width: 2, 1481 - height: "100%", 1482 - //background: theme.textSecondary, 1483 - opacity: 0.5, 1484 - // no flex here 1485 - //color: "Red", 1486 - //zIndex: 99 1523 + top: isRepost 1524 + ? "calc(16px + 1rem)" 1525 + : isQuote 1526 + ? 12 1527 + : topReplyLine 1528 + ? 8 1529 + : 16, 1530 + left: isQuote ? 12 : 16, 1487 1531 }} 1488 - className="bg-gray-500 dark:bg-gray-400" 1489 - /> 1490 - )} 1491 - {/* <div 1532 + onClick={onProfileClick} 1533 + > 1534 + <img 1535 + src={post.author.avatar || defaultpfp} 1536 + alt="avatar" 1537 + className={`rounded-full object-cover border border-gray-300 dark:border-gray-800 bg-gray-300 dark:bg-gray-600`} 1538 + style={{ 1539 + width: isQuote ? 16 : 42, 1540 + height: isQuote ? 16 : 42, 1541 + }} 1542 + /> 1543 + </div> 1544 + </HoverCard.Trigger> 1545 + <HoverCard.Portal> 1546 + <HoverCard.Content 1547 + className="rounded-md p-4 w-72 bg-gray-50 dark:bg-gray-900 shadow-lg border border-gray-300 dark:border-gray-800 animate-slide-fade z-50" 1548 + side={"bottom"} 1549 + sideOffset={5} 1550 + onClick={onProfileClick} 1551 + > 1552 + <div className="flex flex-col gap-2"> 1553 + <div className="flex flex-row"> 1554 + <img 1555 + src={post.author.avatar || defaultpfp} 1556 + alt="avatar" 1557 + className="rounded-full w-[58px] h-[58px] object-cover border border-gray-300 dark:border-gray-800 bg-gray-300 dark:bg-gray-600" 1558 + /> 1559 + <div className=" flex-1 flex flex-row align-middle justify-end"> 1560 + <div className=" flex flex-col justify-start"> 1561 + <FollowButton targetdidorhandle={post.author.did} /> 1562 + </div> 1563 + </div> 1564 + </div> 1565 + <div className="flex flex-col gap-3"> 1566 + <div> 1567 + <div className="text-gray-900 dark:text-gray-100 font-medium text-md"> 1568 + {post.author.displayName || post.author.handle}{" "} 1569 + </div> 1570 + <div className="text-gray-500 dark:text-gray-400 text-md flex flex-row gap-1"> 1571 + <Mutual targetdidorhandle={post.author.did} />@{post.author.handle}{" "} 1572 + </div> 1573 + </div> 1574 + {uprrrsauthor?.description && ( 1575 + <div className="text-gray-700 dark:text-gray-300 text-sm text-left break-words line-clamp-3"> 1576 + {uprrrsauthor.description} 1577 + </div> 1578 + )} 1579 + {/* <div className="flex gap-4"> 1580 + <div className="flex gap-1"> 1581 + <div className="font-medium text-gray-900 dark:text-gray-100"> 1582 + 0 1583 + </div> 1584 + <div className="text-gray-500 dark:text-gray-400"> 1585 + Following 1586 + </div> 1587 + </div> 1588 + <div className="flex gap-1"> 1589 + <div className="font-medium text-gray-900 dark:text-gray-100"> 1590 + 2,900 1591 + </div> 1592 + <div className="text-gray-500 dark:text-gray-400"> 1593 + Followers 1594 + </div> 1595 + </div> 1596 + </div> */} 1597 + </div> 1598 + </div> 1599 + 1600 + {/* <HoverCard.Arrow className="fill-gray-50 dark:fill-gray-900" /> */} 1601 + </HoverCard.Content> 1602 + </HoverCard.Portal> 1603 + </HoverCard.Root> 1604 + 1605 + <div style={{ display: "flex", alignItems: "flex-start", zIndex: 2 }}> 1606 + <div 1607 + style={{ 1608 + display: "flex", 1609 + flexDirection: "column", 1610 + alignSelf: "stretch", 1611 + alignItems: "center", 1612 + overflow: "hidden", 1613 + width: expanded || isQuote ? 0 : "auto", 1614 + marginRight: expanded || isQuote ? 0 : 12, 1615 + }} 1616 + > 1617 + {/* dummy for later use */} 1618 + <div style={{ width: 42, height: 42 + 6, minHeight: 42 + 6 }} /> 1619 + {/* reply line !!!! bottomReplyLine */} 1620 + {bottomReplyLine && ( 1621 + <div 1622 + style={{ 1623 + width: 2, 1624 + height: "100%", 1625 + //background: theme.textSecondary, 1626 + opacity: 0.5, 1627 + // no flex here 1628 + //color: "Red", 1629 + //zIndex: 99 1630 + }} 1631 + className="bg-gray-500 dark:bg-gray-400" 1632 + /> 1633 + )} 1634 + {/* <div 1492 1635 layout 1493 1636 transition={{ duration: 0.2 }} 1494 1637 animate={{ height: expanded ? 0 : '100%' }} ··· 1498 1641 // no flex here 1499 1642 }} 1500 1643 /> */} 1501 - </div> 1502 - <div style={{ flex: 1, maxWidth: "100%" }}> 1503 - <div 1504 - style={{ 1505 - display: "flex", 1506 - flexDirection: "row", 1507 - alignItems: "center", 1508 - flexWrap: "nowrap", 1509 - maxWidth: `calc(100% - ${!expanded ? (isQuote ? 26 : 0) : 54}px)`, 1510 - width: `calc(100% - ${!expanded ? (isQuote ? 26 : 0) : 54}px)`, 1511 - marginLeft: !expanded ? (isQuote ? 26 : 0) : 54, 1512 - marginBottom: !expanded ? 4 : 0, 1513 - }} 1514 - > 1644 + </div> 1645 + <div style={{ flex: 1, maxWidth: "100%" }}> 1515 1646 <div 1516 1647 style={{ 1517 1648 display: "flex", 1518 - //overflow: "hidden", // hey why is overflow hidden unapplied 1519 - overflow: "hidden", 1520 - textOverflow: "ellipsis", 1521 - flexShrink: 1, 1522 - flexGrow: 1, 1523 - flexBasis: 0, 1524 - width: 0, 1525 - gap: expanded ? 0 : 6, 1526 - alignItems: expanded ? "flex-start" : "center", 1527 - flexDirection: expanded ? "column" : "row", 1528 - height: expanded ? 48 : "1rem", 1649 + flexDirection: "row", 1650 + alignItems: "center", 1651 + flexWrap: "nowrap", 1652 + maxWidth: `calc(100% - ${!expanded ? (isQuote ? 26 : 0) : 54}px)`, 1653 + width: `calc(100% - ${!expanded ? (isQuote ? 26 : 0) : 54}px)`, 1654 + marginLeft: !expanded ? (isQuote ? 26 : 0) : 54, 1655 + marginBottom: !expanded ? 4 : 6, 1529 1656 }} 1530 1657 > 1531 - <span 1658 + <div 1532 1659 style={{ 1533 1660 display: "flex", 1534 - fontWeight: 700, 1535 - fontSize: 16, 1661 + //overflow: "hidden", // hey why is overflow hidden unapplied 1536 1662 overflow: "hidden", 1537 1663 textOverflow: "ellipsis", 1538 - whiteSpace: "nowrap", 1539 1664 flexShrink: 1, 1540 - minWidth: 0, 1541 - gap: 4, 1542 - alignItems: "center", 1543 - //color: theme.text, 1665 + flexGrow: 1, 1666 + flexBasis: 0, 1667 + width: 0, 1668 + gap: expanded ? 0 : 6, 1669 + alignItems: expanded ? "flex-start" : "center", 1670 + flexDirection: expanded ? "column" : "row", 1671 + height: expanded ? 42 : "1rem", 1544 1672 }} 1545 - className="text-gray-900 dark:text-gray-100" 1546 1673 > 1547 - {/* verified checkmark */} 1548 - {post.author.displayName || post.author.handle}{" "} 1549 - {post.author.verification?.verifiedStatus == "valid" && ( 1550 - <MdiVerified /> 1551 - )} 1552 - </span> 1674 + <span 1675 + style={{ 1676 + display: "flex", 1677 + fontWeight: 700, 1678 + fontSize: 16, 1679 + overflow: "hidden", 1680 + textOverflow: "ellipsis", 1681 + whiteSpace: "nowrap", 1682 + flexShrink: 1, 1683 + minWidth: 0, 1684 + gap: 4, 1685 + alignItems: "center", 1686 + //color: theme.text, 1687 + }} 1688 + className="text-gray-900 dark:text-gray-100" 1689 + > 1690 + {/* verified checkmark */} 1691 + {post.author.displayName || post.author.handle}{" "} 1692 + {post.author.verification?.verifiedStatus == "valid" && ( 1693 + <MdiVerified /> 1694 + )} 1695 + </span> 1553 1696 1554 - <span 1697 + <span 1698 + style={{ 1699 + //color: theme.textSecondary, 1700 + fontSize: 16, 1701 + overflowX: "hidden", 1702 + textOverflow: "ellipsis", 1703 + whiteSpace: "nowrap", 1704 + flexShrink: 1, 1705 + flexGrow: 0, 1706 + minWidth: 0, 1707 + }} 1708 + className="text-gray-500 dark:text-gray-400" 1709 + > 1710 + @{post.author.handle} 1711 + </span> 1712 + </div> 1713 + <div 1555 1714 style={{ 1556 - //color: theme.textSecondary, 1557 - fontSize: 16, 1558 - overflowX: "hidden", 1559 - textOverflow: "ellipsis", 1560 - whiteSpace: "nowrap", 1561 - flexShrink: 1, 1562 - flexGrow: 0, 1563 - minWidth: 0, 1715 + display: "flex", 1716 + alignItems: "center", 1717 + height: "1rem", 1564 1718 }} 1565 - className="text-gray-500 dark:text-gray-400" 1566 1719 > 1567 - @{post.author.handle} 1568 - </span> 1720 + <span 1721 + style={{ 1722 + //color: theme.textSecondary, 1723 + fontSize: 16, 1724 + marginLeft: 8, 1725 + whiteSpace: "nowrap", 1726 + flexShrink: 0, 1727 + maxWidth: "100%", 1728 + }} 1729 + className="text-gray-500 dark:text-gray-400" 1730 + > 1731 + ยท {/* time placeholder */} 1732 + {shortTimeAgo(post.indexedAt)} 1733 + </span> 1734 + </div> 1569 1735 </div> 1570 - <div 1571 - style={{ 1572 - display: "flex", 1573 - alignItems: "center", 1574 - height: "1rem", 1575 - }} 1576 - > 1577 - <span 1736 + {/* reply indicator */} 1737 + {!!feedviewpostreplyhandle && ( 1738 + <div 1578 1739 style={{ 1740 + display: "flex", 1741 + borderRadius: 12, 1742 + paddingBottom: 2, 1743 + fontSize: 14, 1744 + justifyContent: "flex-start", 1579 1745 //color: theme.textSecondary, 1580 - fontSize: 16, 1581 - marginLeft: 8, 1582 - whiteSpace: "nowrap", 1583 - flexShrink: 0, 1584 - maxWidth: "100%", 1746 + gap: 4, 1747 + alignItems: "center", 1748 + //marginLeft: 36, 1749 + height: 1750 + !(expanded || isQuote) && !!feedviewpostreplyhandle 1751 + ? "1rem" 1752 + : 0, 1753 + opacity: 1754 + !(expanded || isQuote) && !!feedviewpostreplyhandle ? 1 : 0, 1585 1755 }} 1586 1756 className="text-gray-500 dark:text-gray-400" 1587 1757 > 1588 - ยท {/* time placeholder */} 1589 - {shortTimeAgo(post.indexedAt)} 1590 - </span> 1591 - </div> 1592 - </div> 1593 - {/* reply indicator */} 1594 - {!!feedviewpostreplyhandle && ( 1758 + <MdiReply /> Reply to @{feedviewpostreplyhandle} 1759 + </div> 1760 + )} 1595 1761 <div 1596 1762 style={{ 1597 - display: "flex", 1598 - borderRadius: 12, 1599 - paddingBottom: 2, 1600 - fontSize: 14, 1601 - justifyContent: "flex-start", 1602 - //color: theme.textSecondary, 1603 - gap: 4, 1604 - alignItems: "center", 1605 - //marginLeft: 36, 1606 - height: !(expanded || isQuote) && !!feedviewpostreplyhandle ? "1rem" : 0, 1607 - opacity: !(expanded || isQuote) && !!feedviewpostreplyhandle ? 1 : 0, 1763 + fontSize: 16, 1764 + marginBottom: !post.embed /*|| depth > 0*/ ? 0 : 8, 1765 + whiteSpace: "pre-wrap", 1766 + textAlign: "left", 1767 + overflowWrap: "anywhere", 1768 + wordBreak: "break-word", 1769 + //color: theme.text, 1608 1770 }} 1609 - className="text-gray-500 dark:text-gray-400" 1771 + className="text-gray-900 dark:text-gray-100" 1610 1772 > 1611 - <MdiReply /> Reply to {feedviewpostreplyhandle} 1773 + {fedi ? ( 1774 + <> 1775 + <span 1776 + className="dangerousFediContent" 1777 + dangerouslySetInnerHTML={{ 1778 + __html: DOMPurify.sanitize(fedi), 1779 + }} 1780 + /> 1781 + </> 1782 + ) : ( 1783 + <> 1784 + {renderTextWithFacets({ 1785 + text: (post.record as { text?: string }).text ?? "", 1786 + facets: (post.record.facets as Facet[]) ?? [], 1787 + navigate: navigate, 1788 + })} 1789 + </> 1790 + )} 1612 1791 </div> 1613 - )} 1614 - <div 1615 - style={{ 1616 - fontSize: 16, 1617 - marginBottom: (!post.embed && !expanded) ? 0 : 8, 1618 - whiteSpace: "pre-wrap", 1619 - textAlign: "left", 1620 - overflowWrap: "anywhere", 1621 - wordBreak: "break-word", 1622 - //color: theme.text, 1623 - }} 1624 - className="text-gray-900 dark:text-gray-100" 1625 - > 1626 - {renderTextWithFacets( 1627 - (post.record as { text?: string }).text ?? "", 1628 - (post.record.facets as Facet[]) ?? [], 1792 + {post.embed && depth < 1 ? ( 1793 + <PostEmbeds 1794 + embed={post.embed} 1795 + //moderation={moderation} 1796 + viewContext={PostEmbedViewContext.Feed} 1797 + salt={salt} 1798 + navigate={navigate} 1799 + postid={{ did: post.author.did, rkey: parsed.rkey }} 1800 + nopics={nopics} 1801 + lightboxCallback={lightboxCallback} 1802 + /> 1803 + ) : null} 1804 + {post.embed && depth > 0 && ( 1805 + /* pretty bad hack imo. its trying to sync up with how the embed shim doesnt 1806 + hydrate embeds this deep but the connection here is implicit 1807 + todo: idk make this a real part of the embed shim so its not implicit */ 1808 + <> 1809 + <div className="border-gray-300 dark:border-gray-800 p-3 rounded-xl border italic text-gray-400 text-[14px]"> 1810 + (there is an embed here thats too deep to render) 1811 + </div> 1812 + </> 1629 1813 )} 1630 - {} 1631 - </div> 1632 - {post.embed ? ( 1633 - <PostEmbeds 1634 - embed={post.embed} 1635 - //moderation={moderation} 1636 - viewContext={PostEmbedViewContext.Feed} 1637 - salt={salt} 1638 - navigate={navigate} 1639 - /> 1640 - ) : null} 1641 - <div style={{ paddingTop: post.embed ? 4 : 0 }}> 1642 - <> 1643 - {expanded && ( 1814 + <div style={{ paddingTop: post.embed && depth < 1 ? 4 : 0 }}> 1815 + <> 1816 + {expanded && ( 1817 + <div 1818 + style={{ 1819 + overflow: "hidden", 1820 + //color: theme.textSecondary, 1821 + fontSize: 14, 1822 + display: "flex", 1823 + borderBottomStyle: "solid", 1824 + //borderBottomColor: theme.border, 1825 + //background: "#f00", 1826 + // height: "1rem", 1827 + paddingTop: 4, 1828 + paddingBottom: 8, 1829 + borderBottomWidth: 1, 1830 + marginBottom: 8, 1831 + }} // important for height animation 1832 + className="text-gray-500 dark:text-gray-400 border-gray-200 dark:border-gray-800 was7" 1833 + > 1834 + {fullDateTimeFormat(post.indexedAt)} 1835 + </div> 1836 + )} 1837 + </> 1838 + {!isQuote && ( 1644 1839 <div 1645 1840 style={{ 1646 - overflow: "hidden", 1647 - //color: theme.textSecondary, 1648 - fontSize: 14, 1649 1841 display: "flex", 1650 - borderBottomStyle: "solid", 1651 - //borderBottomColor: theme.border, 1652 - //background: "#f00", 1653 - // height: "1rem", 1654 - paddingTop: 4, 1655 - paddingBottom: 8, 1656 - borderBottomWidth: 1, 1657 - marginBottom: 8, 1658 - }} // important for height animation 1659 - className="text-gray-500 dark:text-gray-400 border-gray-200 dark:border-gray-700" 1660 - > 1661 - {fullDateTimeFormat(post.indexedAt)} 1662 - </div> 1663 - )} 1664 - </> 1665 - {!isQuote && ( 1666 - <div 1667 - style={{ 1668 - display: "flex", 1669 - gap: 32, 1670 - paddingTop: 8, 1671 - //color: theme.textSecondary, 1672 - fontSize: 15, 1673 - justifyContent: "space-between", 1674 - //background: "#0f0", 1675 - }} 1676 - className="text-gray-500 dark:text-gray-400" 1677 - > 1678 - <span style={btnstyle}> 1679 - <MdiCommentOutline /> 1680 - {post.replyCount} 1681 - </span> 1682 - <HitSlopButton 1683 - onClick={() => { 1684 - repostOrUnrepostPost(); 1842 + gap: 32, 1843 + paddingTop: 8, 1844 + //color: theme.textSecondary, 1845 + fontSize: 15, 1846 + justifyContent: "space-between", 1847 + //background: "#0f0", 1685 1848 }} 1686 - style={{ 1687 - ...btnstyle, 1688 - ...(hasRetweeted ? { color: "#5CEFAA" } : {}), 1689 - }} 1849 + className="text-gray-500 dark:text-gray-400" 1690 1850 > 1691 - {hasRetweeted ? <MdiRepeatGreen /> : <MdiRepeat />} 1692 - {(post.repostCount || 0) + (hasRetweeted ? 1 : 0)} 1693 - </HitSlopButton> 1694 - <HitSlopButton 1695 - onClick={() => { 1696 - likeOrUnlikePost(); 1697 - }} 1698 - style={{ 1699 - ...btnstyle, 1700 - ...(hasLiked ? { color: "#EC4899" } : {}), 1701 - }} 1702 - > 1703 - {hasLiked ? <MdiCardsHeart /> : <MdiCardsHeartOutline />} 1704 - {(post.likeCount || 0) + (hasLiked ? 1 : 0)} 1705 - </HitSlopButton> 1706 - <div style={{ display: "flex", gap: 8 }}> 1851 + <HitSlopButton 1852 + onClick={() => { 1853 + setComposerPost({ kind: "reply", parent: post.uri }); 1854 + }} 1855 + style={{ 1856 + ...btnstyle, 1857 + }} 1858 + > 1859 + <MdiCommentOutline /> 1860 + {post.replyCount} 1861 + </HitSlopButton> 1862 + <DropdownMenu.Root modal={false}> 1863 + <DropdownMenu.Trigger asChild> 1864 + <div 1865 + style={{ 1866 + ...btnstyle, 1867 + ...(hasRetweeted ? { color: "#5CEFAA" } : {}), 1868 + }} 1869 + aria-label="Repost or quote post" 1870 + > 1871 + {hasRetweeted ? <MdiRepeatGreen /> : <MdiRepeat />} 1872 + {post.repostCount ?? 0} 1873 + </div> 1874 + </DropdownMenu.Trigger> 1875 + 1876 + <DropdownMenu.Portal> 1877 + <DropdownMenu.Content 1878 + align="start" 1879 + sideOffset={5} 1880 + className="bg-white dark:bg-gray-800 rounded-lg shadow-xl border border-gray-200 dark:border-gray-700 w-32 z-50 overflow-hidden" 1881 + > 1882 + <DropdownMenu.Item 1883 + onSelect={repostOrUnrepostPost} 1884 + className="px-3 py-2 text-sm flex items-center gap-2 cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none focus:bg-gray-100 dark:focus:bg-gray-700" 1885 + > 1886 + <MdiRepeat 1887 + className={hasRetweeted ? "text-green-400" : ""} 1888 + /> 1889 + <span>{hasRetweeted ? "Undo Repost" : "Repost"}</span> 1890 + </DropdownMenu.Item> 1891 + 1892 + <DropdownMenu.Item 1893 + onSelect={() => { 1894 + setComposerPost({ 1895 + kind: "quote", 1896 + subject: post.uri, 1897 + }); 1898 + }} 1899 + className="px-3 py-2 text-sm flex items-center gap-2 cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none focus:bg-gray-100 dark:focus:bg-gray-700" 1900 + > 1901 + {/* You might want a specific quote icon here */} 1902 + <MdiCommentOutline /> 1903 + <span>Quote</span> 1904 + </DropdownMenu.Item> 1905 + </DropdownMenu.Content> 1906 + </DropdownMenu.Portal> 1907 + </DropdownMenu.Root> 1707 1908 <HitSlopButton 1708 - onClick={async (e) => { 1709 - e.stopPropagation(); 1710 - try { 1711 - await navigator.clipboard.writeText( 1712 - "https://bsky.app" + 1713 - "/profile/" + 1714 - post.author.handle + 1715 - "/post/" + 1716 - post.uri.split("/").pop(), 1717 - ); 1718 - } catch {} 1909 + onClick={() => { 1910 + likeOrUnlikePost(); 1719 1911 }} 1720 1912 style={{ 1721 1913 ...btnstyle, 1914 + ...(hasLiked ? { color: "#EC4899" } : {}), 1722 1915 }} 1723 1916 > 1724 - <MdiShareVariant /> 1917 + {hasLiked ? <MdiCardsHeart /> : <MdiCardsHeartOutline />} 1918 + {(post.likeCount || 0) + (hasLiked ? 1 : 0)} 1725 1919 </HitSlopButton> 1726 - <span style={btnstyle}> 1727 - <MdiMoreHoriz /> 1728 - </span> 1920 + <div style={{ display: "flex", gap: 8 }}> 1921 + <HitSlopButton 1922 + onClick={async (e) => { 1923 + e.stopPropagation(); 1924 + try { 1925 + await navigator.clipboard.writeText( 1926 + "https://bsky.app" + 1927 + "/profile/" + 1928 + post.author.handle + 1929 + "/post/" + 1930 + post.uri.split("/").pop() 1931 + ); 1932 + } catch (_e) { 1933 + // idk 1934 + } 1935 + }} 1936 + style={{ 1937 + ...btnstyle, 1938 + }} 1939 + > 1940 + <MdiShareVariant /> 1941 + </HitSlopButton> 1942 + <span style={btnstyle}> 1943 + <MdiMoreHoriz /> 1944 + </span> 1945 + </div> 1729 1946 </div> 1730 - </div> 1731 - )} 1947 + )} 1948 + </div> 1949 + <div 1950 + style={{ 1951 + //height: bottomReplyLine ? 16 : 0 1952 + height: isQuote ? 12 : 16, 1953 + }} 1954 + /> 1732 1955 </div> 1733 - <div 1734 - style={{ 1735 - //height: bottomReplyLine ? 16 : 0 1736 - height: isQuote ? 12 : 16, 1737 - }} 1738 - /> 1739 1956 </div> 1740 1957 </div> 1741 1958 </div> ··· 1827 2044 viewContext, 1828 2045 salt, 1829 2046 navigate, 2047 + postid, 2048 + nopics, 2049 + lightboxCallback, 1830 2050 }: { 1831 2051 embed?: Embed; 1832 2052 moderation?: ModerationDecision; ··· 1834 2054 allowNestedQuotes?: boolean; 1835 2055 viewContext?: PostEmbedViewContext; 1836 2056 salt: string; 1837 - navigate: ({}: any) => void; 2057 + navigate: (_: any) => void; 2058 + postid?: { did: string; rkey: string }; 2059 + nopics?: boolean; 2060 + lightboxCallback?: (d: LightboxProps) => void; 1838 2061 }) { 1839 - const [lightboxIndex, setLightboxIndex] = useState<number | null>(null); 2062 + //const [lightboxIndex, setLightboxIndex] = useState<number | null>(null); 2063 + function setLightboxIndex(number: number) { 2064 + navigate({ 2065 + to: "/profile/$did/post/$rkey/image/$i", 2066 + params: { 2067 + did: postid?.did, 2068 + rkey: postid?.rkey, 2069 + i: number.toString(), 2070 + }, 2071 + }); 2072 + } 1840 2073 if ( 1841 2074 AppBskyEmbedRecordWithMedia.isView(embed) && 1842 2075 AppBskyEmbedRecord.isViewRecord(embed.record.record) && ··· 1870 2103 viewContext={viewContext} 1871 2104 salt={salt} 1872 2105 navigate={navigate} 2106 + postid={postid} 2107 + nopics={nopics} 2108 + lightboxCallback={lightboxCallback} 1873 2109 /> 1874 2110 {/* padding empty div of 8px height */} 1875 2111 <div style={{ height: 12 }} /> ··· 1883 2119 //boxShadow: theme.cardShadow, 1884 2120 overflow: "hidden", 1885 2121 }} 1886 - className="shadow border border-gray-200 dark:border-gray-700" 2122 + className="shadow border border-gray-200 dark:border-gray-800 was7" 1887 2123 > 1888 2124 <UniversalPostRenderer 1889 2125 post={post} ··· 1891 2127 salt={salt} 1892 2128 onPostClick={(e) => { 1893 2129 e.stopPropagation(); 1894 - const parsed = parseAtUri(post.uri); 2130 + const parsed = new AtUri(post.uri); //parseAtUri(post.uri); 1895 2131 if (parsed) { 1896 2132 navigate({ 1897 2133 to: "/profile/$did/post/$rkey", 1898 - params: { did: parsed.did, rkey: parsed.rkey }, 2134 + params: { did: parsed.host, rkey: parsed.rkey }, 1899 2135 }); 1900 2136 } 1901 2137 }} 2138 + depth={1} 1902 2139 /> 1903 2140 </div> 1904 2141 {/* <QuotePostRenderer ··· 1999 2236 //boxShadow: theme.cardShadow, 2000 2237 overflow: "hidden", 2001 2238 }} 2002 - className="shadow border border-gray-200 dark:border-gray-700" 2239 + className="shadow border border-gray-200 dark:border-gray-800 was7" 2003 2240 > 2004 2241 <UniversalPostRenderer 2005 2242 post={post} ··· 2007 2244 salt={salt} 2008 2245 onPostClick={(e) => { 2009 2246 e.stopPropagation(); 2010 - const parsed = parseAtUri(post.uri); 2247 + const parsed = new AtUri(post.uri); //parseAtUri(post.uri); 2011 2248 if (parsed) { 2012 2249 navigate({ 2013 2250 to: "/profile/$did/post/$rkey", 2014 - params: { did: parsed.did, rkey: parsed.rkey }, 2251 + params: { did: parsed.host, rkey: parsed.rkey }, 2015 2252 }); 2016 2253 } 2017 2254 }} 2255 + depth={1} 2018 2256 /> 2019 2257 </div> 2020 2258 ); ··· 2042 2280 src: img.fullsize, 2043 2281 alt: img.alt, 2044 2282 })); 2283 + console.log("rendering images"); 2284 + if (lightboxCallback) { 2285 + lightboxCallback({ images: lightboxImages }); 2286 + console.log("rendering images"); 2287 + } 2045 2288 2289 + if (nopics) return; 2046 2290 2047 2291 if (images.length > 0) { 2048 2292 // const items = embed.images.map(img => ({ ··· 2072 2316 //border: `1px solid ${theme.border}`, 2073 2317 overflow: "hidden", 2074 2318 }} 2075 - className="border border-gray-200 dark:border-gray-700 bg-gray-200 dark:bg-gray-900" 2319 + className="border border-gray-200 dark:border-gray-800 was7 bg-gray-200 dark:bg-gray-900" 2076 2320 > 2077 - {lightboxIndex !== null && ( 2078 - <Lightbox 2079 - images={lightboxImages} 2080 - index={lightboxIndex} 2081 - onClose={() => setLightboxIndex(null)} 2082 - onNavigate={(newIndex) => setLightboxIndex(newIndex)} 2083 - /> 2084 - )} 2321 + {/* {lightboxIndex !== null && ( 2322 + <Lightbox 2323 + images={lightboxImages} 2324 + index={lightboxIndex} 2325 + onClose={() => setLightboxIndex(null)} 2326 + onNavigate={(newIndex) => setLightboxIndex(newIndex)} 2327 + post={postid} 2328 + /> 2329 + )} */} 2085 2330 <img 2086 2331 src={image.fullsize} 2087 2332 alt={image.alt} ··· 2090 2335 height: "100%", 2091 2336 objectFit: "contain", // letterbox or scale to fit 2092 2337 }} 2093 - onClick={(e) => {e.stopPropagation();setLightboxIndex(0)}} 2338 + onClick={(e) => { 2339 + e.stopPropagation(); 2340 + setLightboxIndex(0); 2341 + }} 2094 2342 /> 2095 2343 </div> 2096 2344 </div> ··· 2109 2357 overflow: "hidden", 2110 2358 //border: `1px solid ${theme.border}`, 2111 2359 }} 2112 - className="border border-gray-200 dark:border-gray-700" 2360 + className="border border-gray-200 dark:border-gray-800 was7" 2113 2361 > 2114 - {lightboxIndex !== null && ( 2362 + {/* {lightboxIndex !== null && ( 2115 2363 <Lightbox 2116 2364 images={lightboxImages} 2117 2365 index={lightboxIndex} 2118 2366 onClose={() => setLightboxIndex(null)} 2119 2367 onNavigate={(newIndex) => setLightboxIndex(newIndex)} 2368 + post={postid} 2120 2369 /> 2121 - )} 2370 + )} */} 2122 2371 {images.map((img, i) => ( 2123 2372 <div 2124 2373 key={i} ··· 2133 2382 objectFit: "cover", 2134 2383 borderRadius: i === 0 ? "12px 0 0 12px" : "0 12px 12px 0", 2135 2384 }} 2136 - onClick={(e) => {e.stopPropagation();setLightboxIndex(i)}} 2385 + onClick={(e) => { 2386 + e.stopPropagation(); 2387 + setLightboxIndex(i); 2388 + }} 2137 2389 /> 2138 2390 </div> 2139 2391 ))} ··· 2155 2407 //border: `1px solid ${theme.border}`, 2156 2408 // height: 240, // fixed height for cropping 2157 2409 }} 2158 - className="border border-gray-200 dark:border-gray-700" 2410 + className="border border-gray-200 dark:border-gray-800 was7" 2159 2411 > 2160 - {lightboxIndex !== null && ( 2412 + {/* {lightboxIndex !== null && ( 2161 2413 <Lightbox 2162 2414 images={lightboxImages} 2163 2415 index={lightboxIndex} 2164 2416 onClose={() => setLightboxIndex(null)} 2165 2417 onNavigate={(newIndex) => setLightboxIndex(newIndex)} 2418 + post={postid} 2166 2419 /> 2167 - )} 2420 + )} */} 2168 2421 {/* Left: 1:1 */} 2169 2422 <div 2170 2423 style={{ flex: 1, aspectRatio: "1 / 1", position: "relative" }} ··· 2178 2431 objectFit: "cover", 2179 2432 borderRadius: "12px 0 0 12px", 2180 2433 }} 2181 - onClick={(e) => {e.stopPropagation();setLightboxIndex(0)}} 2434 + onClick={(e) => { 2435 + e.stopPropagation(); 2436 + setLightboxIndex(0); 2437 + }} 2182 2438 /> 2183 2439 </div> 2184 2440 {/* Right: two stacked 2:1 */} ··· 2208 2464 objectFit: "cover", 2209 2465 borderRadius: i === 1 ? "0 12px 0 0" : "0 0 12px 0", 2210 2466 }} 2211 - onClick={(e) => {e.stopPropagation();setLightboxIndex(i+1)}} 2467 + onClick={(e) => { 2468 + e.stopPropagation(); 2469 + setLightboxIndex(i + 1); 2470 + }} 2212 2471 /> 2213 2472 </div> 2214 2473 ))} ··· 2233 2492 //border: `1px solid ${theme.border}`, 2234 2493 //aspectRatio: "3 / 2", // overall grid aspect 2235 2494 }} 2236 - className="border border-gray-200 dark:border-gray-700" 2495 + className="border border-gray-200 dark:border-gray-800 was7" 2237 2496 > 2238 - {lightboxIndex !== null && ( 2497 + {/* {lightboxIndex !== null && ( 2239 2498 <Lightbox 2240 2499 images={lightboxImages} 2241 2500 index={lightboxIndex} 2242 2501 onClose={() => setLightboxIndex(null)} 2243 2502 onNavigate={(newIndex) => setLightboxIndex(newIndex)} 2503 + post={postid} 2244 2504 /> 2245 - )} 2505 + )} */} 2246 2506 {images.map((img, i) => ( 2247 2507 <div 2248 2508 key={i} ··· 2269 2529 ? "0 0 0 12px" 2270 2530 : "0 0 12px 0", 2271 2531 }} 2272 - onClick={(e) => {e.stopPropagation();setLightboxIndex(i)}} 2532 + onClick={(e) => { 2533 + e.stopPropagation(); 2534 + setLightboxIndex(i); 2535 + }} 2273 2536 /> 2274 2537 </div> 2275 2538 ))} ··· 2330 2593 return <div />; 2331 2594 } 2332 2595 2333 - import { createPortal } from "react-dom"; 2334 - type LightboxProps = { 2335 - images: { src: string; alt?: string }[]; 2336 - index: number; 2337 - onClose: () => void; 2338 - onNavigate?: (newIndex: number) => void; 2339 - }; 2340 - export function Lightbox({ images, index, onClose, onNavigate }: LightboxProps) { 2341 - const image = images[index]; 2342 - 2343 - useEffect(() => { 2344 - function handleKey(e: KeyboardEvent) { 2345 - if (e.key === "Escape") onClose(); 2346 - if (e.key === "ArrowRight" && onNavigate) onNavigate((index + 1) % images.length); 2347 - if (e.key === "ArrowLeft" && onNavigate) onNavigate((index - 1 + images.length) % images.length); 2348 - } 2349 - window.addEventListener("keydown", handleKey); 2350 - return () => window.removeEventListener("keydown", handleKey); 2351 - }, [index, images.length, onClose, onNavigate]); 2352 - 2353 - return createPortal( 2354 - <div 2355 - className="fixed inset-0 z-50 flex items-center justify-center bg-black/80" 2356 - onClick={(e)=>{e.stopPropagation();onClose()}} 2357 - > 2358 - <img 2359 - src={image.src} 2360 - alt={image.alt} 2361 - className="max-h-[90vh] max-w-[90vw] object-contain rounded-lg shadow-lg" 2362 - onClick={(e) => e.stopPropagation()} 2363 - /> 2364 - 2365 - {images.length > 1 && ( 2366 - <> 2367 - <button 2368 - onClick={(e) => { 2369 - e.stopPropagation(); 2370 - onNavigate?.((index - 1 + images.length) % images.length); 2371 - }} 2372 - className="absolute left-4 top-1/2 -translate-y-1/2 text-white text-4xl h-8 w-8 rounded-full bg-gray-900 flex items-center justify-center" 2373 - > 2374 - <svg xmlns="http://www.w3.org/2000/svg" width={28} height={28} viewBox="0 0 24 24"><g fill="none" fillRule="evenodd"><path d="M24 0v24H0V0zM12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.019-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"></path><path fill="currentColor" d="M8.293 12.707a1 1 0 0 1 0-1.414l5.657-5.657a1 1 0 1 1 1.414 1.414L10.414 12l4.95 4.95a1 1 0 0 1-1.414 1.414z"></path></g></svg> 2375 - </button> 2376 - <button 2377 - onClick={(e) => { 2378 - e.stopPropagation(); 2379 - onNavigate?.((index + 1) % images.length); 2380 - }} 2381 - className="absolute right-4 top-1/2 -translate-y-1/2 text-white text-4xl h-8 w-8 rounded-full bg-gray-900 flex items-center justify-center" 2382 - > 2383 - <svg xmlns="http://www.w3.org/2000/svg" width={28} height={28} viewBox="0 0 24 24"><g fill="none" fillRule="evenodd"><path d="M24 0v24H0V0zM12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.019-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"></path><path fill="currentColor" d="M15.707 11.293a1 1 0 0 1 0 1.414l-5.657 5.657a1 1 0 1 1-1.414-1.414l4.95-4.95l-4.95-4.95a1 1 0 0 1 1.414-1.414z"></path></g></svg> 2384 - </button> 2385 - </> 2386 - )} 2387 - </div>, 2388 - document.body 2389 - ); 2390 - } 2391 - 2392 2596 function getDomain(url: string) { 2393 2597 try { 2394 2598 const { hostname } = new URL(url); ··· 2419 2623 for (let i = 0; i < bytes.length; i++) { 2420 2624 map[byteIndex++] = charIndex; 2421 2625 } 2422 - charIndex++; 2626 + charIndex += char.length; 2423 2627 } 2424 2628 2425 2629 return map; ··· 2428 2632 function facetByteRangeToCharRange( 2429 2633 byteStart: number, 2430 2634 byteEnd: number, 2431 - byteToCharMap: number[], 2635 + byteToCharMap: number[] 2432 2636 ): [number, number] { 2433 2637 return [ 2434 2638 byteToCharMap[byteStart] ?? 0, ··· 2448 2652 const [start, end] = facetByteRangeToCharRange( 2449 2653 f.index.byteStart, 2450 2654 f.index.byteEnd, 2451 - map, 2655 + map 2452 2656 ); 2453 2657 return { start, end, feature: f.features[0] }; 2454 2658 }); 2455 2659 } 2456 - function renderTextWithFacets(text: string, facets: Facet[]) { 2660 + export function renderTextWithFacets({ 2661 + text, 2662 + facets, 2663 + navigate, 2664 + }: { 2665 + text: string; 2666 + facets: Facet[]; 2667 + navigate: (_: any) => void; 2668 + }) { 2457 2669 const ranges = extractFacetRanges(text, facets).sort( 2458 - (a: any, b: any) => a.start - b.start, 2670 + (a: any, b: any) => a.start - b.start 2459 2671 ); 2460 2672 2461 2673 const result: React.ReactNode[] = []; ··· 2467 2679 } 2468 2680 2469 2681 const fragment = text.slice(start, end); 2470 - // @ts-ignore 2682 + // @ts-expect-error i didnt bother with the correct types here sorry. bsky api types are cursed 2471 2683 if (feature.$type === "app.bsky.richtext.facet#link" && feature.uri) { 2472 2684 result.push( 2473 2685 <a 2474 - // @ts-ignore 2686 + // @ts-expect-error i didnt bother with the correct types here sorry. bsky api types are cursed 2475 2687 href={feature.uri} 2476 2688 key={start} 2477 2689 className="link" ··· 2487 2699 }} 2488 2700 > 2489 2701 {fragment} 2490 - </a>, 2702 + </a> 2491 2703 ); 2492 2704 } else if ( 2493 2705 feature.$type === "app.bsky.richtext.facet#mention" && 2494 - // @ts-ignore 2706 + // @ts-expect-error i didnt bother with the correct types here sorry. bsky api types are cursed 2495 2707 feature.did 2496 2708 ) { 2497 2709 result.push( 2498 2710 <span 2499 2711 key={start} 2500 2712 style={{ color: "rgb(29, 122, 242)" }} 2713 + className=" cursor-pointer" 2501 2714 onClick={(e) => { 2502 2715 e.stopPropagation(); 2716 + navigate({ 2717 + to: "/profile/$did", 2718 + // @ts-expect-error i didnt bother with the correct types here sorry. bsky api types are cursed 2719 + params: { did: feature.did }, 2720 + }); 2503 2721 }} 2504 2722 > 2505 2723 {fragment} 2506 - </span>, 2724 + </span> 2507 2725 ); 2508 2726 } else if (feature.$type === "app.bsky.richtext.facet#tag") { 2509 2727 result.push( ··· 2515 2733 }} 2516 2734 > 2517 2735 {fragment} 2518 - </span>, 2736 + </span> 2519 2737 ); 2520 2738 } else { 2521 2739 result.push(<span key={start}>{fragment}</span>); ··· 2594 2812 rel="noopener noreferrer" 2595 2813 onClick={(e) => { 2596 2814 e.stopPropagation(); 2597 - onOpen; 2815 + if (onOpen) onOpen(); 2598 2816 }} 2599 - /* @ts-ignore */ 2817 + /* @ts-expect-error css arent typed or something idk fuck you */ 2600 2818 style={linkStyle} 2601 2819 className="text-gray-500 dark:text-gray-400" 2602 2820 > 2603 - {/* @ts-ignore ehiaeih */} 2604 2821 <div 2605 2822 style={containerStyle as React.CSSProperties} 2606 - className="border border-gray-200 dark:border-gray-700" 2823 + className="border border-gray-200 dark:border-gray-800 was7" 2607 2824 > 2608 2825 {thumb && ( 2609 2826 <div ··· 2617 2834 marginBottom: 8, 2618 2835 //borderBottom: `1px solid ${theme.border}`, 2619 2836 }} 2620 - className="border-b border-gray-200 dark:border-gray-700" 2837 + className="border-b border-gray-200 dark:border-gray-800 was7" 2621 2838 > 2622 2839 <img 2623 2840 src={thumb} ··· 2641 2858 paddingTop: thumb ? 0 : 12, 2642 2859 }} 2643 2860 > 2644 - {/* @ts-ignore */} 2861 + {/* @ts-expect-error css */} 2645 2862 <div style={titleStyle} className="text-gray-900 dark:text-gray-100"> 2646 2863 {title} 2647 2864 </div> 2648 - {/* @ts-ignore */} 2649 2865 <div 2650 2866 style={descriptionStyle as React.CSSProperties} 2651 2867 className="text-gray-500 dark:text-gray-400" ··· 2708 2924 { 2709 2925 root: null, 2710 2926 threshold: 0.25, 2711 - }, 2927 + } 2712 2928 ); 2713 2929 2714 2930 if (containerRef.current) { ··· 2744 2960 borderRadius: 12, 2745 2961 //border: `1px solid ${theme.border}`, 2746 2962 }} 2747 - className="border border-gray-200 dark:border-gray-700" 2963 + className="border border-gray-200 dark:border-gray-800 was7" 2748 2964 onClick={async (e) => { 2749 2965 e.stopPropagation(); 2750 2966 setPlaying(true); ··· 2785 3001 100 / (aspect ? aspect.width / aspect.height : 16 / 9) 2786 3002 }%`, // 16:9 = 56.25%, 4:3 = 75% 2787 3003 }} 2788 - className="border border-gray-200 dark:border-gray-700" 3004 + className="border border-gray-200 dark:border-gray-800 was7" 2789 3005 > 2790 3006 <ReactPlayer 2791 3007 src={url}
+59
src/components/radix-m3-rd/Button.tsx
··· 1 + import { Slot } from "@radix-ui/react-slot"; 2 + import clsx from "clsx"; 3 + import * as React from "react"; 4 + 5 + export type ButtonVariant = "filled" | "outlined" | "text" | "secondary"; 6 + export type ButtonSize = "sm" | "md" | "lg"; 7 + 8 + const variantClasses: Record<ButtonVariant, string> = { 9 + filled: 10 + "bg-gray-300 text-gray-900 hover:bg-gray-400 dark:bg-gray-600 dark:text-white dark:hover:bg-gray-500", 11 + secondary: 12 + "bg-gray-300 text-gray-900 hover:bg-gray-400 dark:bg-gray-600 dark:text-white dark:hover:bg-gray-500", 13 + outlined: 14 + "border border-gray-800 text-gray-800 hover:bg-gray-100 dark:border-gray-200 dark:text-gray-200 dark:hover:bg-gray-800/10", 15 + text: "bg-transparent text-gray-800 hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-gray-800/10", 16 + }; 17 + 18 + const sizeClasses: Record<ButtonSize, string> = { 19 + sm: "px-3 py-1.5 text-sm", 20 + md: "px-4 py-2 text-base", 21 + lg: "px-6 py-3 text-lg", 22 + }; 23 + 24 + export function Button({ 25 + variant = "filled", 26 + size = "md", 27 + asChild = false, 28 + ref, 29 + className, 30 + children, 31 + ...props 32 + }: { 33 + variant?: ButtonVariant; 34 + size?: ButtonSize; 35 + asChild?: boolean; 36 + className?: string; 37 + children?: React.ReactNode; 38 + ref?: React.Ref<HTMLButtonElement>; 39 + } & React.ComponentPropsWithoutRef<"button">) { 40 + const Comp = asChild ? Slot : "button"; 41 + 42 + return ( 43 + <Comp 44 + ref={ref} 45 + className={clsx( 46 + //focus:outline-none focus:ring-1 focus:ring-offset-1 focus:ring-gray-500 dark:focus:ring-gray-300 47 + "inline-flex items-center justify-center rounded-full transition-colors disabled:opacity-50 disabled:cursor-not-allowed", 48 + variantClasses[variant], 49 + sizeClasses[size], 50 + className 51 + )} 52 + {...props} 53 + > 54 + {children} 55 + </Comp> 56 + ); 57 + } 58 + 59 + Button.displayName = "Button";
+24
src/components/shrinkpadding.tsx
··· 1 + import { useEffect, useState } from "react"; 2 + 3 + export default function ShrinkingBox() { 4 + const [size, setSize] = useState(2000); 5 + 6 + useEffect(() => { 7 + const interval = setInterval(() => { 8 + setSize(prev => Math.max(prev - 125, 0)); 9 + }, 250); 10 + 11 + return () => clearInterval(interval); 12 + }, []); 13 + 14 + return ( 15 + <div 16 + style={{ 17 + //width: `${size}px`, 18 + height: `${size}px`, 19 + //backgroundColor: "skyblue", 20 + transition: "all 0.5s ease", 21 + }} 22 + /> 23 + ); 24 + }
+77 -8
src/main.tsx
··· 1 - import { StrictMode } from "react"; 1 + import "~/styles/app.css"; 2 + 3 + import { createSyncStoragePersister } from "@tanstack/query-sync-storage-persister"; 4 + import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; 5 + import { persistQueryClient } from "@tanstack/react-query-persist-client"; 6 + import { createRouter, RouterProvider } from "@tanstack/react-router"; 7 + import { useSetAtom } from "jotai"; 8 + import { useEffect } from "react"; 9 + //import { StrictMode } from "react"; 2 10 import ReactDOM from "react-dom/client"; 3 - import { RouterProvider, createRouter } from "@tanstack/react-router"; 4 11 12 + import reportWebVitals from "./reportWebVitals.ts"; 5 13 // Import the generated route tree 6 14 import { routeTree } from "./routeTree.gen"; 15 + import { isAtTopAtom } from "./utils/atoms.ts"; 7 16 8 - import "~/styles/app.css"; 9 - import reportWebVitals from "./reportWebVitals.ts"; 17 + //initAtomToCssVar(hueAtom, "--tw-gray-hue") 18 + 19 + const queryClient = new QueryClient({ 20 + defaultOptions: { 21 + queries: { 22 + gcTime: 1000 * 60 * 60 * 24 * 24, // 24 days 23 + }, 24 + }, 25 + }); 26 + const localStoragePersister = createSyncStoragePersister({ 27 + storage: window.localStorage, 28 + }); 29 + 30 + persistQueryClient({ 31 + queryClient, 32 + persister: localStoragePersister, 33 + }); 10 34 11 35 // Create a new router instance 12 36 const router = createRouter({ 13 37 routeTree, 14 - context: {}, 38 + context: { queryClient }, 15 39 defaultPreload: "intent", 16 40 scrollRestoration: true, 17 41 defaultStructuralSharing: true, ··· 31 55 const root = ReactDOM.createRoot(rootElement); 32 56 root.render( 33 57 // double queries annoys me 34 - <StrictMode> 58 + // <StrictMode> 59 + <QueryClientProvider client={queryClient}> 60 + <ScrollTopWatcher /> 35 61 <RouterProvider router={router} /> 36 - </StrictMode> 62 + </QueryClientProvider> 63 + // </StrictMode> 37 64 ); 38 65 } 39 66 40 67 // If you want to start measuring performance in your app, pass a function 41 - // to log results (for example: reportWebVitals(console.log)) 68 + // to log results (for example: reportWebVitals(// /*mass comment*/ console.log)) 42 69 // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 43 70 reportWebVitals(); 71 + 72 + export default function ScrollTopWatcher() { 73 + const setIsAtTop = useSetAtom(isAtTopAtom); 74 + useEffect(() => { 75 + const meta = document.querySelector('meta[name="theme-color"]'); 76 + let lastAtTop = window.scrollY === 0; 77 + let timeoutId: number | undefined; 78 + 79 + const setVars = (atTop: boolean) => { 80 + const root = document.documentElement; 81 + root.style.setProperty("--is-top", atTop ? "1" : "0"); 82 + 83 + const bg = getComputedStyle(root).getPropertyValue("--header-bg").trim(); 84 + if (meta && bg) meta.setAttribute("content", bg); 85 + setIsAtTop(atTop); 86 + }; 87 + 88 + const check = () => { 89 + const atTop = window.scrollY === 0; 90 + if (atTop !== lastAtTop) { 91 + lastAtTop = atTop; 92 + setVars(atTop); 93 + } 94 + }; 95 + 96 + const handleScroll = () => { 97 + if (timeoutId) clearTimeout(timeoutId); 98 + timeoutId = window.setTimeout(check, 2); 99 + }; 100 + 101 + // initialize 102 + setVars(lastAtTop); 103 + window.addEventListener("scroll", handleScroll, { passive: true }); 104 + 105 + return () => { 106 + window.removeEventListener("scroll", handleScroll); 107 + if (timeoutId) clearTimeout(timeoutId); 108 + }; 109 + }, []); 110 + 111 + return null; 112 + }
-149
src/providers/PassAuthProvider.tsx
··· 1 - import React, { createContext, useState, useEffect, useContext } from "react"; 2 - import { AtpAgent, type AtpSessionData } from "@atproto/api"; 3 - 4 - interface AuthContextValue { 5 - agent: AtpAgent | null; 6 - loginStatus: boolean; 7 - login: (user: string, password: string, service?: string) => Promise<void>; 8 - logout: () => Promise<void>; 9 - loading: boolean; 10 - authed: boolean | undefined; 11 - } 12 - 13 - const AuthContext = createContext<AuthContextValue>({} as AuthContextValue); 14 - 15 - export const AuthProvider = ({ children }: { children: React.ReactNode }) => { 16 - const [agent, setAgent] = useState<AtpAgent | null>(null); 17 - const [loginStatus, setLoginStatus] = useState(false); 18 - const [loading, setLoading] = useState(true); 19 - const [increment, setIncrement] = useState(0); 20 - const [authed, setAuthed] = useState<boolean | undefined>(undefined); 21 - 22 - useEffect(() => { 23 - const initialize = async () => { 24 - try { 25 - const service = localStorage.getItem("service"); 26 - // const user = await AsyncStorage.getItem('user'); 27 - // const password = await AsyncStorage.getItem('password'); 28 - const session = localStorage.getItem("sess"); 29 - 30 - if (service && session) { 31 - console.log("Auto-login service is:", service); 32 - const apiAgent = new AtpAgent({ service }); 33 - try { 34 - if (!apiAgent) { 35 - console.log("Agent is null or undefined"); 36 - return; 37 - } 38 - let sess: AtpSessionData = JSON.parse(session); 39 - console.log("resuming session is:", sess); 40 - const { data } = await apiAgent.resumeSession(sess); 41 - console.log("!!!8!!! agent resume session"); 42 - setAgent(apiAgent); 43 - setLoginStatus(true); 44 - setLoading(false); 45 - setAuthed(true); 46 - } catch (e) { 47 - console.log("Failed to resume session" + e); 48 - setLoginStatus(true); 49 - localStorage.removeItem("sess"); 50 - localStorage.removeItem("service"); 51 - const apiAgent = new AtpAgent({ service: "https://api.bsky.app" }); 52 - setAgent(apiAgent); 53 - setLoginStatus(true); 54 - setLoading(false); 55 - setAuthed(false); 56 - return; 57 - } 58 - } else { 59 - const apiAgent = new AtpAgent({ service: "https://api.bsky.app" }); 60 - setAgent(apiAgent); 61 - setLoginStatus(true); 62 - setLoading(false); 63 - setAuthed(false); 64 - } 65 - } catch (e) { 66 - console.log("Failed to auto-login:", e); 67 - } finally { 68 - setLoading(false); 69 - } 70 - }; 71 - 72 - initialize(); 73 - }, [increment]); 74 - 75 - const login = async ( 76 - user: string, 77 - password: string, 78 - service: string = "https://bsky.social", 79 - ) => { 80 - try { 81 - let sessionthing; 82 - const apiAgent = new AtpAgent({ 83 - service: service, 84 - persistSession: (evt, sess) => { 85 - sessionthing = sess; 86 - }, 87 - }); 88 - await apiAgent.login({ identifier: user, password }); 89 - console.log("!!!8!!! agent logged on"); 90 - 91 - localStorage.setItem("service", service); 92 - // await AsyncStorage.setItem('user', user); 93 - // await AsyncStorage.setItem('password', password); 94 - if (sessionthing) { 95 - localStorage.setItem("sess", JSON.stringify(sessionthing)); 96 - } else { 97 - localStorage.setItem("sess", "{}"); 98 - } 99 - 100 - setAgent(apiAgent); 101 - setLoginStatus(true); 102 - setAuthed(true); 103 - } catch (e) { 104 - console.error("Login failed:", e); 105 - } 106 - }; 107 - 108 - const logout = async () => { 109 - if (!agent) { 110 - console.error("Agent is null or undefined"); 111 - return; 112 - } 113 - setLoading(true); 114 - try { 115 - // check if its even in async storage before removing 116 - if (localStorage.getItem("service") && localStorage.getItem("sess")) { 117 - localStorage.removeItem("service"); 118 - localStorage.removeItem("sess"); 119 - } 120 - await agent.logout(); 121 - console.log("!!!8!!! agent logout"); 122 - setLoginStatus(false); 123 - setAuthed(undefined); 124 - await agent.com.atproto.server.deleteSession(); 125 - console.log("!!!8!!! agent deltesession"); 126 - //setAgent(null); 127 - setIncrement(increment + 1); 128 - } catch (e) { 129 - console.error("Logout failed:", e); 130 - } finally { 131 - setLoading(false); 132 - } 133 - }; 134 - 135 - // why the hell are we doing this 136 - /*if (loading) { 137 - return <div><span>Laoding...ae</span></div>; 138 - }*/ 139 - 140 - return ( 141 - <AuthContext.Provider 142 - value={{ agent, loginStatus, login, logout, loading, authed }} 143 - > 144 - {children} 145 - </AuthContext.Provider> 146 - ); 147 - }; 148 - 149 - export const useAuth = () => useContext(AuthContext);
-61
src/providers/PersistentStoreProvider.tsx
··· 1 - import React, { createContext, useContext, useCallback } from "react"; 2 - import { get as idbGet, set as idbSet, del as idbDel } from "idb-keyval"; 3 - 4 - type PersistentValue = { 5 - value: string; 6 - time: number; 7 - }; 8 - 9 - type PersistentStoreContextType = { 10 - get: (key: string) => Promise<PersistentValue | null>; 11 - set: (key: string, value: string) => Promise<void>; 12 - remove: (key: string) => Promise<void>; 13 - }; 14 - 15 - const PersistentStoreContext = createContext<PersistentStoreContextType | null>( 16 - null, 17 - ); 18 - 19 - export const PersistentStoreProvider: React.FC<{ 20 - children: React.ReactNode; 21 - }> = ({ children }) => { 22 - const get = useCallback( 23 - async (key: string): Promise<PersistentValue | null> => { 24 - if (typeof window === "undefined") return null; 25 - const raw = await idbGet(key); 26 - if (!raw) return null; 27 - try { 28 - return JSON.parse(raw) as PersistentValue; 29 - } catch { 30 - return null; 31 - } 32 - }, 33 - [], 34 - ); 35 - 36 - const set = useCallback(async (key: string, value: string) => { 37 - if (typeof window === "undefined") return; 38 - const entry: PersistentValue = { value, time: Date.now() }; 39 - await idbSet(key, JSON.stringify(entry)); 40 - }, []); 41 - 42 - const remove = useCallback(async (key: string) => { 43 - if (typeof window === "undefined") return; 44 - await idbDel(key); 45 - }, []); 46 - 47 - return ( 48 - <PersistentStoreContext.Provider value={{ get, set, remove }}> 49 - {children} 50 - </PersistentStoreContext.Provider> 51 - ); 52 - }; 53 - 54 - export const usePersistentStore = (): PersistentStoreContextType => { 55 - const context = useContext(PersistentStoreContext); 56 - if (!context) 57 - throw new Error( 58 - "usePersistentStore must be used within a PersistentStoreProvider", 59 - ); 60 - return context; 61 - };
+209
src/providers/UnifiedAuthProvider.tsx
··· 1 + import { Agent, AtpAgent, type AtpSessionData } from "@atproto/api"; 2 + import { 3 + type OAuthSession, 4 + TokenInvalidError, 5 + TokenRefreshError, 6 + TokenRevokedError, 7 + } from "@atproto/oauth-client-browser"; 8 + import { useAtom } from "jotai"; 9 + import React, { 10 + createContext, 11 + use, 12 + useCallback, 13 + useEffect, 14 + useState, 15 + } from "react"; 16 + 17 + import { quickAuthAtom } from "~/utils/atoms"; 18 + 19 + import { oauthClient } from "../utils/oauthClient"; 20 + 21 + type AuthStatus = "loading" | "signedIn" | "signedOut"; 22 + type AuthMethod = "password" | "oauth" | null; 23 + 24 + interface AuthContextValue { 25 + agent: Agent | null; 26 + status: AuthStatus; 27 + authMethod: AuthMethod; 28 + loginWithPassword: ( 29 + user: string, 30 + password: string, 31 + service?: string, 32 + ) => Promise<void>; 33 + loginWithOAuth: (handleOrPdsUrl: string) => Promise<void>; 34 + logout: () => Promise<void>; 35 + } 36 + 37 + const AuthContext = createContext<AuthContextValue>({} as AuthContextValue); 38 + 39 + export const UnifiedAuthProvider = ({ 40 + children, 41 + }: { 42 + children: React.ReactNode; 43 + }) => { 44 + const [agent, setAgent] = useState<Agent | null>(null); 45 + const [status, setStatus] = useState<AuthStatus>("loading"); 46 + const [authMethod, setAuthMethod] = useState<AuthMethod>(null); 47 + const [oauthSession, setOauthSession] = useState<OAuthSession | null>(null); 48 + const [quickAuth, setQuickAuth] = useAtom(quickAuthAtom); 49 + 50 + const initialize = useCallback(async () => { 51 + try { 52 + const oauthResult = await oauthClient.init(); 53 + if (oauthResult) { 54 + // /*mass comment*/ console.log("OAuth session restored."); 55 + const apiAgent = new Agent(oauthResult.session); 56 + setAgent(apiAgent); 57 + setOauthSession(oauthResult.session); 58 + setAuthMethod("oauth"); 59 + setStatus("signedIn"); 60 + setQuickAuth(apiAgent?.did || null); 61 + return; 62 + } 63 + } catch (e) { 64 + console.error("OAuth init failed, checking password session.", e); 65 + if (!quickAuth) { 66 + // quickAuth restoration. if last used method is oauth we immediately call for oauth redo 67 + // (and set a persistent atom somewhere to not retry again if it failed) 68 + } 69 + } 70 + 71 + try { 72 + const service = localStorage.getItem("service"); 73 + const sessionString = localStorage.getItem("sess"); 74 + 75 + if (service && sessionString) { 76 + // /*mass comment*/ console.log("Resuming password-based session using AtpAgent..."); 77 + const apiAgent = new AtpAgent({ service }); 78 + const session: AtpSessionData = JSON.parse(sessionString); 79 + await apiAgent.resumeSession(session); 80 + 81 + // /*mass comment*/ console.log("Password-based session resumed successfully."); 82 + setAgent(apiAgent); 83 + setAuthMethod("password"); 84 + setStatus("signedIn"); 85 + setQuickAuth(apiAgent?.did || null); 86 + return; 87 + } 88 + } catch (e) { 89 + console.error("Failed to resume password-based session.", e); 90 + localStorage.removeItem("sess"); 91 + localStorage.removeItem("service"); 92 + } 93 + 94 + // /*mass comment*/ console.log("No active session found."); 95 + setStatus("signedOut"); 96 + setAgent(null); 97 + setAuthMethod(null); 98 + // do we want to null it here? 99 + setQuickAuth(null); 100 + }, [quickAuth, setQuickAuth]); 101 + 102 + useEffect(() => { 103 + const handleOAuthSessionDeleted = ( 104 + event: CustomEvent<{ sub: string; cause: TokenRefreshError | TokenRevokedError | TokenInvalidError }>, 105 + ) => { 106 + console.error(`OAuth Session for ${event.detail.sub} was deleted.`, event.detail.cause); 107 + setAgent(null); 108 + setOauthSession(null); 109 + setAuthMethod(null); 110 + setStatus("signedOut"); 111 + setQuickAuth(null); 112 + }; 113 + 114 + oauthClient.addEventListener("deleted", handleOAuthSessionDeleted as EventListener); 115 + initialize(); 116 + 117 + return () => { 118 + oauthClient.removeEventListener("deleted", handleOAuthSessionDeleted as EventListener); 119 + }; 120 + }, [initialize, setQuickAuth]); 121 + 122 + const loginWithPassword = async ( 123 + user: string, 124 + password: string, 125 + service: string = "https://bsky.social", 126 + ) => { 127 + if (status !== "signedOut") return; 128 + setStatus("loading"); 129 + try { 130 + let sessionData: AtpSessionData | undefined; 131 + const apiAgent = new AtpAgent({ 132 + service, 133 + persistSession: (_evt, sess) => { 134 + sessionData = sess; 135 + }, 136 + }); 137 + await apiAgent.login({ identifier: user, password }); 138 + 139 + if (sessionData) { 140 + localStorage.setItem("service", service); 141 + localStorage.setItem("sess", JSON.stringify(sessionData)); 142 + setAgent(apiAgent); 143 + setAuthMethod("password"); 144 + setStatus("signedIn"); 145 + setQuickAuth(apiAgent?.did || null); 146 + // /*mass comment*/ console.log("Successfully logged in with password."); 147 + } else { 148 + throw new Error("Session data not persisted after login."); 149 + } 150 + } catch (e) { 151 + console.error("Password login failed:", e); 152 + setStatus("signedOut"); 153 + setQuickAuth(null); 154 + throw e; 155 + } 156 + }; 157 + 158 + const loginWithOAuth = useCallback(async (handleOrPdsUrl: string) => { 159 + if (status !== "signedOut") return; 160 + try { 161 + sessionStorage.setItem("postLoginRedirect", window.location.pathname + window.location.search); 162 + await oauthClient.signIn(handleOrPdsUrl); 163 + } catch (err) { 164 + console.error("OAuth sign-in aborted or failed:", err); 165 + } 166 + }, [status]); 167 + 168 + const logout = useCallback(async () => { 169 + if (status !== "signedIn" || !agent) return; 170 + setStatus("loading"); 171 + 172 + try { 173 + if (authMethod === "oauth" && oauthSession) { 174 + await oauthClient.revoke(oauthSession.sub); 175 + // /*mass comment*/ console.log("OAuth session revoked."); 176 + } else if (authMethod === "password") { 177 + localStorage.removeItem("service"); 178 + localStorage.removeItem("sess"); 179 + await (agent as AtpAgent).com.atproto.server.deleteSession(); 180 + // /*mass comment*/ console.log("Password-based session deleted."); 181 + } 182 + } catch (e) { 183 + console.error("Logout failed:", e); 184 + } finally { 185 + setAgent(null); 186 + setAuthMethod(null); 187 + setOauthSession(null); 188 + setStatus("signedOut"); 189 + setQuickAuth(null); 190 + } 191 + }, [status, agent, authMethod, oauthSession, setQuickAuth]); 192 + 193 + return ( 194 + <AuthContext 195 + value={{ 196 + agent, 197 + status, 198 + authMethod, 199 + loginWithPassword, 200 + loginWithOAuth, 201 + logout, 202 + }} 203 + > 204 + {children} 205 + </AuthContext> 206 + ); 207 + }; 208 + 209 + export const useAuth = () => use(AuthContext);
+57 -5
src/routeTree.gen.ts
··· 15 15 import { Route as FeedsRouteImport } from './routes/feeds' 16 16 import { Route as PathlessLayoutRouteImport } from './routes/_pathlessLayout' 17 17 import { Route as IndexRouteImport } from './routes/index' 18 + import { Route as CallbackIndexRouteImport } from './routes/callback/index' 18 19 import { Route as PathlessLayoutNestedLayoutRouteImport } from './routes/_pathlessLayout/_nested-layout' 19 20 import { Route as ProfileDidIndexRouteImport } from './routes/profile.$did/index' 20 21 import { Route as PathlessLayoutNestedLayoutRouteBRouteImport } from './routes/_pathlessLayout/_nested-layout/route-b' 21 22 import { Route as PathlessLayoutNestedLayoutRouteARouteImport } from './routes/_pathlessLayout/_nested-layout/route-a' 22 23 import { Route as ProfileDidPostRkeyRouteImport } from './routes/profile.$did/post.$rkey' 24 + import { Route as ProfileDidPostRkeyImageIRouteImport } from './routes/profile.$did/post.$rkey.image.$i' 23 25 24 26 const SettingsRoute = SettingsRouteImport.update({ 25 27 id: '/settings', ··· 50 52 path: '/', 51 53 getParentRoute: () => rootRouteImport, 52 54 } as any) 55 + const CallbackIndexRoute = CallbackIndexRouteImport.update({ 56 + id: '/callback/', 57 + path: '/callback/', 58 + getParentRoute: () => rootRouteImport, 59 + } as any) 53 60 const PathlessLayoutNestedLayoutRoute = 54 61 PathlessLayoutNestedLayoutRouteImport.update({ 55 62 id: '/_nested-layout', ··· 77 84 path: '/profile/$did/post/$rkey', 78 85 getParentRoute: () => rootRouteImport, 79 86 } as any) 87 + const ProfileDidPostRkeyImageIRoute = 88 + ProfileDidPostRkeyImageIRouteImport.update({ 89 + id: '/image/$i', 90 + path: '/image/$i', 91 + getParentRoute: () => ProfileDidPostRkeyRoute, 92 + } as any) 80 93 81 94 export interface FileRoutesByFullPath { 82 95 '/': typeof IndexRoute ··· 84 97 '/notifications': typeof NotificationsRoute 85 98 '/search': typeof SearchRoute 86 99 '/settings': typeof SettingsRoute 100 + '/callback': typeof CallbackIndexRoute 87 101 '/route-a': typeof PathlessLayoutNestedLayoutRouteARoute 88 102 '/route-b': typeof PathlessLayoutNestedLayoutRouteBRoute 89 103 '/profile/$did': typeof ProfileDidIndexRoute 90 - '/profile/$did/post/$rkey': typeof ProfileDidPostRkeyRoute 104 + '/profile/$did/post/$rkey': typeof ProfileDidPostRkeyRouteWithChildren 105 + '/profile/$did/post/$rkey/image/$i': typeof ProfileDidPostRkeyImageIRoute 91 106 } 92 107 export interface FileRoutesByTo { 93 108 '/': typeof IndexRoute ··· 95 110 '/notifications': typeof NotificationsRoute 96 111 '/search': typeof SearchRoute 97 112 '/settings': typeof SettingsRoute 113 + '/callback': typeof CallbackIndexRoute 98 114 '/route-a': typeof PathlessLayoutNestedLayoutRouteARoute 99 115 '/route-b': typeof PathlessLayoutNestedLayoutRouteBRoute 100 116 '/profile/$did': typeof ProfileDidIndexRoute 101 - '/profile/$did/post/$rkey': typeof ProfileDidPostRkeyRoute 117 + '/profile/$did/post/$rkey': typeof ProfileDidPostRkeyRouteWithChildren 118 + '/profile/$did/post/$rkey/image/$i': typeof ProfileDidPostRkeyImageIRoute 102 119 } 103 120 export interface FileRoutesById { 104 121 __root__: typeof rootRouteImport ··· 109 126 '/search': typeof SearchRoute 110 127 '/settings': typeof SettingsRoute 111 128 '/_pathlessLayout/_nested-layout': typeof PathlessLayoutNestedLayoutRouteWithChildren 129 + '/callback/': typeof CallbackIndexRoute 112 130 '/_pathlessLayout/_nested-layout/route-a': typeof PathlessLayoutNestedLayoutRouteARoute 113 131 '/_pathlessLayout/_nested-layout/route-b': typeof PathlessLayoutNestedLayoutRouteBRoute 114 132 '/profile/$did/': typeof ProfileDidIndexRoute 115 - '/profile/$did/post/$rkey': typeof ProfileDidPostRkeyRoute 133 + '/profile/$did/post/$rkey': typeof ProfileDidPostRkeyRouteWithChildren 134 + '/profile/$did/post/$rkey/image/$i': typeof ProfileDidPostRkeyImageIRoute 116 135 } 117 136 export interface FileRouteTypes { 118 137 fileRoutesByFullPath: FileRoutesByFullPath ··· 122 141 | '/notifications' 123 142 | '/search' 124 143 | '/settings' 144 + | '/callback' 125 145 | '/route-a' 126 146 | '/route-b' 127 147 | '/profile/$did' 128 148 | '/profile/$did/post/$rkey' 149 + | '/profile/$did/post/$rkey/image/$i' 129 150 fileRoutesByTo: FileRoutesByTo 130 151 to: 131 152 | '/' ··· 133 154 | '/notifications' 134 155 | '/search' 135 156 | '/settings' 157 + | '/callback' 136 158 | '/route-a' 137 159 | '/route-b' 138 160 | '/profile/$did' 139 161 | '/profile/$did/post/$rkey' 162 + | '/profile/$did/post/$rkey/image/$i' 140 163 id: 141 164 | '__root__' 142 165 | '/' ··· 146 169 | '/search' 147 170 | '/settings' 148 171 | '/_pathlessLayout/_nested-layout' 172 + | '/callback/' 149 173 | '/_pathlessLayout/_nested-layout/route-a' 150 174 | '/_pathlessLayout/_nested-layout/route-b' 151 175 | '/profile/$did/' 152 176 | '/profile/$did/post/$rkey' 177 + | '/profile/$did/post/$rkey/image/$i' 153 178 fileRoutesById: FileRoutesById 154 179 } 155 180 export interface RootRouteChildren { ··· 159 184 NotificationsRoute: typeof NotificationsRoute 160 185 SearchRoute: typeof SearchRoute 161 186 SettingsRoute: typeof SettingsRoute 187 + CallbackIndexRoute: typeof CallbackIndexRoute 162 188 ProfileDidIndexRoute: typeof ProfileDidIndexRoute 163 - ProfileDidPostRkeyRoute: typeof ProfileDidPostRkeyRoute 189 + ProfileDidPostRkeyRoute: typeof ProfileDidPostRkeyRouteWithChildren 164 190 } 165 191 166 192 declare module '@tanstack/react-router' { ··· 207 233 preLoaderRoute: typeof IndexRouteImport 208 234 parentRoute: typeof rootRouteImport 209 235 } 236 + '/callback/': { 237 + id: '/callback/' 238 + path: '/callback' 239 + fullPath: '/callback' 240 + preLoaderRoute: typeof CallbackIndexRouteImport 241 + parentRoute: typeof rootRouteImport 242 + } 210 243 '/_pathlessLayout/_nested-layout': { 211 244 id: '/_pathlessLayout/_nested-layout' 212 245 path: '' ··· 242 275 preLoaderRoute: typeof ProfileDidPostRkeyRouteImport 243 276 parentRoute: typeof rootRouteImport 244 277 } 278 + '/profile/$did/post/$rkey/image/$i': { 279 + id: '/profile/$did/post/$rkey/image/$i' 280 + path: '/image/$i' 281 + fullPath: '/profile/$did/post/$rkey/image/$i' 282 + preLoaderRoute: typeof ProfileDidPostRkeyImageIRouteImport 283 + parentRoute: typeof ProfileDidPostRkeyRoute 284 + } 245 285 } 246 286 } 247 287 ··· 275 315 PathlessLayoutRouteChildren, 276 316 ) 277 317 318 + interface ProfileDidPostRkeyRouteChildren { 319 + ProfileDidPostRkeyImageIRoute: typeof ProfileDidPostRkeyImageIRoute 320 + } 321 + 322 + const ProfileDidPostRkeyRouteChildren: ProfileDidPostRkeyRouteChildren = { 323 + ProfileDidPostRkeyImageIRoute: ProfileDidPostRkeyImageIRoute, 324 + } 325 + 326 + const ProfileDidPostRkeyRouteWithChildren = 327 + ProfileDidPostRkeyRoute._addFileChildren(ProfileDidPostRkeyRouteChildren) 328 + 278 329 const rootRouteChildren: RootRouteChildren = { 279 330 IndexRoute: IndexRoute, 280 331 PathlessLayoutRoute: PathlessLayoutRouteWithChildren, ··· 282 333 NotificationsRoute: NotificationsRoute, 283 334 SearchRoute: SearchRoute, 284 335 SettingsRoute: SettingsRoute, 336 + CallbackIndexRoute: CallbackIndexRoute, 285 337 ProfileDidIndexRoute: ProfileDidIndexRoute, 286 - ProfileDidPostRkeyRoute: ProfileDidPostRkeyRoute, 338 + ProfileDidPostRkeyRoute: ProfileDidPostRkeyRouteWithChildren, 287 339 } 288 340 export const routeTree = rootRouteImport 289 341 ._addFileChildren(rootRouteChildren)
+586 -473
src/routes/__root.tsx
··· 2 2 3 3 // dont forget to run this 4 4 // npx @tanstack/router-cli generate 5 - 6 - import { useState, type SVGProps } from "react"; 5 + import type { QueryClient } from "@tanstack/react-query"; 7 6 import { 8 - HeadContent, 9 - Link, 10 - Outlet, 7 + createRootRouteWithContext, 8 + // Link, 9 + // Outlet, 11 10 Scripts, 12 - createRootRoute, 13 11 useLocation, 12 + useNavigate, 14 13 } from "@tanstack/react-router"; 15 14 import { TanStackRouterDevtools } from "@tanstack/react-router-devtools"; 15 + import { useAtom } from "jotai"; 16 16 import * as React from "react"; 17 + import { KeepAliveOutlet, KeepAliveProvider } from "tanstack-router-keepalive"; 18 + 19 + import { Composer } from "~/components/Composer"; 17 20 import { DefaultCatchBoundary } from "~/components/DefaultCatchBoundary"; 21 + import { Import } from "~/components/Import"; 18 22 import Login from "~/components/Login"; 19 23 import { NotFound } from "~/components/NotFound"; 20 - import appCss from "~/styles/app.css?url"; 24 + import { FluentEmojiHighContrastGlowingStar } from "~/components/Star"; 25 + import { UnifiedAuthProvider, useAuth } from "~/providers/UnifiedAuthProvider"; 26 + import { composerAtom, hueAtom, useAtomCssVar } from "~/utils/atoms"; 21 27 import { seo } from "~/utils/seo"; 22 - import { AuthProvider, useAuth } from "~/providers/PassAuthProvider"; 23 - import { PersistentStoreProvider } from "~/providers/PersistentStoreProvider"; 24 - import type AtpAgent from "@atproto/api"; 25 28 26 - export const Route = createRootRoute({ 29 + export const Route = createRootRouteWithContext<{ 30 + queryClient: QueryClient; 31 + }>()({ 27 32 head: () => ({ 28 33 meta: [ 29 34 { ··· 39 44 }), 40 45 ], 41 46 links: [ 42 - { rel: "stylesheet", href: appCss }, 43 47 { 44 48 rel: "apple-touch-icon", 45 49 sizes: "180x180", ··· 61 65 { rel: "icon", href: "/favicon.ico" }, 62 66 ], 63 67 }), 64 - errorComponent: (props) => { 65 - return ( 66 - <RootDocument> 67 - <DefaultCatchBoundary {...props} /> 68 - </RootDocument> 69 - ); 70 - }, 68 + errorComponent: import.meta.env.DEV 69 + ? undefined 70 + : (props) => ( 71 + <RootDocument> 72 + <DefaultCatchBoundary {...props} /> 73 + </RootDocument> 74 + ), 71 75 notFoundComponent: () => <NotFound />, 72 76 component: RootComponent, 73 77 }); 74 78 75 79 function RootComponent() { 76 80 return ( 77 - <AuthProvider> 78 - <PersistentStoreProvider> 79 - <RootDocument> 80 - <Outlet /> 81 - </RootDocument> 82 - </PersistentStoreProvider> 83 - </AuthProvider> 81 + <UnifiedAuthProvider> 82 + <RootDocument> 83 + <KeepAliveProvider> 84 + <KeepAliveOutlet /> 85 + </KeepAliveProvider> 86 + </RootDocument> 87 + </UnifiedAuthProvider> 84 88 ); 85 89 } 86 90 87 91 function RootDocument({ children }: { children: React.ReactNode }) { 92 + useAtomCssVar(hueAtom, "--tw-gray-hue"); 88 93 const location = useLocation(); 89 - const { agent, authed } = useAuth(); 94 + const navigate = useNavigate(); 95 + const { agent } = useAuth(); 96 + const authed = !!agent?.did; 90 97 const isHome = location.pathname === "/"; 91 98 const isNotifications = location.pathname.startsWith("/notifications"); 92 - const isProfile = location.pathname.startsWith("/profile/"); 99 + const isProfile = 100 + agent && 101 + (location.pathname === `/profile/${agent?.did}` || 102 + location.pathname === `/profile/${encodeURIComponent(agent?.did ?? "")}`); 103 + const isSettings = location.pathname.startsWith("/settings"); 104 + const isSearch = location.pathname.startsWith("/search"); 105 + const isFeeds = location.pathname.startsWith("/feeds"); 93 106 94 - const [postOpen, setPostOpen] = useState(false); 95 - const [postText, setPostText] = useState(""); 96 - const [posting, setPosting] = useState(false); 97 - const [postSuccess, setPostSuccess] = useState(false); 98 - const [postError, setPostError] = useState<string | null>(null); 107 + const locationEnum: 108 + | "feeds" 109 + | "search" 110 + | "settings" 111 + | "notifications" 112 + | "profile" 113 + | "home" = isFeeds 114 + ? "feeds" 115 + : isSearch 116 + ? "search" 117 + : isSettings 118 + ? "settings" 119 + : isNotifications 120 + ? "notifications" 121 + : isProfile 122 + ? "profile" 123 + : "home"; 99 124 100 - async function handlePost() { 101 - if (!agent) return; 102 - setPosting(true); 103 - setPostError(null); 104 - try { 105 - await agent.com.atproto.repo.createRecord({ 106 - collection: "app.bsky.feed.post", 107 - repo: agent.assertDid, 108 - record: { 109 - $type: "app.bsky.feed.post", 110 - text: postText, 111 - createdAt: new Date().toISOString(), 112 - }, 113 - }); 114 - setPostSuccess(true); 115 - setPostText(""); 116 - setTimeout(() => { 117 - setPostSuccess(false); 118 - setPostOpen(false); 119 - }, 1500); 120 - } catch (e: any) { 121 - setPostError(e?.message || "Failed to post"); 122 - } finally { 123 - setPosting(false); 124 - } 125 - } 125 + const [, setComposerPost] = useAtom(composerAtom); 126 126 127 127 return ( 128 128 <> 129 - {postOpen && ( 130 - <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40"> 131 - <div className="bg-white dark:bg-gray-900 rounded-lg shadow-lg p-6 w-full max-w-md relative"> 132 - <button 133 - className="absolute top-2 right-2 text-gray-400 hover:text-gray-700 dark:hover:text-gray-200" 134 - onClick={() => !posting && setPostOpen(false)} 135 - disabled={posting} 136 - aria-label="Close" 137 - > 138 - ร— 139 - </button> 140 - <h2 className="text-lg font-bold mb-2">Create Post</h2> 141 - {postSuccess ? ( 142 - <div className="flex flex-col items-center justify-center py-8"> 143 - <span className="text-green-500 text-4xl mb-2">โœ“</span> 144 - <span className="text-green-600">Posted!</span> 145 - </div> 146 - ) : ( 147 - <> 148 - <textarea 149 - className="w-full border rounded p-2 mb-2 dark:bg-gray-800 dark:border-gray-700" 150 - rows={4} 151 - placeholder="What's on your mind?" 152 - value={postText} 153 - onChange={(e) => setPostText(e.target.value)} 154 - disabled={posting} 155 - autoFocus 156 - /> 157 - {postError && ( 158 - <div className="text-red-500 text-sm mb-2">{postError}</div> 159 - )} 160 - <button 161 - className="bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded disabled:opacity-50" 162 - onClick={handlePost} 163 - disabled={posting || !postText.trim()} 164 - > 165 - {posting ? "Posting..." : "Post"} 166 - </button> 167 - </> 168 - )} 169 - </div> 170 - </div> 171 - )} 129 + <Composer /> 172 130 173 131 <div className="min-h-screen flex justify-center bg-gray-50 dark:bg-gray-950"> 174 - <nav className="hidden lg:flex h-screen w-[250px] flex-col gap-2 p-4 dark:border-gray-800 sticky top-0 self-start"> 132 + <nav className="hidden lg:flex h-screen w-[250px] flex-col gap-0 p-4 dark:border-gray-800 sticky top-0 self-start"> 175 133 <div className="flex items-center gap-3 mb-4"> 176 - <img src="/redstar.png" alt="Red Dwarf Logo" className="w-8 h-8" /> 134 + <FluentEmojiHighContrastGlowingStar className="h-8 w-8" style={{color: "oklch(0.6616 0.2249 calc(25.88 + (var(--safe-hue) - 28))"}} /> 177 135 <span className="font-extrabold text-2xl tracking-tight text-gray-900 dark:text-gray-100"> 178 136 Red Dwarf{" "} 179 137 {/* <span className="text-gray-500 dark:text-gray-400 text-sm"> ··· 181 139 </span> */} 182 140 </span> 183 141 </div> 184 - <Link 142 + <MaterialNavItem 143 + InactiveIcon={ 144 + <IconMaterialSymbolsHomeOutline className="w-6 h-6" /> 145 + } 146 + ActiveIcon={<IconMaterialSymbolsHome className="w-6 h-6" />} 147 + active={locationEnum === "home"} 148 + onClickCallbback={() => 149 + navigate({ 150 + to: "/", 151 + //params: { did: agent.assertDid }, 152 + }) 153 + } 154 + text="Home" 155 + /> 156 + 157 + <MaterialNavItem 158 + InactiveIcon={<IconMaterialSymbolsSearch className="w-6 h-6" />} 159 + ActiveIcon={<IconMaterialSymbolsSearch className="w-6 h-6" />} 160 + active={locationEnum === "search"} 161 + onClickCallbback={() => 162 + navigate({ 163 + to: "/search", 164 + //params: { did: agent.assertDid }, 165 + }) 166 + } 167 + text="Explore" 168 + /> 169 + <MaterialNavItem 170 + InactiveIcon={ 171 + <IconMaterialSymbolsNotificationsOutline className="w-6 h-6" /> 172 + } 173 + ActiveIcon={ 174 + <IconMaterialSymbolsNotifications className="w-6 h-6" /> 175 + } 176 + active={locationEnum === "notifications"} 177 + onClickCallbback={() => 178 + navigate({ 179 + to: "/notifications", 180 + //params: { did: agent.assertDid }, 181 + }) 182 + } 183 + text="Notifications" 184 + /> 185 + <MaterialNavItem 186 + InactiveIcon={<IconMaterialSymbolsTag className="w-6 h-6" />} 187 + ActiveIcon={<IconMaterialSymbolsTag className="w-6 h-6" />} 188 + active={locationEnum === "feeds"} 189 + onClickCallbback={() => 190 + navigate({ 191 + to: "/feeds", 192 + //params: { did: agent.assertDid }, 193 + }) 194 + } 195 + text="Feeds" 196 + /> 197 + <MaterialNavItem 198 + InactiveIcon={ 199 + <IconMaterialSymbolsAccountCircleOutline className="w-6 h-6" /> 200 + } 201 + ActiveIcon={ 202 + <IconMaterialSymbolsAccountCircle className="w-6 h-6" /> 203 + } 204 + active={locationEnum === "profile"} 205 + onClickCallbback={() => { 206 + if (authed && agent && agent.assertDid) { 207 + //window.location.href = `/profile/${agent.assertDid}`; 208 + navigate({ 209 + to: "/profile/$did", 210 + params: { did: agent.assertDid }, 211 + }); 212 + } 213 + }} 214 + text="Profile" 215 + /> 216 + <MaterialNavItem 217 + InactiveIcon={ 218 + <IconMaterialSymbolsSettingsOutline className="w-6 h-6" /> 219 + } 220 + ActiveIcon={<IconMaterialSymbolsSettings className="w-6 h-6" />} 221 + active={locationEnum === "settings"} 222 + onClickCallbback={() => 223 + navigate({ 224 + to: "/settings", 225 + //params: { did: agent.assertDid }, 226 + }) 227 + } 228 + text="Settings" 229 + /> 230 + <div className="flex flex-row items-center justify-center mt-3"> 231 + <MaterialPillButton 232 + InactiveIcon={<IconMdiPencilOutline className="w-6 h-6" />} 233 + ActiveIcon={<IconMdiPencilOutline className="w-6 h-6" />} 234 + //active={true} 235 + onClickCallbback={() => setComposerPost({ kind: 'root' })} 236 + text="Post" 237 + /> 238 + </div> 239 + {/* <Link 185 240 to="/" 186 241 className={ 187 242 `py-2 px-4 hover:bg-gray-100 dark:hover:bg-gray-900 text-xl flex items-center gap-3 ` + 188 243 (isHome ? "font-bold" : "") 189 244 } 190 245 > 191 - {isHome ? ( 192 - <TablerHomeFilled width={28} height={28} /> 246 + {!isHome ? ( 247 + <IconMaterialSymbolsHomeOutline width={28} height={28} /> 193 248 ) : ( 194 - <TablerHome width={28} height={28} /> 249 + <IconMaterialSymbolsHome width={28} height={28} /> 195 250 )} 196 251 <span>Home</span> 197 252 </Link> ··· 202 257 (isNotifications ? "font-bold" : "") 203 258 } 204 259 > 205 - {isNotifications ? ( 206 - <TablerBellFilled width={28} height={28} /> 260 + {!isNotifications ? ( 261 + <IconMaterialSymbolsNotificationsOutline width={28} height={28} /> 207 262 ) : ( 208 - <TablerBell width={28} height={28} /> 263 + <IconMaterialSymbolsNotifications width={28} height={28} /> 209 264 )} 210 265 <span>Notifications</span> 211 266 </Link> ··· 216 271 }`} 217 272 > 218 273 {location.pathname.startsWith("/feeds") ? ( 219 - <TablerHashtagFilled width={28} height={28} /> 274 + <IconMaterialSymbolsTag width={28} height={28} /> 220 275 ) : ( 221 - <TablerHashtag width={28} height={28} /> 276 + <IconMaterialSymbolsTag width={28} height={28} /> 222 277 )} 223 278 <span>Feeds</span> 224 279 </Link> ··· 230 285 }`} 231 286 > 232 287 {location.pathname.startsWith("/search") ? ( 233 - <TablerSearchFilled width={28} height={28} /> 288 + <IconMaterialSymbolsSearch width={28} height={28} /> 234 289 ) : ( 235 - <TablerSearch width={28} height={28} /> 290 + <IconMaterialSymbolsSearch width={28} height={28} /> 236 291 )} 237 292 <span>Search</span> 238 293 </Link> ··· 242 297 }`} 243 298 onClick={() => { 244 299 if (authed && agent && agent.assertDid) { 245 - window.location.href = `/profile/${agent.assertDid}`; 300 + //window.location.href = `/profile/${agent.assertDid}`; 301 + navigate({ 302 + to: "/profile/$did", 303 + params: { did: agent.assertDid }, 304 + }); 246 305 } 247 306 }} 248 307 type="button" 249 308 > 250 - <TablerUserCircle width={28} height={28} /> 309 + {!isProfile ? ( 310 + <IconMaterialSymbolsAccountCircleOutline width={28} height={28} /> 311 + ) : ( 312 + <IconMaterialSymbolsAccountCircle width={28} height={28} /> 313 + )} 251 314 <span>Profile</span> 252 315 </button> 253 316 <Link ··· 256 319 location.pathname.startsWith("/settings") ? "font-bold" : "" 257 320 }`} 258 321 > 259 - {location.pathname.startsWith("/settings") ? ( 260 - <IonSettingsSharp width={28} height={28} /> 322 + {!location.pathname.startsWith("/settings") ? ( 323 + <IconMaterialSymbolsSettingsOutline width={28} height={28} /> 261 324 ) : ( 262 - <IonSettings width={28} height={28} /> 325 + <IconMaterialSymbolsSettings width={28} height={28} /> 263 326 )} 264 327 <span>Settings</span> 265 - </Link> 266 - <button 328 + </Link> */} 329 + {/* <button 267 330 className="mt-4 w-full flex items-center justify-center gap-3 py-3 px-0 mb-3 bg-gray-200 dark:bg-gray-800 hover:bg-gray-300 dark:hover:bg-gray-700 text-gray-900 dark:text-gray-100 text-xl font-bold rounded-full transition-colors shadow" 268 331 onClick={() => setPostOpen(true)} 269 332 type="button" 270 333 > 271 - <TablerEdit 334 + <IconMdiPencilOutline 272 335 width={24} 273 336 height={24} 274 337 className="text-gray-600 dark:text-gray-400" 275 338 /> 276 339 <span>Post</span> 277 - </button> 340 + </button> */} 278 341 <div className="flex-1"></div> 279 342 <a 280 343 href="https://tangled.sh/@whey.party/red-dwarf" ··· 305 368 </div> 306 369 </nav> 307 370 308 - <button 309 - className="lg:hidden fixed bottom-20 right-6 z-50 bg-gray-200 dark:bg-gray-800 hover:bg-gray-300 dark:hover:bg-gray-700 text-blue-600 dark:text-blue-400 rounded-full shadow-lg w-16 h-16 flex items-center justify-center border-4 border-white dark:border-gray-950 transition-all" 310 - style={{ boxShadow: "0 4px 24px 0 rgba(0,0,0,0.12)" }} 311 - onClick={() => setPostOpen(true)} 312 - type="button" 313 - aria-label="Create Post" 314 - > 315 - <TablerEdit 316 - width={24} 317 - height={24} 318 - className="text-gray-600 dark:text-gray-400" 371 + <nav className="hidden sm:flex items-center lg:hidden h-screen flex-col gap-2 p-4 dark:border-gray-800 sticky top-0 self-start"> 372 + <div className="flex items-center gap-3 mb-4"> 373 + <FluentEmojiHighContrastGlowingStar className="h-8 w-8" style={{color: "oklch(0.6616 0.2249 calc(25.88 + (var(--safe-hue) - 28))"}} /> 374 + </div> 375 + <MaterialNavItem 376 + small 377 + InactiveIcon={ 378 + <IconMaterialSymbolsHomeOutline className="w-6 h-6" /> 379 + } 380 + ActiveIcon={<IconMaterialSymbolsHome className="w-6 h-6" />} 381 + active={locationEnum === "home"} 382 + onClickCallbback={() => 383 + navigate({ 384 + to: "/", 385 + //params: { did: agent.assertDid }, 386 + }) 387 + } 388 + text="Home" 319 389 /> 320 - </button> 321 390 322 - <main className="w-full max-w-[600px] lg:border-x border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-950 pb-16 lg:pb-0"> 323 - <div className="lg:hidden flex items-center justify-between px-4 py-3 border-b border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-950"> 324 - <div className="flex items-center gap-2"> 325 - <img 326 - src="/redstar.png" 327 - alt="Red Dwarf Logo" 328 - className="w-6 h-6" 329 - /> 330 - <span className="font-bold text-lg text-gray-900 dark:text-gray-100"> 331 - Red Dwarf{" "} 332 - {/* <span className="text-gray-500 dark:text-gray-400 text-sm"> 333 - lite 334 - </span> */} 335 - </span> 336 - </div> 337 - <div className="flex items-center gap-2"> 338 - <Login compact={true} /> 339 - </div> 391 + <MaterialNavItem 392 + small 393 + InactiveIcon={<IconMaterialSymbolsSearch className="w-6 h-6" />} 394 + ActiveIcon={<IconMaterialSymbolsSearch className="w-6 h-6" />} 395 + active={locationEnum === "search"} 396 + onClickCallbback={() => 397 + navigate({ 398 + to: "/search", 399 + //params: { did: agent.assertDid }, 400 + }) 401 + } 402 + text="Explore" 403 + /> 404 + <MaterialNavItem 405 + small 406 + InactiveIcon={ 407 + <IconMaterialSymbolsNotificationsOutline className="w-6 h-6" /> 408 + } 409 + ActiveIcon={ 410 + <IconMaterialSymbolsNotifications className="w-6 h-6" /> 411 + } 412 + active={locationEnum === "notifications"} 413 + onClickCallbback={() => 414 + navigate({ 415 + to: "/notifications", 416 + //params: { did: agent.assertDid }, 417 + }) 418 + } 419 + text="Notifications" 420 + /> 421 + <MaterialNavItem 422 + small 423 + InactiveIcon={<IconMaterialSymbolsTag className="w-6 h-6" />} 424 + ActiveIcon={<IconMaterialSymbolsTag className="w-6 h-6" />} 425 + active={locationEnum === "feeds"} 426 + onClickCallbback={() => 427 + navigate({ 428 + to: "/feeds", 429 + //params: { did: agent.assertDid }, 430 + }) 431 + } 432 + text="Feeds" 433 + /> 434 + <MaterialNavItem 435 + small 436 + InactiveIcon={ 437 + <IconMaterialSymbolsAccountCircleOutline className="w-6 h-6" /> 438 + } 439 + ActiveIcon={ 440 + <IconMaterialSymbolsAccountCircle className="w-6 h-6" /> 441 + } 442 + active={locationEnum === "profile"} 443 + onClickCallbback={() => { 444 + if (authed && agent && agent.assertDid) { 445 + //window.location.href = `/profile/${agent.assertDid}`; 446 + navigate({ 447 + to: "/profile/$did", 448 + params: { did: agent.assertDid }, 449 + }); 450 + } 451 + }} 452 + text="Profile" 453 + /> 454 + <MaterialNavItem 455 + small 456 + InactiveIcon={ 457 + <IconMaterialSymbolsSettingsOutline className="w-6 h-6" /> 458 + } 459 + ActiveIcon={<IconMaterialSymbolsSettings className="w-6 h-6" />} 460 + active={locationEnum === "settings"} 461 + onClickCallbback={() => 462 + navigate({ 463 + to: "/settings", 464 + //params: { did: agent.assertDid }, 465 + }) 466 + } 467 + text="Settings" 468 + /> 469 + <div className="flex flex-row items-center justify-center mt-3"> 470 + <MaterialPillButton 471 + small 472 + InactiveIcon={<IconMdiPencilOutline className="w-6 h-6" />} 473 + ActiveIcon={<IconMdiPencilOutline className="w-6 h-6" />} 474 + //active={true} 475 + onClickCallbback={() => setComposerPost({ kind: 'root' })} 476 + text="Post" 477 + /> 340 478 </div> 479 + </nav> 341 480 481 + {agent?.did && ( 482 + <button 483 + className="lg:hidden fixed bottom-22 right-4 z-50 bg-gray-200 dark:bg-gray-800 hover:bg-gray-300 dark:hover:bg-gray-700 rounded-2xl w-14 h-14 flex items-center justify-center transition-all" 484 + style={{ boxShadow: "0 4px 24px 0 rgba(0,0,0,0.12)" }} 485 + onClick={() => setComposerPost({ kind: 'root' })} 486 + type="button" 487 + aria-label="Create Post" 488 + > 489 + <IconMdiPencilOutline 490 + width={24} 491 + height={24} 492 + className="text-gray-600 dark:text-gray-400" 493 + /> 494 + </button> 495 + )} 496 + 497 + <main className="w-full max-w-[600px] sm:border-x border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-950 pb-16 lg:pb-0 overflow-x-clip"> 342 498 {children} 343 499 </main> 344 500 345 501 <aside className="hidden lg:flex h-screen w-[250px] sticky top-0 self-start flex-col"> 502 + <div className="px-4 pt-4"><Import /></div> 346 503 <Login /> 347 504 348 505 <div className="flex-1"></div> 349 506 <p className="text-xs text-gray-400 dark:text-gray-500 text-justify mx-4 mb-4"> 350 - Red Dwarf is a bluesky client that uses Constellation and 351 - direct PDS queries. Skylite would be a 352 - self-hosted bluesky "instance". Stay tuned for the release of Skylite. 507 + Red Dwarf is a Bluesky client that does not rely on any Bluesky API App Servers. Instead, it uses Microcosm to fetch records directly from each users' PDS (via Slingshot) and connect them using backlinks (via Constellation) 353 508 </p> 354 509 </aside> 355 510 </div> 356 511 357 - <nav className="lg:hidden fixed bottom-0 left-0 right-0 bg-white dark:bg-gray-950 border-t border-gray-200 dark:border-gray-700 z-40"> 358 - <div className="flex justify-around items-center py-2"> 359 - <Link 360 - to="/" 361 - className={`flex flex-col items-center py-2 px-3 rounded-lg transition-colors flex-1 ${ 362 - isHome 363 - ? "text-gray-900 dark:text-gray-100" 364 - : "text-gray-600 dark:text-gray-400" 365 - }`} 366 - > 367 - {isHome ? ( 368 - <TablerHomeFilled width={24} height={24} /> 369 - ) : ( 370 - <TablerHome width={24} height={24} /> 371 - )} 372 - <span className="text-xs mt-1">Home</span> 373 - </Link> 374 - <Link 375 - to="/search" 376 - className={`flex flex-col items-center py-2 px-3 rounded-lg transition-colors flex-1 ${ 377 - location.pathname.startsWith("/search") 378 - ? "text-gray-900 dark:text-gray-100" 379 - : "text-gray-600 dark:text-gray-400" 380 - }`} 381 - > 382 - {location.pathname.startsWith("/search") ? ( 383 - <TablerSearchFilled width={24} height={24} /> 384 - ) : ( 385 - <TablerSearch width={24} height={24} /> 386 - )} 387 - <span className="text-xs mt-1">Search</span> 388 - </Link> 389 - <Link 390 - to="/notifications" 391 - className={`flex flex-col items-center py-2 px-3 rounded-lg transition-colors flex-1 ${ 392 - isNotifications 393 - ? "text-gray-900 dark:text-gray-100" 394 - : "text-gray-600 dark:text-gray-400" 395 - }`} 396 - > 397 - {isNotifications ? ( 398 - <TablerBellFilled width={24} height={24} /> 399 - ) : ( 400 - <TablerBell width={24} height={24} /> 401 - )} 402 - <span className="text-xs mt-1">Notifications</span> 403 - </Link> 404 - <button 405 - className={`flex flex-col items-center py-2 px-3 rounded-lg transition-colors flex-1 ${ 406 - isProfile 407 - ? "text-gray-900 dark:text-gray-100" 408 - : "text-gray-600 dark:text-gray-400" 409 - }`} 410 - onClick={() => { 411 - if (authed && agent && agent.assertDid) { 412 - window.location.href = `/profile/${agent.assertDid}`; 512 + {agent?.did ? ( 513 + <nav className="sm:hidden fixed bottom-0 left-0 right-0 bg-gray-50 dark:bg-gray-900 border-0 shadow border-gray-200 dark:border-gray-700 z-40"> 514 + <div className="flex justify-around items-center p-2"> 515 + <MaterialNavItem 516 + small 517 + InactiveIcon={ 518 + <IconMaterialSymbolsHomeOutline className="w-6 h-6" /> 519 + } 520 + ActiveIcon={<IconMaterialSymbolsHome className="w-6 h-6" />} 521 + active={locationEnum === "home"} 522 + onClickCallbback={() => 523 + navigate({ 524 + to: "/", 525 + //params: { did: agent.assertDid }, 526 + }) 527 + } 528 + text="Home" 529 + /> 530 + {/* <Link 531 + to="/" 532 + className={`flex flex-col items-center py-2 px-3 rounded-lg transition-colors flex-1 ${ 533 + isHome 534 + ? "text-gray-900 dark:text-gray-100" 535 + : "text-gray-600 dark:text-gray-400" 536 + }`} 537 + > 538 + {!isHome ? ( 539 + <IconMaterialSymbolsHomeOutline width={24} height={24} /> 540 + ) : ( 541 + <IconMaterialSymbolsHome width={24} height={24} /> 542 + )} 543 + <span className="text-xs mt-1">Home</span> 544 + </Link> */} 545 + <MaterialNavItem 546 + small 547 + InactiveIcon={<IconMaterialSymbolsSearch className="w-6 h-6" />} 548 + ActiveIcon={<IconMaterialSymbolsSearch className="w-6 h-6" />} 549 + active={locationEnum === "search"} 550 + onClickCallbback={() => 551 + navigate({ 552 + to: "/search", 553 + //params: { did: agent.assertDid }, 554 + }) 555 + } 556 + text="Explore" 557 + /> 558 + {/* <Link 559 + to="/search" 560 + className={`flex flex-col items-center py-2 px-3 rounded-lg transition-colors flex-1 ${ 561 + location.pathname.startsWith("/search") 562 + ? "text-gray-900 dark:text-gray-100" 563 + : "text-gray-600 dark:text-gray-400" 564 + }`} 565 + > 566 + {!location.pathname.startsWith("/search") ? ( 567 + <IconMaterialSymbolsSearch width={24} height={24} /> 568 + ) : ( 569 + <IconMaterialSymbolsSearch width={24} height={24} /> 570 + )} 571 + <span className="text-xs mt-1">Search</span> 572 + </Link> */} 573 + <MaterialNavItem 574 + small 575 + InactiveIcon={ 576 + <IconMaterialSymbolsNotificationsOutline className="w-6 h-6" /> 577 + } 578 + ActiveIcon={ 579 + <IconMaterialSymbolsNotifications className="w-6 h-6" /> 580 + } 581 + active={locationEnum === "notifications"} 582 + onClickCallbback={() => 583 + navigate({ 584 + to: "/notifications", 585 + //params: { did: agent.assertDid }, 586 + }) 587 + } 588 + text="Notifications" 589 + /> 590 + {/* <Link 591 + to="/notifications" 592 + className={`flex flex-col items-center py-2 px-3 rounded-lg transition-colors flex-1 ${ 593 + isNotifications 594 + ? "text-gray-900 dark:text-gray-100" 595 + : "text-gray-600 dark:text-gray-400" 596 + }`} 597 + > 598 + {!isNotifications ? ( 599 + <IconMaterialSymbolsNotificationsOutline 600 + width={24} 601 + height={24} 602 + /> 603 + ) : ( 604 + <IconMaterialSymbolsNotifications width={24} height={24} /> 605 + )} 606 + <span className="text-xs mt-1">Notifications</span> 607 + </Link> */} 608 + <MaterialNavItem 609 + small 610 + InactiveIcon={ 611 + <IconMaterialSymbolsAccountCircleOutline className="w-6 h-6" /> 612 + } 613 + ActiveIcon={ 614 + <IconMaterialSymbolsAccountCircle className="w-6 h-6" /> 615 + } 616 + active={locationEnum === "profile"} 617 + onClickCallbback={() => { 618 + if (authed && agent && agent.assertDid) { 619 + //window.location.href = `/profile/${agent.assertDid}`; 620 + navigate({ 621 + to: "/profile/$did", 622 + params: { did: agent.assertDid }, 623 + }); 624 + } 625 + }} 626 + text="Profile" 627 + /> 628 + {/* <button 629 + className={`flex flex-col items-center py-2 px-3 rounded-lg transition-colors flex-1 ${ 630 + isProfile 631 + ? "text-gray-900 dark:text-gray-100" 632 + : "text-gray-600 dark:text-gray-400" 633 + }`} 634 + onClick={() => { 635 + if (authed && agent && agent.assertDid) { 636 + //window.location.href = `/profile/${agent.assertDid}`; 637 + navigate({ 638 + to: "/profile/$did", 639 + params: { did: agent.assertDid }, 640 + }); 641 + } 642 + }} 643 + type="button" 644 + > 645 + <IconMaterialSymbolsAccountCircleOutline width={24} height={24} /> 646 + <span className="text-xs mt-1">Profile</span> 647 + </button> */} 648 + <MaterialNavItem 649 + small 650 + InactiveIcon={ 651 + <IconMaterialSymbolsSettingsOutline className="w-6 h-6" /> 652 + } 653 + ActiveIcon={<IconMaterialSymbolsSettings className="w-6 h-6" />} 654 + active={locationEnum === "settings"} 655 + onClickCallbback={() => 656 + navigate({ 657 + to: "/settings", 658 + //params: { did: agent.assertDid }, 659 + }) 413 660 } 414 - }} 415 - type="button" 416 - > 417 - <TablerUserCircle width={24} height={24} /> 418 - <span className="text-xs mt-1">Profile</span> 419 - </button> 420 - <Link 421 - to="/settings" 422 - className={`flex flex-col items-center py-2 px-3 rounded-lg transition-colors flex-1 ${ 423 - location.pathname.startsWith("/settings") 424 - ? "text-gray-900 dark:text-gray-100" 425 - : "text-gray-600 dark:text-gray-400" 426 - }`} 427 - > 428 - {location.pathname.startsWith("/settings") ? ( 429 - <IonSettingsSharp width={24} height={24} /> 430 - ) : ( 431 - <IonSettings width={24} height={24} /> 432 - )} 433 - <span className="text-xs mt-1">Settings</span> 434 - </Link> 661 + text="Settings" 662 + /> 663 + {/* <Link 664 + to="/settings" 665 + className={`flex flex-col items-center py-2 px-3 rounded-lg transition-colors flex-1 ${ 666 + location.pathname.startsWith("/settings") 667 + ? "text-gray-900 dark:text-gray-100" 668 + : "text-gray-600 dark:text-gray-400" 669 + }`} 670 + > 671 + {!location.pathname.startsWith("/settings") ? ( 672 + <IconMaterialSymbolsSettingsOutline width={24} height={24} /> 673 + ) : ( 674 + <IconMaterialSymbolsSettings width={24} height={24} /> 675 + )} 676 + <span className="text-xs mt-1">Settings</span> 677 + </Link> */} 678 + </div> 679 + </nav> 680 + ) : ( 681 + <div className="lg:hidden flex items-center fixed bottom-0 left-0 right-0 justify-between px-4 py-3 border-0 shadow border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-900 z-10"> 682 + <div className="flex items-center gap-2"> 683 + <FluentEmojiHighContrastGlowingStar className="h-6 w-6" style={{color: "oklch(0.6616 0.2249 calc(25.88 + (var(--safe-hue) - 28))"}} /> 684 + <span className="font-bold text-lg text-gray-900 dark:text-gray-100"> 685 + Red Dwarf{" "} 686 + {/* <span className="text-gray-500 dark:text-gray-400 text-sm"> 687 + lite 688 + </span> */} 689 + </span> 690 + </div> 691 + <div className="flex items-center gap-2"> 692 + <Login compact={true} popup={true} /> 693 + </div> 435 694 </div> 436 - </nav> 695 + )} 437 696 438 - <TanStackRouterDevtools position="bottom-right" /> 697 + <TanStackRouterDevtools position="bottom-left" /> 439 698 <Scripts /> 440 699 </> 441 700 ); 442 701 } 443 - export function TablerHashtag(props: SVGProps<SVGSVGElement>) { 444 - return ( 445 - <svg 446 - xmlns="http://www.w3.org/2000/svg" 447 - width={24} 448 - height={24} 449 - viewBox="0 0 24 24" 450 - {...props} 451 - > 452 - <path 453 - fill="none" 454 - stroke="currentColor" 455 - strokeLinecap="round" 456 - strokeLinejoin="round" 457 - strokeWidth={2} 458 - d="M5 9h14M5 15h14M11 4L7 20M17 4l-4 16" 459 - ></path> 460 - </svg> 461 - ); 462 - } 463 702 464 - export function TablerHashtagFilled(props: SVGProps<SVGSVGElement>) { 465 - return ( 466 - <svg 467 - xmlns="http://www.w3.org/2000/svg" 468 - width={24} 469 - height={24} 470 - viewBox="0 0 24 24" 471 - {...props} 472 - > 473 - <path 474 - fill="none" 475 - stroke="currentColor" 476 - strokeLinecap="round" 477 - strokeLinejoin="round" 478 - strokeWidth={3} 479 - d="M5 9h14M5 15h14M11 4L7 20M17 4l-4 16" 480 - ></path> 481 - </svg> 482 - ); 483 - } 484 - export function TablerEdit(props: SVGProps<SVGSVGElement>) { 485 - return ( 486 - <svg 487 - xmlns="http://www.w3.org/2000/svg" 488 - width={24} 489 - height={24} 490 - viewBox="0 0 24 24" 491 - className="text-white" 492 - {...props} 493 - > 494 - <g 495 - fill="none" 496 - stroke="currentColor" 497 - strokeLinecap="round" 498 - strokeLinejoin="round" 499 - strokeWidth={2} 703 + function MaterialNavItem({ 704 + InactiveIcon, 705 + ActiveIcon, 706 + text, 707 + active, 708 + onClickCallbback, 709 + small, 710 + }: { 711 + InactiveIcon: React.ReactElement; 712 + ActiveIcon: React.ReactElement; 713 + text: string; 714 + active: boolean; 715 + onClickCallbback: () => void; 716 + small?: boolean | string; 717 + }) { 718 + if (small) 719 + return ( 720 + <button 721 + className={`flex flex-col items-center rounded-lg transition-colors ${small} gap-1 ${ 722 + active 723 + ? "text-gray-900 dark:text-gray-100" 724 + : "text-gray-600 dark:text-gray-400" 725 + }`} 726 + onClick={() => { 727 + onClickCallbback(); 728 + }} 500 729 > 501 - <path d="M16.475 5.408a2.36 2.36 0 1 1 3.34 3.34L7.5 21H3v-4.5z"></path> 502 - </g> 503 - </svg> 504 - ); 505 - } 506 - export function TablerHome(props: SVGProps<SVGSVGElement>) { 507 - return ( 508 - <svg 509 - xmlns="http://www.w3.org/2000/svg" 510 - width={24} 511 - height={24} 512 - viewBox="0 0 24 24" 513 - className="text-gray-900 dark:text-gray-100 hover:text-gray-700 dark:hover:text-gray-300 transition-colors" 514 - {...props} 515 - > 516 - <g 517 - stroke="currentColor" 518 - strokeLinecap="round" 519 - strokeLinejoin="round" 520 - strokeWidth={2} 521 - fill="none" 522 - > 523 - <path d="M5 12H3l9-9l9 9h-2M5 12v7a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-7"></path> 524 - <path d="M9 21v-6a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v6"></path> 525 - </g> 526 - </svg> 527 - ); 528 - } 529 - export function TablerHomeFilled(props: SVGProps<SVGSVGElement>) { 530 - return ( 531 - <svg 532 - xmlns="http://www.w3.org/2000/svg" 533 - width={24} 534 - height={24} 535 - viewBox="0 0 24 24" 536 - className="text-gray-900 dark:text-gray-100 hover:text-gray-700 dark:hover:text-gray-300 transition-colors" 537 - {...props} 538 - > 539 - <path 540 - fill="currentColor" 541 - d="m12.707 2.293l9 9c.63.63.184 1.707-.707 1.707h-1v6a3 3 0 0 1-3 3h-1v-7a3 3 0 0 0-2.824-2.995L13 12h-2a3 3 0 0 0-3 3v7H7a3 3 0 0 1-3-3v-6H3c-.89 0-1.337-1.077-.707-1.707l9-9a1 1 0 0 1 1.414 0M13 14a1 1 0 0 1 1 1v7h-4v-7a1 1 0 0 1 .883-.993L11 14z" 542 - ></path> 543 - </svg> 544 - ); 545 - } 546 - 547 - export function TablerBell(props: SVGProps<SVGSVGElement>) { 548 - return ( 549 - <svg 550 - xmlns="http://www.w3.org/2000/svg" 551 - width={24} 552 - height={24} 553 - viewBox="0 0 24 24" 554 - {...props} 555 - > 556 - <path 557 - className="text-gray-900 dark:text-gray-100 hover:text-gray-700 dark:hover:text-gray-300 transition-colors" 558 - stroke="currentColor" 559 - strokeLinecap="round" 560 - strokeLinejoin="round" 561 - strokeWidth={2} 562 - d="M10 5a2 2 0 1 1 4 0a7 7 0 0 1 4 6v3a4 4 0 0 0 2 3H4a4 4 0 0 0 2-3v-3a7 7 0 0 1 4-6M9 17v1a3 3 0 0 0 6 0v-1" 563 - ></path> 564 - </svg> 565 - ); 566 - } 567 - export function TablerBellFilled(props: SVGProps<SVGSVGElement>) { 568 - return ( 569 - <svg 570 - xmlns="http://www.w3.org/2000/svg" 571 - width={24} 572 - height={24} 573 - viewBox="0 0 24 24" 574 - className="text-gray-900 dark:text-gray-100 hover:text-gray-700 dark:hover:text-gray-300 transition-colors" 575 - {...props} 576 - > 577 - <path 578 - fill="currentColor" 579 - stroke="currentColor" 580 - d="M14.235 19c.865 0 1.322 1.024.745 1.668A4 4 0 0 1 12 22a4 4 0 0 1-2.98-1.332c-.552-.616-.158-1.579.634-1.661l.11-.006zM12 2c1.358 0 2.506.903 2.875 2.141l.046.171l.008.043a8.01 8.01 0 0 1 4.024 6.069l.028.287L19 11v2.931l.021.136a3 3 0 0 0 1.143 1.847l.167.117l.162.099c.86.487.56 1.766-.377 1.864L20 18H4c-1.028 0-1.387-1.364-.493-1.87a3 3 0 0 0 1.472-2.063L5 13.924l.001-2.97A8 8 0 0 1 8.822 4.5l.248-.146l.01-.043a3 3 0 0 1 2.562-2.29l.182-.017z" 581 - ></path> 582 - </svg> 583 - ); 584 - } 585 - 586 - export function TablerUserCircle(props: SVGProps<SVGSVGElement>) { 587 - return ( 588 - <svg 589 - xmlns="http://www.w3.org/2000/svg" 590 - width={24} 591 - height={24} 592 - viewBox="0 0 24 24" 593 - className="text-gray-900 dark:text-gray-100 hover:text-gray-700 dark:hover:text-gray-300 transition-colors" 594 - {...props} 595 - > 596 - <g 597 - fill="none" 598 - stroke="currentColor" 599 - strokeLinecap="round" 600 - strokeLinejoin="round" 601 - strokeWidth={2} 602 - > 603 - <path d="M3 12a9 9 0 1 0 18 0a9 9 0 1 0-18 0"></path> 604 - <path d="M9 10a3 3 0 1 0 6 0a3 3 0 1 0-6 0m-2.832 8.849A4 4 0 0 1 10 16h4a4 4 0 0 1 3.834 2.855"></path> 605 - </g> 606 - </svg> 607 - ); 608 - } 730 + <div 731 + className={`px-4 py-1 rounded-full flex items-center justify-center ${active ? " bg-gray-100 dark:bg-gray-800 hover:bg-gray-200 hover:dark:bg-gray-700" : "hover:bg-gray-50 hover:dark:bg-gray-900"}`} 732 + > 733 + {active ? ActiveIcon : InactiveIcon} 734 + </div> 735 + <span 736 + className={`text-[12.8px] text-roboto ${active ? "font-medium" : ""}`} 737 + > 738 + {text} 739 + </span> 740 + </button> 741 + ); 609 742 610 - export function TablerSearch(props: SVGProps<SVGSVGElement>) { 611 743 return ( 612 - <svg 613 - xmlns="http://www.w3.org/2000/svg" 614 - width={24} 615 - height={24} 616 - viewBox="0 0 24 24" 617 - //className="text-gray-400 dark:text-gray-500" 618 - {...props} 619 - > 620 - <g 621 - fill="none" 622 - stroke="currentColor" 623 - strokeLinecap="round" 624 - strokeLinejoin="round" 625 - strokeWidth={2} 626 - > 627 - <path d="M3 10a7 7 0 1 0 14 0a7 7 0 1 0-14 0"></path> 628 - <path d="m21 21l-6-6"></path> 629 - </g> 630 - </svg> 631 - ); 632 - } 633 - export function TablerSearchFilled(props: SVGProps<SVGSVGElement>) { 634 - return ( 635 - <svg 636 - xmlns="http://www.w3.org/2000/svg" 637 - width={24} 638 - height={24} 639 - viewBox="0 0 24 24" 640 - //className="text-gray-400 dark:text-gray-500" 641 - {...props} 744 + <button 745 + className={`flex flex-row h-12 min-h-12 max-h-12 px-4 py-0.5 w-full items-center rounded-full transition-colors flex-1 gap-1 ${ 746 + active 747 + ? "text-gray-900 dark:text-gray-100 hover:bg-gray-300 dark:bg-gray-800 bg-gray-200 hover:dark:bg-gray-700" 748 + : "text-gray-600 dark:text-gray-400 hover:bg-gray-100 hover:dark:bg-gray-900" 749 + }`} 750 + onClick={() => { 751 + onClickCallbback(); 752 + }} 642 753 > 643 - <g 644 - fill="none" 645 - stroke="currentColor" 646 - strokeLinecap="round" 647 - strokeLinejoin="round" 648 - strokeWidth={3} 754 + <div className={`mr-4 ${active ? " " : " "}`}> 755 + {active ? ActiveIcon : InactiveIcon} 756 + </div> 757 + <span 758 + className={`text-[17px] text-roboto ${active ? "font-medium" : ""}`} 649 759 > 650 - <path d="M3 10a7 7 0 1 0 14 0a7 7 0 1 0-14 0"></path> 651 - <path d="m21 21l-6-6"></path> 652 - </g> 653 - </svg> 760 + {text} 761 + </span> 762 + </button> 654 763 ); 655 764 } 656 765 657 - export function IonSettings(props: SVGProps<SVGSVGElement>) { 658 - return ( 659 - <svg 660 - xmlns="http://www.w3.org/2000/svg" 661 - width={24} 662 - height={24} 663 - viewBox="0 0 512 512" 664 - {...props} 665 - > 666 - <path 667 - fill="none" 668 - stroke="currentColor" 669 - strokeLinecap="round" 670 - strokeLinejoin="round" 671 - strokeWidth={32} 672 - d="M262.29 192.31a64 64 0 1 0 57.4 57.4a64.13 64.13 0 0 0-57.4-57.4M416.39 256a154 154 0 0 1-1.53 20.79l45.21 35.46a10.81 10.81 0 0 1 2.45 13.75l-42.77 74a10.81 10.81 0 0 1-13.14 4.59l-44.9-18.08a16.11 16.11 0 0 0-15.17 1.75A164.5 164.5 0 0 1 325 400.8a15.94 15.94 0 0 0-8.82 12.14l-6.73 47.89a11.08 11.08 0 0 1-10.68 9.17h-85.54a11.11 11.11 0 0 1-10.69-8.87l-6.72-47.82a16.07 16.07 0 0 0-9-12.22a155 155 0 0 1-21.46-12.57a16 16 0 0 0-15.11-1.71l-44.89 18.07a10.81 10.81 0 0 1-13.14-4.58l-42.77-74a10.8 10.8 0 0 1 2.45-13.75l38.21-30a16.05 16.05 0 0 0 6-14.08c-.36-4.17-.58-8.33-.58-12.5s.21-8.27.58-12.35a16 16 0 0 0-6.07-13.94l-38.19-30A10.81 10.81 0 0 1 49.48 186l42.77-74a10.81 10.81 0 0 1 13.14-4.59l44.9 18.08a16.11 16.11 0 0 0 15.17-1.75A164.5 164.5 0 0 1 187 111.2a15.94 15.94 0 0 0 8.82-12.14l6.73-47.89A11.08 11.08 0 0 1 213.23 42h85.54a11.11 11.11 0 0 1 10.69 8.87l6.72 47.82a16.07 16.07 0 0 0 9 12.22a155 155 0 0 1 21.46 12.57a16 16 0 0 0 15.11 1.71l44.89-18.07a10.81 10.81 0 0 1 13.14 4.58l42.77 74a10.8 10.8 0 0 1-2.45 13.75l-38.21 30a16.05 16.05 0 0 0-6.05 14.08c.33 4.14.55 8.3.55 12.47" 673 - ></path> 674 - </svg> 675 - ); 676 - } 677 - export function IonSettingsSharp(props: SVGProps<SVGSVGElement>) { 766 + function MaterialPillButton({ 767 + InactiveIcon, 768 + ActiveIcon, 769 + text, 770 + //active, 771 + onClickCallbback, 772 + small, 773 + }: { 774 + InactiveIcon: React.ReactElement; 775 + ActiveIcon: React.ReactElement; 776 + text: string; 777 + //active: boolean; 778 + onClickCallbback: () => void; 779 + small?: boolean | string; 780 + }) { 781 + const active = false; 678 782 return ( 679 - <svg 680 - xmlns="http://www.w3.org/2000/svg" 681 - width={24} 682 - height={24} 683 - viewBox="0 0 512 512" 684 - {...props} 783 + <button 784 + className={`flex border border-gray-400 dark:border-gray-400 flex-row h-12 min-h-12 max-h-12 ${small ? "p-3 w-12" : "px-4 py-0.5"} items-center rounded-full transition-colors gap-1 ${ 785 + active 786 + ? "text-gray-900 dark:text-gray-100 hover:bg-gray-300 dark:bg-gray-700 bg-gray-200 hover:dark:bg-gray-600" 787 + : "text-gray-600 dark:text-gray-400 hover:bg-gray-100 hover:dark:bg-gray-800" 788 + }`} 789 + onClick={() => { 790 + onClickCallbback(); 791 + }} 685 792 > 686 - <path 687 - fill="currentColor" 688 - d="M256 176a80 80 0 1 0 80 80a80.24 80.24 0 0 0-80-80m172.72 80a165.5 165.5 0 0 1-1.64 22.34l48.69 38.12a11.59 11.59 0 0 1 2.63 14.78l-46.06 79.52a11.64 11.64 0 0 1-14.14 4.93l-57.25-23a176.6 176.6 0 0 1-38.82 22.67l-8.56 60.78a11.93 11.93 0 0 1-11.51 9.86h-92.12a12 12 0 0 1-11.51-9.53l-8.56-60.78A169.3 169.3 0 0 1 151.05 393L93.8 416a11.64 11.64 0 0 1-14.14-4.92L33.6 331.57a11.59 11.59 0 0 1 2.63-14.78l48.69-38.12A175 175 0 0 1 83.28 256a165.5 165.5 0 0 1 1.64-22.34l-48.69-38.12a11.59 11.59 0 0 1-2.63-14.78l46.06-79.52a11.64 11.64 0 0 1 14.14-4.93l57.25 23a176.6 176.6 0 0 1 38.82-22.67l8.56-60.78A11.93 11.93 0 0 1 209.94 26h92.12a12 12 0 0 1 11.51 9.53l8.56 60.78A169.3 169.3 0 0 1 361 119l57.2-23a11.64 11.64 0 0 1 14.14 4.92l46.06 79.52a11.59 11.59 0 0 1-2.63 14.78l-48.69 38.12a175 175 0 0 1 1.64 22.66" 689 - ></path> 690 - </svg> 793 + <div className={`${!small && "mr-2"} ${active ? " " : " "}`}> 794 + {active ? ActiveIcon : InactiveIcon} 795 + </div> 796 + {!small && ( 797 + <span 798 + className={`text-[17px] text-roboto ${active ? "font-medium" : ""}`} 799 + > 800 + {text} 801 + </span> 802 + )} 803 + </button> 691 804 ); 692 805 }
+13
src/routes/callback/index.tsx
··· 1 + import { createFileRoute, useNavigate } from '@tanstack/react-router' 2 + 3 + export const Route = createFileRoute('/callback/')({ 4 + component: RouteComponent, 5 + }) 6 + 7 + function RouteComponent() { 8 + const navigate = useNavigate() 9 + const redirectPath = sessionStorage.getItem('postLoginRedirect') || '/'; 10 + navigate({to:redirectPath}) 11 + sessionStorage.removeItem('postLoginRedirect'); 12 + return <div>Hello "/callback/"!</div> 13 + }
+449 -223
src/routes/index.tsx
··· 1 1 import { createFileRoute } from "@tanstack/react-router"; 2 - import { 3 - CACHE_TIMEOUT, 4 - cachedGetRecord, 5 - cachedResolveIdentity, 6 - UniversalPostRendererATURILoader, 7 - } from "~/components/UniversalPostRenderer"; 2 + import { useAtom } from "jotai"; 8 3 import * as React from "react"; 9 - import { useAuth } from "~/providers/PassAuthProvider"; 10 - import { usePersistentStore } from "~/providers/PersistentStoreProvider"; 4 + import { useLayoutEffect, useState } from "react"; 5 + 6 + import { Header } from "~/components/Header"; 7 + import { InfiniteCustomFeed } from "~/components/InfiniteCustomFeed"; 8 + import { useAuth } from "~/providers/UnifiedAuthProvider"; 9 + import { 10 + feedScrollPositionsAtom, 11 + isAtTopAtom, 12 + quickAuthAtom, 13 + selectedFeedUriAtom, 14 + } from "~/utils/atoms"; 15 + //import { usePersistentStore } from "~/providers/PersistentStoreProvider"; 16 + import { 17 + //constructArbitraryQuery, 18 + //constructIdentityQuery, 19 + //constructInfiniteFeedSkeletonQuery, 20 + //constructPostQuery, 21 + useQueryArbitrary, 22 + useQueryIdentity, 23 + useQueryPreferences, 24 + } from "~/utils/useQuery"; 11 25 12 26 export const Route = createFileRoute("/")({ 27 + // loader: async ({ context }) => { 28 + // const { queryClient } = context; 29 + // const atomauth = store.get(authedAtom); 30 + // const atomagent = store.get(agentAtom); 31 + 32 + // let identitypds: string | undefined; 33 + // const initialselectedfeed = store.get(selectedFeedUriAtom); 34 + // if (atomagent && atomauth && atomagent?.did) { 35 + // const identityopts = constructIdentityQuery(atomagent.did); 36 + // const identityresultmaybe = 37 + // await queryClient.ensureQueryData(identityopts); 38 + // identitypds = identityresultmaybe?.pds; 39 + // } 40 + 41 + // const arbitraryopts = constructArbitraryQuery( 42 + // initialselectedfeed ?? 43 + // "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot" 44 + // ); 45 + // const feedGengetrecordquery = 46 + // await queryClient.ensureQueryData(arbitraryopts); 47 + // const feedServiceDid = (feedGengetrecordquery?.value as any)?.did; 48 + // //queryClient.ensureInfiniteQueryData() 49 + 50 + // const { queryKey, queryFn } = constructInfiniteFeedSkeletonQuery({ 51 + // feedUri: 52 + // initialselectedfeed ?? 53 + // "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot", 54 + // agent: atomagent ?? undefined, 55 + // isAuthed: atomauth ?? false, 56 + // pdsUrl: identitypds, 57 + // feedServiceDid: feedServiceDid, 58 + // }); 59 + 60 + // const res = await queryClient.ensureInfiniteQueryData({ 61 + // queryKey, 62 + // queryFn, 63 + // initialPageParam: undefined as never, 64 + // getNextPageParam: (lastPage: any) => lastPage.cursor as null | undefined, 65 + // staleTime: Infinity, 66 + // //refetchOnWindowFocus: false, 67 + // //enabled: true, 68 + // }); 69 + // await Promise.all( 70 + // res.pages.map(async (page) => { 71 + // await Promise.all( 72 + // page.feed.map(async (feedviewpost) => { 73 + // if (!feedviewpost.post) return; 74 + // // /*mass comment*/ console.log("preloading: ", feedviewpost.post); 75 + // const opts = constructPostQuery(feedviewpost.post); 76 + // try { 77 + // await queryClient.ensureQueryData(opts); 78 + // } catch (e) { 79 + // // /*mass comment*/ console.log(" failed:", e); 80 + // } 81 + // }) 82 + // ); 83 + // }) 84 + // ); 85 + // }, 13 86 component: Home, 87 + pendingComponent: PendingHome, // PendingHome, 88 + staticData: { keepAlive: true }, 14 89 }); 90 + function PendingHome() { 91 + return <div>loading... (prefetching your timeline)</div>; 92 + } 15 93 16 - function Home() { 94 + //function Homer() { 95 + // return <div></div> 96 + //} 97 + export function Home({ hidden = false }: { hidden?: boolean }) { 17 98 const { 18 99 agent, 19 - loginStatus, 20 - login, 100 + status, 101 + authMethod, 102 + loginWithPassword, 103 + loginWithOAuth, 21 104 logout, 22 - loading: loadering, 23 - authed, 24 105 } = useAuth(); 25 - const { get, set } = usePersistentStore(); 26 - const [feed, setFeed] = React.useState<any[]>([]); 27 - const [loading, setLoading] = React.useState(true); 28 - const [error, setError] = React.useState<string | null>(null); 106 + const authed = !!agent?.did; 29 107 30 - const [prefs, setPrefs] = React.useState<any>({}); 31 - React.useEffect(() => { 32 - if (!loadering && authed && agent && agent.did) { 33 - const run = async () => { 34 - try { 35 - if (!agent.did) return; 36 - const prefs = await cachedGetPrefs({ 37 - did: agent.did, 38 - agent, 39 - get, 40 - set, 41 - }); 108 + // i dont remember why this is even here 109 + // useEffect(() => { 110 + // if (agent?.did) { 111 + // store.set(authedAtom, true); 112 + // } else { 113 + // store.set(authedAtom, false); 114 + // } 115 + // }, [status, agent, authed]); 116 + // useEffect(() => { 117 + // if (agent) { 118 + // // eslint-disable-next-line @typescript-eslint/ban-ts-comment 119 + // // @ts-ignore is it just me or is the type really weird here it should be Agent not AtpAgent 120 + // store.set(agentAtom, agent); 121 + // } else { 122 + // store.set(agentAtom, null); 123 + // } 124 + // }, [status, agent, authed]); 42 125 43 - console.log("alistoffeeds", prefs); 44 - setPrefs(prefs || {}); 45 - } catch (err) { 46 - console.error("alistoffeeds Fetch error in preferences effect:", err); 47 - } 48 - }; 126 + //const { get, set } = usePersistentStore(); 127 + // const [feed, setFeed] = React.useState<any[]>([]); 128 + // const [loading, setLoading] = React.useState(true); 129 + // const [error, setError] = React.useState<string | null>(null); 49 130 50 - run(); 51 - } 52 - }, [loadering, authed, agent]); 131 + // const [prefs, setPrefs] = React.useState<any>({}); 132 + // React.useEffect(() => { 133 + // if (!loadering && authed && agent && agent.did) { 134 + // const run = async () => { 135 + // try { 136 + // if (!agent.did) return; 137 + // const prefs = await cachedGetPrefs({ 138 + // did: agent.did, 139 + // agent, 140 + // get, 141 + // set, 142 + // }); 53 143 54 - const savedFeedsPref = React.useMemo(() => { 55 - if (!prefs?.preferences) return null; 56 - return prefs.preferences.find( 57 - (p: any) => p?.$type === "app.bsky.actor.defs#savedFeedsPrefV2", 144 + // // /*mass comment*/ console.log("alistoffeeds", prefs); 145 + // setPrefs(prefs || {}); 146 + // } catch (err) { 147 + // console.error("alistoffeeds Fetch error in preferences effect:", err); 148 + // } 149 + // }; 150 + 151 + // run(); 152 + // } 153 + // }, [loadering, authed, agent]); 154 + 155 + // const savedFeedsPref = React.useMemo(() => { 156 + // if (!prefs?.preferences) return null; 157 + // return prefs.preferences.find( 158 + // (p: any) => p?.$type === "app.bsky.actor.defs#savedFeedsPrefV2", 159 + // ); 160 + // }, [prefs]); 161 + 162 + // const savedFeeds = savedFeedsPref?.items || []; 163 + 164 + const [quickAuth, setQuickAuth] = useAtom(quickAuthAtom); 165 + const isAuthRestoring = quickAuth ? status === "loading" : false; 166 + 167 + const identityresultmaybe = useQueryIdentity(!isAuthRestoring ? agent?.did : undefined); 168 + const identity = identityresultmaybe?.data; 169 + 170 + const prefsresultmaybe = useQueryPreferences({ 171 + agent: !isAuthRestoring ? (agent ?? undefined) : undefined, 172 + pdsUrl: !isAuthRestoring ? (identity?.pds) : undefined, 173 + }); 174 + const prefs = prefsresultmaybe?.data; 175 + 176 + const savedFeeds = React.useMemo(() => { 177 + const savedFeedsPref = prefs?.preferences?.find( 178 + (p: any) => p?.$type === "app.bsky.actor.defs#savedFeedsPrefV2" 58 179 ); 180 + return savedFeedsPref?.items || []; 59 181 }, [prefs]); 60 182 61 - const savedFeeds = savedFeedsPref?.items || []; 62 - 63 - const [selectedFeed, setSelectedFeed] = React.useState<string | null>(null); 183 + const [persistentSelectedFeed, setPersistentSelectedFeed] = useAtom(selectedFeedUriAtom); 184 + const [unauthedSelectedFeed, setUnauthedSelectedFeed] = useState(persistentSelectedFeed); 185 + const selectedFeed = agent?.did 186 + ? persistentSelectedFeed 187 + : unauthedSelectedFeed; 188 + const setSelectedFeed = agent?.did 189 + ? setPersistentSelectedFeed 190 + : setUnauthedSelectedFeed; 64 191 192 + // /*mass comment*/ console.log("my selectedFeed is: ", selectedFeed); 65 193 React.useEffect(() => { 66 194 const fallbackFeed = 67 - "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/wh-hot"; 195 + "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot"; 68 196 if (authed) { 197 + if (selectedFeed) return; 69 198 if (savedFeeds.length > 0) { 70 199 setSelectedFeed((prev) => 71 200 prev && savedFeeds.some((f: any) => f.value === prev) 72 201 ? prev 73 - : savedFeeds[0].value, 202 + : savedFeeds[0].value 74 203 ); 75 204 } else { 205 + if (selectedFeed) return; 76 206 setSelectedFeed(fallbackFeed); 77 207 } 78 208 } else { 209 + if (selectedFeed) return; 79 210 setSelectedFeed(fallbackFeed); 80 211 } 81 - }, [savedFeeds, authed]); 212 + }, [savedFeeds, authed, setSelectedFeed]); 82 213 83 - React.useEffect(() => { 84 - if (loadering || !selectedFeed) return; 214 + // React.useEffect(() => { 215 + // if (loadering || !selectedFeed) return; 85 216 86 - let ignore = false; 217 + // let ignore = false; 87 218 88 - const run = async () => { 89 - setLoading(true); 90 - setError(null); 219 + // const run = async () => { 220 + // setLoading(true); 221 + // setError(null); 91 222 92 - try { 93 - if (authed && agent) { 94 - if (!agent.did) return; 223 + // try { 224 + // if (authed && agent) { 225 + // if (!agent.did) return; 95 226 96 - const pdsurl = await cachedResolveIdentity({ 97 - didOrHandle: agent.did, 98 - get, 99 - set, 100 - }); 227 + // const pdsurl = await cachedResolveIdentity({ 228 + // didOrHandle: agent.did, 229 + // get, 230 + // set, 231 + // }); 101 232 102 - const fetchstringcomplex = `${pdsurl.pdsUrl}/xrpc/app.bsky.feed.getFeedSkeleton?feed=${selectedFeed}`; 103 - console.log("fetching feed authed: " + fetchstringcomplex); 233 + // const fetchstringcomplex = `${pdsurl.pdsUrl}/xrpc/app.bsky.feed.getFeedSkeleton?feed=${selectedFeed}`; 234 + // // /*mass comment*/ console.log("fetching feed authed: " + fetchstringcomplex); 104 235 105 - const feeddef = await cachedGetRecord({ 106 - atUri: selectedFeed, 107 - get, 108 - set, 109 - }); 236 + // const feeddef = await cachedGetRecord({ 237 + // atUri: selectedFeed, 238 + // get, 239 + // set, 240 + // }); 110 241 111 - const feedservicedid = feeddef.value.did; 242 + // const feedservicedid = feeddef.value.did; 112 243 113 - const res = await agent.fetchHandler(fetchstringcomplex, { 114 - method: "GET", 115 - headers: { 116 - "atproto-proxy": `${feedservicedid}#bsky_fg`, 117 - "Content-Type": "application/json", 118 - }, 119 - }); 244 + // const res = await agent.fetchHandler(fetchstringcomplex, { 245 + // method: "GET", 246 + // headers: { 247 + // "atproto-proxy": `${feedservicedid}#bsky_fg`, 248 + // "Content-Type": "application/json", 249 + // }, 250 + // }); 120 251 121 - if (!res.ok) throw new Error("Failed to fetch feed"); 122 - const data = await res.json(); 252 + // if (!res.ok) throw new Error("Failed to fetch feed"); 253 + // const data = await res.json(); 123 254 124 - if (!ignore) setFeed(data.feed || []); 125 - } else { 126 - console.log("falling back"); 127 - // always use fallback feed for not logged in 128 - const fallbackFeed = 129 - "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot"; 130 - // const feeddef = await cachedGetRecord({ 131 - // atUri: fallbackFeed, 132 - // get, 133 - // set, 134 - // }); 255 + // if (!ignore) setFeed(data.feed || []); 256 + // } else { 257 + // // /*mass comment*/ console.log("falling back"); 258 + // // always use fallback feed for not logged in 259 + // const fallbackFeed = 260 + // "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot"; 261 + // // const feeddef = await cachedGetRecord({ 262 + // // atUri: fallbackFeed, 263 + // // get, 264 + // // set, 265 + // // }); 135 266 136 - //const feedservicedid = "did:web:discover.bsky.app" //feeddef.did; 137 - const fetchstringsimple = `https://discover.bsky.app/xrpc/app.bsky.feed.getFeedSkeleton?feed=${fallbackFeed}`; 138 - console.log("fetching feed unauthed: " + fetchstringsimple); 267 + // //const feedservicedid = "did:web:discover.bsky.app" //feeddef.did; 268 + // const fetchstringsimple = `https://discover.bsky.app/xrpc/app.bsky.feed.getFeedSkeleton?feed=${fallbackFeed}`; 269 + // // /*mass comment*/ console.log("fetching feed unauthed: " + fetchstringsimple); 139 270 140 - const res = await fetch(fetchstringsimple); 141 - if (!res.ok) throw new Error("Failed to fetch feed"); 142 - const data = await res.json(); 271 + // const res = await fetch(fetchstringsimple); 272 + // if (!res.ok) throw new Error("Failed to fetch feed"); 273 + // const data = await res.json(); 143 274 144 - if (!ignore) setFeed(data.feed || []); 145 - } 146 - } catch (e) { 147 - if (!ignore) { 148 - if (e instanceof Error) { 149 - setError(e.message); 150 - } else { 151 - setError("Unknown error"); 152 - } 153 - } 154 - } finally { 155 - if (!ignore) setLoading(false); 156 - } 157 - }; 275 + // if (!ignore) setFeed(data.feed || []); 276 + // } 277 + // } catch (e) { 278 + // if (!ignore) { 279 + // if (e instanceof Error) { 280 + // setError(e.message); 281 + // } else { 282 + // setError("Unknown error"); 283 + // } 284 + // } 285 + // } finally { 286 + // if (!ignore) setLoading(false); 287 + // } 288 + // }; 158 289 159 - run(); 290 + // run(); 160 291 292 + // return () => { 293 + // ignore = true; 294 + // }; 295 + // }, [authed, agent, loadering, selectedFeed, get, set]); 296 + 297 + const [scrollPositions, setScrollPositions] = useAtom( 298 + feedScrollPositionsAtom 299 + ); 300 + 301 + const scrollPositionsRef = React.useRef(scrollPositions); 302 + 303 + React.useEffect(() => { 304 + scrollPositionsRef.current = scrollPositions; 305 + }, [scrollPositions]); 306 + 307 + useLayoutEffect(() => { 308 + if (isAuthRestoring) return; 309 + const savedPosition = scrollPositions[selectedFeed ?? "null"] ?? 0; 310 + 311 + window.scrollTo({ top: savedPosition, behavior: "instant" }); 312 + // eslint-disable-next-line react-hooks/exhaustive-deps 313 + }, [selectedFeed, isAuthRestoring]); 314 + 315 + useLayoutEffect(() => { 316 + if (!selectedFeed || isAuthRestoring) return; 317 + 318 + const handleScroll = () => { 319 + scrollPositionsRef.current = { 320 + ...scrollPositionsRef.current, 321 + [selectedFeed]: window.scrollY, 322 + }; 323 + }; 324 + 325 + window.addEventListener("scroll", handleScroll, { passive: true }); 161 326 return () => { 162 - ignore = true; 327 + window.removeEventListener("scroll", handleScroll); 328 + 329 + setScrollPositions(scrollPositionsRef.current); 163 330 }; 164 - }, [authed, agent, loadering, selectedFeed, get, set]); 331 + }, [isAuthRestoring, selectedFeed, setScrollPositions]); 332 + 333 + const feedGengetrecordquery = useQueryArbitrary(!isAuthRestoring ? selectedFeed ?? undefined : undefined); 334 + const feedServiceDid = !isAuthRestoring ? (feedGengetrecordquery?.data?.value as any)?.did as string | undefined : undefined; 335 + 336 + // const { 337 + // data: feedData, 338 + // isLoading: isFeedLoading, 339 + // error: feedError, 340 + // } = useQueryFeedSkeleton({ 341 + // feedUri: selectedFeed!, 342 + // agent: agent ?? undefined, 343 + // isAuthed: authed ?? false, 344 + // pdsUrl: identity?.pds, 345 + // feedServiceDid: feedServiceDid, 346 + // }); 347 + 348 + // const feed = feedData?.feed || []; 349 + 350 + const isReadyForAuthedFeed = !isAuthRestoring && authed && agent && identity?.pds && feedServiceDid; 351 + const isReadyForUnauthedFeed = !isAuthRestoring && !authed && selectedFeed; 352 + 353 + 354 + const [isAtTop] = useAtom(isAtTopAtom); 165 355 166 356 return ( 167 - <div className="flex flex-col divide-y divide-gray-200 dark:divide-gray-800"> 168 - <div className="flex items-center gap-2 px-4 py-2 h-[52px] sticky top-0 bg-white dark:bg-gray-950 z-10 border-b border-gray-200 dark:border-gray-700 overflow-x-auto overflow-y-hidden scroll-thin"> 169 - {savedFeeds.length > 0 ? ( 170 - savedFeeds.map((item: any, idx: number) => { 357 + <div 358 + className={`relative flex flex-col divide-y divide-gray-200 dark:divide-gray-800 ${hidden && "hidden"}`} 359 + > 360 + {!isAuthRestoring && savedFeeds.length > 0 ? ( 361 + <div className={`flex items-center px-4 py-2 h-[52px] sticky top-0 bg-[var(--header-bg-light)] dark:bg-[var(--header-bg-dark)] ${!isAtTop && "shadow-sm"} sm:shadow-none sm:bg-white sm:dark:bg-gray-950 z-10 border-0 sm:border-b border-gray-200 dark:border-gray-700 overflow-x-auto overflow-y-hidden scroll-thin`}> 362 + {savedFeeds.map((item: any, idx: number) => { 171 363 const label = item.value.split("/").pop() || item.value; 172 364 const isActive = selectedFeed === item.value; 173 365 return ( ··· 175 367 key={item.value || idx} 176 368 className={`px-3 py-1 rounded-full whitespace-nowrap font-medium transition-colors ${ 177 369 isActive 178 - ? "bg-gray-600 text-white" 179 - : item.pinned 180 - ? "bg-gray-200 text-gray-700 dark:bg-gray-700 dark:text-gray-200" 181 - : "bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-200" 370 + ? "text-gray-900 dark:text-gray-100 hover:bg-gray-300 dark:bg-gray-700 bg-gray-200 hover:dark:bg-gray-600" 371 + : "text-gray-600 dark:text-gray-400 hover:bg-gray-100 hover:dark:bg-gray-800" 372 + // ? "bg-gray-500 text-white" 373 + // : item.pinned 374 + // ? "bg-gray-200 text-gray-700 dark:bg-gray-700 dark:text-gray-200" 375 + // : "bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-200" 182 376 }`} 183 377 onClick={() => setSelectedFeed(item.value)} 184 378 title={item.value} 185 379 > 186 380 {label} 187 381 {item.pinned && ( 188 - <span className="ml-1 text-xs text-gray-700 dark:text-gray-200"> 382 + <span 383 + className={`ml-1 text-xs ${ 384 + isActive 385 + ? "text-gray-900 dark:text-gray-100" 386 + : "text-gray-600 dark:text-gray-400" 387 + }`} 388 + > 189 389 โ˜… 190 390 </span> 191 391 )} 192 392 </button> 193 393 ); 194 - }) 195 - ) : ( 196 - <span className="text-xl font-bold ml-2">Home</span> 197 - )} 198 - </div> 199 - {loading && <div className="p-4 text-gray-500">Loading...</div>} 200 - {error && <div className="p-4 text-red-500">{error}</div>} 201 - {!loading && !error && feed.length === 0 && ( 202 - <div className="p-4 text-gray-500">No posts found.</div> 394 + })} 395 + </div> 396 + ) : ( 397 + // <span className="text-xl font-bold ml-2">Home</span> 398 + <Header title="Home" /> 203 399 )} 204 - {feed.map((item, i) => ( 400 + {/* {isFeedLoading && <div className="p-4 text-gray-500">Loading...</div>} 401 + {feedError && <div className="p-4 text-red-500">{feedError.message}</div>} 402 + {!isFeedLoading && !feedError && feed.length === 0 && ( 403 + <div className="p-4 text-gray-500">No posts found.</div> 404 + )} */} 405 + {/* {feed.map((item, i) => ( 205 406 <UniversalPostRendererATURILoader 206 407 key={item.post || i} 207 408 atUri={item.post} 208 409 /> 209 - ))} 410 + ))} */} 411 + 412 + {isAuthRestoring || authed && (!identity?.pds || !feedServiceDid) && ( 413 + <div className="p-4 text-center text-gray-500"> 414 + Preparing your feed... 415 + </div> 416 + )} 417 + 418 + {!isAuthRestoring && (isReadyForAuthedFeed || isReadyForUnauthedFeed) ? ( 419 + <InfiniteCustomFeed 420 + key={selectedFeed!} 421 + feedUri={selectedFeed!} 422 + pdsUrl={identity?.pds} 423 + feedServiceDid={feedServiceDid} 424 + /> 425 + ) : ( 426 + <div className="p-4 text-center text-gray-500"> 427 + Loading....... 428 + </div> 429 + )} 430 + {/* {false && restoringScrollPosition && ( 431 + <div className="fixed top-1/2 left-1/2 right-1/2"> 432 + restoringScrollPosition 433 + </div> 434 + )} */} 210 435 </div> 211 436 ); 212 437 } 438 + // not even used lmaooo 213 439 214 - export async function cachedResolveDIDWEBDOC({ 215 - didweb, 216 - cacheTimeout = CACHE_TIMEOUT, 217 - get, 218 - set, 219 - }: { 220 - didweb: string; 221 - cacheTimeout?: number; 222 - get: (key: string) => any; 223 - set: (key: string, value: string) => void; 224 - }): Promise<any> { 225 - const isDidInput = didweb.startsWith("did:web:"); 226 - const cacheKey = `didwebdoc:${didweb}`; 227 - const now = Date.now(); 228 - const cached = get(cacheKey); 229 - if ( 230 - cached && 231 - cached.value && 232 - cached.time && 233 - now - cached.time < cacheTimeout 234 - ) { 235 - try { 236 - return JSON.parse(cached.value); 237 - } catch {} 238 - } 239 - const url = `https://free-fly-24.deno.dev/resolve-did-web?did=${encodeURIComponent( 240 - didweb, 241 - )}`; 242 - const res = await fetch(url); 243 - if (!res.ok) throw new Error("Failed to resolve didwebdoc"); 244 - const data = await res.json(); 245 - set(cacheKey, JSON.stringify(data)); 246 - if (!isDidInput && data.did) { 247 - set(`didwebdoc:${data.did}`, JSON.stringify(data)); 248 - } 249 - return data; 250 - } 440 + // export async function cachedResolveDIDWEBDOC({ 441 + // didweb, 442 + // cacheTimeout = CACHE_TIMEOUT, 443 + // get, 444 + // set, 445 + // }: { 446 + // didweb: string; 447 + // cacheTimeout?: number; 448 + // get: (key: string) => any; 449 + // set: (key: string, value: string) => void; 450 + // }): Promise<any> { 451 + // const isDidInput = didweb.startsWith("did:web:"); 452 + // const cacheKey = `didwebdoc:${didweb}`; 453 + // const now = Date.now(); 454 + // const cached = get(cacheKey); 455 + // if ( 456 + // cached && 457 + // cached.value && 458 + // cached.time && 459 + // now - cached.time < cacheTimeout 460 + // ) { 461 + // try { 462 + // return JSON.parse(cached.value); 463 + // } catch (_e) {/* whatever*/ } 464 + // } 465 + // const url = `https://free-fly-24.deno.dev/resolve-did-web?did=${encodeURIComponent( 466 + // didweb 467 + // )}`; 468 + // const res = await fetch(url); 469 + // if (!res.ok) throw new Error("Failed to resolve didwebdoc"); 470 + // const data = await res.json(); 471 + // set(cacheKey, JSON.stringify(data)); 472 + // if (!isDidInput && data.did) { 473 + // set(`didwebdoc:${data.did}`, JSON.stringify(data)); 474 + // } 475 + // return data; 476 + // } 251 477 252 - export async function cachedGetPrefs({ 253 - did, 254 - agent, 255 - get, 256 - set, 257 - cacheTimeout = CACHE_TIMEOUT, 258 - }: { 259 - did: string; 260 - agent: any; // or type properly if available 261 - get: (key: string) => any; 262 - set: (key: string, value: string) => void; 263 - cacheTimeout?: number; 264 - }): Promise<any> { 265 - const cacheKey = `prefs:${did}`; 266 - const cached = get(cacheKey); 267 - const now = Date.now(); 478 + // export async function cachedGetPrefs({ 479 + // did, 480 + // agent, 481 + // get, 482 + // set, 483 + // cacheTimeout = CACHE_TIMEOUT, 484 + // }: { 485 + // did: string; 486 + // agent: any; // or type properly if available 487 + // get: (key: string) => any; 488 + // set: (key: string, value: string) => void; 489 + // cacheTimeout?: number; 490 + // }): Promise<any> { 491 + // const cacheKey = `prefs:${did}`; 492 + // const cached = get(cacheKey); 493 + // const now = Date.now(); 268 494 269 - if ( 270 - cached && 271 - cached.value && 272 - cached.time && 273 - now - cached.time < cacheTimeout 274 - ) { 275 - try { 276 - return JSON.parse(cached.value); 277 - } catch { 278 - // fall through to fetch 279 - } 280 - } 495 + // if ( 496 + // cached && 497 + // cached.value && 498 + // cached.time && 499 + // now - cached.time < cacheTimeout 500 + // ) { 501 + // try { 502 + // return JSON.parse(cached.value); 503 + // } catch { 504 + // // fall through to fetch 505 + // } 506 + // } 281 507 282 - const resolved = await cachedResolveIdentity({ 283 - didOrHandle: did, 284 - get, 285 - set, 286 - }); 508 + // const resolved = await cachedResolveIdentity({ 509 + // didOrHandle: did, 510 + // get, 511 + // set, 512 + // }); 287 513 288 - if (!resolved?.pdsUrl) throw new Error("Missing resolved PDS info"); 514 + // if (!resolved?.pdsUrl) throw new Error("Missing resolved PDS info"); 289 515 290 - const fetchUrl = `${resolved.pdsUrl}/xrpc/app.bsky.actor.getPreferences`; 516 + // const fetchUrl = `${resolved.pdsUrl}/xrpc/app.bsky.actor.getPreferences`; 291 517 292 - const res = await agent.fetchHandler(fetchUrl, { 293 - method: "GET", 294 - headers: { 295 - "Content-Type": "application/json", 296 - }, 297 - }); 518 + // const res = await agent.fetchHandler(fetchUrl, { 519 + // method: "GET", 520 + // headers: { 521 + // "Content-Type": "application/json", 522 + // }, 523 + // }); 298 524 299 - if (!res.ok) throw new Error(`Failed to fetch preferences: ${res.status}`); 525 + // if (!res.ok) throw new Error(`Failed to fetch preferences: ${res.status}`); 300 526 301 - const text = await res.text(); 527 + // const text = await res.text(); 302 528 303 - let data: any; 304 - try { 305 - data = JSON.parse(text); 306 - } catch (err) { 307 - console.error("Failed to parse preferences JSON:", err); 308 - throw err; 309 - } 529 + // let data: any; 530 + // try { 531 + // data = JSON.parse(text); 532 + // } catch (err) { 533 + // console.error("Failed to parse preferences JSON:", err); 534 + // throw err; 535 + // } 310 536 311 - set(cacheKey, JSON.stringify(data)); 312 - return data; 313 - } 537 + // set(cacheKey, JSON.stringify(data)); 538 + // return data; 539 + // }
+31 -26
src/routes/notifications.tsx
··· 1 1 import { createFileRoute } from "@tanstack/react-router"; 2 - import React, { useEffect, useState, useRef } from "react"; 3 - import { useAuth } from "~/providers/PassAuthProvider"; 4 - import { usePersistentStore } from "~/providers/PersistentStoreProvider"; 2 + import { useAtom } from "jotai"; 3 + import React, { useEffect, useRef,useState } from "react"; 4 + 5 + import { useAuth } from "~/providers/UnifiedAuthProvider"; 6 + import { constellationURLAtom } from "~/utils/atoms"; 5 7 6 8 const HANDLE_DID_CACHE_TIMEOUT = 60 * 60 * 1000; // 1 hour 7 9 ··· 10 12 }); 11 13 12 14 function NotificationsComponent() { 13 - console.log("NotificationsComponent render"); 14 - const { agent, authed, loading: authLoading } = useAuth(); 15 - const { get, set } = usePersistentStore(); 15 + // /*mass comment*/ console.log("NotificationsComponent render"); 16 + const { agent, status } = useAuth(); 17 + const authed = !!agent?.did; 18 + const authLoading = status === "loading"; 16 19 const [did, setDid] = useState<string | null>(null); 17 20 const [resolving, setResolving] = useState(false); 18 21 const [error, setError] = useState<string | null>(null); ··· 28 31 }, [authed, agent, authLoading]); 29 32 30 33 async function handleSubmit() { 31 - console.log("handleSubmit called"); 34 + // /*mass comment*/ console.log("handleSubmit called"); 32 35 setError(null); 33 36 setResponses([null, null, null]); 34 37 const value = inputRef.current?.value?.trim() || ""; ··· 41 44 setResolving(true); 42 45 const cacheKey = `handleDid:${value}`; 43 46 const now = Date.now(); 44 - const cached = await get(cacheKey); 45 - if ( 46 - cached && 47 - cached.value && 48 - cached.time && 49 - now - cached.time < HANDLE_DID_CACHE_TIMEOUT 50 - ) { 51 - try { 52 - const data = JSON.parse(cached.value); 53 - setDid(data.did); 54 - setResolving(false); 55 - return; 56 - } catch {} 57 - } 47 + const cached = undefined // await get(cacheKey); 48 + // if ( 49 + // cached && 50 + // cached.value && 51 + // cached.time && 52 + // now - cached.time < HANDLE_DID_CACHE_TIMEOUT 53 + // ) { 54 + // try { 55 + // const data = JSON.parse(cached.value); 56 + // setDid(data.did); 57 + // setResolving(false); 58 + // return; 59 + // } catch {} 60 + // } 58 61 try { 59 62 const url = `https://free-fly-24.deno.dev/?handle=${encodeURIComponent(value)}`; 60 63 const res = await fetch(url); 61 64 if (!res.ok) throw new Error("Failed to resolve handle"); 62 65 const data = await res.json(); 63 - set(cacheKey, JSON.stringify(data)); 66 + //set(cacheKey, JSON.stringify(data)); 64 67 setDid(data.did); 65 68 } catch (e: any) { 66 69 setError("Failed to resolve handle: " + (e?.message || e)); ··· 69 72 } 70 73 } 71 74 75 + const [constellationURL] = useAtom(constellationURLAtom) 76 + 72 77 useEffect(() => { 73 78 if (!did) return; 74 79 setLoading(true); 75 80 setError(null); 76 81 const urls = [ 77 - `https://constellation.microcosm.blue/links?target=${encodeURIComponent(did)}&collection=app.bsky.feed.post&path=.facets[app.bsky.richtext.facet].features[app.bsky.richtext.facet%23mention].did`, 78 - `https://constellation.microcosm.blue/links?target=${encodeURIComponent(did)}&collection=app.bsky.feed.post&path=.facets[].features[app.bsky.richtext.facet%23mention].did`, 79 - `https://constellation.microcosm.blue/links?target=${encodeURIComponent(did)}&collection=app.bsky.graph.follow&path=.subject`, 82 + `https://${constellationURL}/links?target=${encodeURIComponent(did)}&collection=app.bsky.feed.post&path=.facets[app.bsky.richtext.facet].features[app.bsky.richtext.facet%23mention].did`, 83 + `https://${constellationURL}/links?target=${encodeURIComponent(did)}&collection=app.bsky.feed.post&path=.facets[].features[app.bsky.richtext.facet%23mention].did`, 84 + `https://${constellationURL}/links?target=${encodeURIComponent(did)}&collection=app.bsky.graph.follow&path=.subject`, 80 85 ]; 81 86 let ignore = false; 82 87 Promise.all( ··· 94 99 } catch (e: any) { 95 100 return { error: e?.message || String(e) }; 96 101 } 97 - }), 102 + }) 98 103 ) 99 104 .then((results) => { 100 105 if (!ignore) setResponses(results);
+310 -368
src/routes/profile.$did/index.tsx
··· 1 - import { createFileRoute, Link } from "@tanstack/react-router"; 2 - import React from "react"; 3 - import { UniversalPostRendererATURILoader } from "~/components/UniversalPostRenderer"; 4 - import { usePersistentStore } from "~/providers/PersistentStoreProvider"; 1 + import { RichText } from "@atproto/api"; 2 + import { useQueryClient } from "@tanstack/react-query"; 3 + import { createFileRoute, useNavigate } from "@tanstack/react-router"; 4 + import { useAtom } from "jotai"; 5 + import React, { type ReactNode, useEffect, useState } from "react"; 5 6 6 - const HANDLE_DID_CACHE_TIMEOUT = 60 * 60 * 1000; // 1 hour 7 - const CACHE_TIMEOUT = 5 * 60 * 1000; // 5 minutes 7 + import { Header } from "~/components/Header"; 8 + import { Button } from "~/components/radix-m3-rd/Button"; 9 + import { 10 + renderTextWithFacets, 11 + UniversalPostRendererATURILoader, 12 + } from "~/components/UniversalPostRenderer"; 13 + import { useAuth } from "~/providers/UnifiedAuthProvider"; 14 + import { imgCDNAtom } from "~/utils/atoms"; 15 + import { 16 + toggleFollow, 17 + useGetFollowState, 18 + useGetOneToOneState, 19 + } from "~/utils/followState"; 20 + import { 21 + useInfiniteQueryAuthorFeed, 22 + useQueryIdentity, 23 + useQueryProfile, 24 + } from "~/utils/useQuery"; 8 25 9 26 export const Route = createFileRoute("/profile/$did/")({ 10 27 component: ProfileComponent, 11 28 }); 12 29 13 30 function ProfileComponent() { 31 + // booo bad this is not always the did it might be a handle, use identity.did instead 14 32 const { did } = Route.useParams(); 15 - const { get, set } = usePersistentStore(); 16 - const [resolvedDid, setResolvedDid] = React.useState<string | null>(null); 17 - const [resolvedHandle, setResolvedHandle] = React.useState<string | null>( 18 - null, 19 - ); 20 - const [loading, setLoading] = React.useState(false); 21 - const [error, setError] = React.useState<string | null>(null); 22 - const [profile, setProfile] = React.useState<any>(null); 23 - const [posts, setPosts] = React.useState<any[]>([]); 24 - const [postsLoading, setPostsLoading] = React.useState(false); 25 - const [cursor, setCursor] = React.useState<string | null>(null); 26 - const [hasMore, setHasMore] = React.useState(true); 27 - const [postsCached, setPostsCached] = React.useState(false); 33 + const navigate = useNavigate(); 34 + const queryClient = useQueryClient(); 35 + const { 36 + data: identity, 37 + isLoading: isIdentityLoading, 38 + error: identityError, 39 + } = useQueryIdentity(did); 28 40 29 - React.useEffect(() => { 30 - let ignore = false; 31 - async function resolveDidIfNeeded() { 32 - if (!did) { 33 - setResolvedDid(null); 34 - setResolvedHandle(null); 35 - return; 36 - } 37 - if (did.startsWith("did:")) { 38 - setResolvedDid(did); 39 - setLoading(true); 40 - setError(null); 41 - const cacheKey = `handleDid:${did}`; 42 - const now = Date.now(); 43 - const cached = await get(cacheKey); 44 - if ( 45 - cached && 46 - cached.value && 47 - cached.time && 48 - now - cached.time < HANDLE_DID_CACHE_TIMEOUT 49 - ) { 50 - try { 51 - const data = JSON.parse(cached.value); 52 - if (!ignore) { 53 - setResolvedDid(data.did); 54 - setResolvedHandle(data.handle || null); 55 - } 56 - setLoading(false); 57 - return; 58 - } catch {} 59 - } 60 - try { 61 - const url = `https://free-fly-24.deno.dev/?did=${encodeURIComponent(did)}`; 62 - const res = await fetch(url); 63 - if (!res.ok) throw new Error("Failed to resolve DID"); 64 - const data = await res.json(); 65 - set(cacheKey, JSON.stringify(data)); 66 - if (!ignore) { 67 - setResolvedDid(data.did); 68 - setResolvedHandle(data.handle || null); 69 - } 70 - } catch (e: any) { 71 - if (!ignore) 72 - setError("Failed to resolve handle: " + (e?.message || e)); 73 - } finally { 74 - setLoading(false); 75 - } 76 - return; 77 - } 78 - setLoading(true); 79 - setError(null); 80 - const cacheKey = `handleDid:${did}`; 81 - const now = Date.now(); 82 - const cached = await get(cacheKey); 83 - if ( 84 - cached && 85 - cached.value && 86 - cached.time && 87 - now - cached.time < HANDLE_DID_CACHE_TIMEOUT 88 - ) { 89 - try { 90 - const data = JSON.parse(cached.value); 91 - if (!ignore) { 92 - setResolvedDid(data.did); 93 - setResolvedHandle(data.handle || did); 94 - } 95 - setLoading(false); 96 - return; 97 - } catch {} 98 - } 99 - try { 100 - const url = `https://free-fly-24.deno.dev/?handle=${encodeURIComponent(did)}`; 101 - const res = await fetch(url); 102 - if (!res.ok) throw new Error("Failed to resolve handle"); 103 - const data = await res.json(); 104 - set(cacheKey, JSON.stringify(data)); 105 - if (!ignore) { 106 - setResolvedDid(data.did); 107 - setResolvedHandle(data.handle || did); 108 - } 109 - } catch (e: any) { 110 - if (!ignore) setError("Failed to resolve handle: " + (e?.message || e)); 111 - } finally { 112 - setLoading(false); 113 - } 114 - } 115 - resolveDidIfNeeded(); 116 - return () => { 117 - ignore = true; 118 - }; 119 - }, [did, get, set]); 41 + const resolvedDid = did.startsWith("did:") ? did : identity?.did; 42 + const resolvedHandle = did.startsWith("did:") ? identity?.handle : did; 43 + const pdsUrl = identity?.pds; 120 44 121 - React.useEffect(() => { 122 - if (!resolvedDid) return; 123 - let ignore = false; 124 - async function fetchProfile() { 125 - const cacheKey = `profile:${resolvedDid}`; 126 - const now = Date.now(); 127 - const cached = await get(cacheKey); 128 - if ( 129 - cached && 130 - cached.value && 131 - cached.time && 132 - now - cached.time < CACHE_TIMEOUT 133 - ) { 134 - try { 135 - if (!ignore) setProfile(JSON.parse(cached.value)); 136 - return; 137 - } catch {} 138 - } 139 - try { 140 - if (!resolvedDid) return; 141 - let resolvedRaw = await get(`handleDid:${resolvedDid}`); 142 - let resolved: any = null; 143 - if ( 144 - resolvedRaw && 145 - resolvedRaw.value && 146 - resolvedRaw.time && 147 - now - resolvedRaw.time < HANDLE_DID_CACHE_TIMEOUT 148 - ) { 149 - try { 150 - resolved = JSON.parse(resolvedRaw.value); 151 - } catch { 152 - resolved = null; 153 - } 154 - } else { 155 - const url = `https://free-fly-24.deno.dev/?did=${encodeURIComponent(resolvedDid)}`; 156 - const res = await fetch(url); 157 - if (!res.ok) throw new Error("Failed to resolve DID"); 158 - resolved = await res.json(); 159 - set(`handleDid:${resolvedDid}`, JSON.stringify(resolved)); 160 - } 161 - if (!resolved || !resolved.pdsUrl) 162 - throw new Error("DID resolution failed or missing pdsUrl"); 45 + const profileUri = resolvedDid 46 + ? `at://${resolvedDid}/app.bsky.actor.profile/self` 47 + : undefined; 48 + const { data: profileRecord } = useQueryProfile(profileUri); 49 + const profile = profileRecord?.value; 163 50 164 - const profileUrl = `${resolved.pdsUrl}/xrpc/com.atproto.repo.getRecord?repo=${encodeURIComponent(resolvedDid)}&collection=app.bsky.actor.profile&rkey=self`; 165 - const profileRes = await fetch(profileUrl); 166 - if (!profileRes.ok) throw new Error("Failed to fetch profile"); 167 - const profileData = await profileRes.json(); 168 - if (!ignore) { 169 - setProfile(profileData); 170 - set(cacheKey, JSON.stringify(profileData)); 171 - } 172 - } catch (e: any) { 173 - if (!ignore) setError("Failed to fetch profile: " + (e?.message || e)); 174 - } 175 - } 176 - fetchProfile(); 177 - return () => { 178 - ignore = true; 179 - }; 180 - }, [resolvedDid, get, set]); 51 + const { 52 + data: postsData, 53 + fetchNextPage, 54 + hasNextPage, 55 + isFetchingNextPage, 56 + isLoading: arePostsLoading, 57 + } = useInfiniteQueryAuthorFeed(resolvedDid, pdsUrl); 181 58 182 59 React.useEffect(() => { 183 - if (!resolvedDid) return; 184 - let ignore = false; 185 - async function fetchPosts() { 186 - setPostsLoading(true); 187 - setPostsCached(false); 188 - try { 189 - if (!resolvedDid) return; 190 - let resolvedRaw = await get(`handleDid:${resolvedDid}`); 191 - let resolved: any = null; 192 - const now = Date.now(); 193 - if ( 194 - resolvedRaw && 195 - resolvedRaw.value && 196 - resolvedRaw.time && 197 - now - resolvedRaw.time < HANDLE_DID_CACHE_TIMEOUT 198 - ) { 199 - try { 200 - resolved = JSON.parse(resolvedRaw.value); 201 - } catch { 202 - resolved = null; 60 + if (postsData) { 61 + postsData.pages.forEach((page) => { 62 + page.records.forEach((record) => { 63 + if (!queryClient.getQueryData(["post", record.uri])) { 64 + queryClient.setQueryData(["post", record.uri], record); 203 65 } 204 - } else { 205 - const url = `https://free-fly-24.deno.dev/?did=${encodeURIComponent(resolvedDid)}`; 206 - const res = await fetch(url); 207 - if (!res.ok) throw new Error("Failed to resolve DID"); 208 - resolved = await res.json(); 209 - set(`handleDid:${resolvedDid}`, JSON.stringify(resolved)); 210 - } 211 - if (!resolved || !resolved.pdsUrl) 212 - throw new Error("DID resolution failed or missing pdsUrl"); 66 + }); 67 + }); 68 + } 69 + }, [postsData, queryClient]); 213 70 214 - const postsUrl = `${resolved.pdsUrl}/xrpc/com.atproto.repo.listRecords?repo=${resolvedDid}&collection=app.bsky.feed.post${cursor && false ? `&cursor=${cursor}` : ""}&limit=20`; 215 - const postsRes = await fetch(postsUrl); 216 - if (!postsRes.ok) throw new Error("Failed to fetch posts"); 217 - const postsData = await postsRes.json(); 218 - 219 - if (postsData.records) { 220 - await Promise.all( 221 - postsData.records.map(async (post: any) => { 222 - if (post.uri && post.value) { 223 - const postCacheKey = `record:${post.uri}`; 224 - console.log( 225 - "caching post", 226 - postCacheKey, 227 - JSON.stringify(post, null, 2), 228 - ); 229 - await set(postCacheKey, JSON.stringify(post)); 230 - } 231 - }), 232 - ); 233 - } 71 + const posts = React.useMemo( 72 + () => postsData?.pages.flatMap((page) => page.records) ?? [], 73 + [postsData] 74 + ); 234 75 235 - if (!ignore) { 236 - setPosts((prev) => 237 - cursor ? [...prev, ...postsData.records] : postsData.records, 238 - ); 239 - setCursor(postsData.cursor || null); 240 - setHasMore(postsData.records.length === 20); 241 - setPostsCached(true); 242 - } 243 - } catch (e: any) { 244 - if (!ignore) setError("Failed to fetch posts: " + (e?.message || e)); 245 - } finally { 246 - if (!ignore) setPostsLoading(false); 247 - } 248 - } 249 - fetchPosts(); 250 - return () => { 251 - ignore = true; 252 - }; 253 - }, [resolvedDid, cursor, get, set]); 76 + const [imgcdn] = useAtom(imgCDNAtom); 254 77 255 - function getAvatarUrl(profile: any) { 256 - const link = profile?.value?.avatar?.ref?.["$link"]; 78 + function getAvatarUrl(p: typeof profile) { 79 + const link = p?.avatar?.ref?.["$link"]; 257 80 if (!link || !resolvedDid) return null; 258 - return `https://cdn.bsky.app/img/avatar/plain/${resolvedDid}/${link}@jpeg`; 81 + return `https://${imgcdn}/img/avatar/plain/${resolvedDid}/${link}@jpeg`; 259 82 } 260 - function getBannerUrl(profile: any) { 261 - const link = profile?.value?.banner?.ref?.["$link"]; 83 + function getBannerUrl(p: typeof profile) { 84 + const link = p?.banner?.ref?.["$link"]; 262 85 if (!link || !resolvedDid) return null; 263 - return `https://cdn.bsky.app/img/banner/plain/${resolvedDid}/${link}@jpeg`; 86 + return `https://${imgcdn}/img/banner/plain/${resolvedDid}/${link}@jpeg`; 264 87 } 265 88 266 89 const displayName = 267 - profile?.value?.displayName || 268 - (resolvedHandle ? `@${resolvedHandle}` : did); 269 - let handle: string; 270 - if (resolvedHandle) { 271 - handle = `@${resolvedHandle}`; 272 - } else if (did && !did.startsWith("did:")) { 273 - handle = `@${did}`; 274 - } else { 275 - handle = resolvedDid || did; 90 + profile?.displayName || (resolvedHandle ? `@${resolvedHandle}` : did); 91 + const handle = resolvedHandle ? `@${resolvedHandle}` : resolvedDid || did; 92 + const description = profile?.description || ""; 93 + 94 + if (isIdentityLoading) { 95 + return ( 96 + <div className="p-4 text-center text-gray-500">Resolving profile...</div> 97 + ); 276 98 } 277 - const description = profile?.value?.description || ""; 278 99 279 - if (!did) return <div>Invalid profile</div>; 280 - if (loading) return <div>Resolving handle...</div>; 281 - if (error) return <div style={{ color: "red" }}>{error}</div>; 282 - if (!resolvedDid) return <div>Invalid profile</div>; 100 + if (identityError) { 101 + return ( 102 + <div className="p-4 text-center text-red-500"> 103 + Error: {identityError.message} 104 + </div> 105 + ); 106 + } 107 + 108 + if (!resolvedDid) { 109 + return ( 110 + <div className="p-4 text-center text-gray-500">Profile not found.</div> 111 + ); 112 + } 283 113 284 114 return ( 285 115 <> 286 - <div className="flex items-center gap-2 px-4 py-2 h-[52px] sticky top-0 bg-white dark:bg-gray-950 z-10 border-b border-gray-200 dark:border-gray-700"> 116 + <Header 117 + title={`Profile`} 118 + backButtonCallback={() => { 119 + if (window.history.length > 1) { 120 + window.history.back(); 121 + } else { 122 + window.location.assign("/"); 123 + } 124 + }} 125 + /> 126 + {/* <div className="flex gap-2 px-4 py-2 h-[52px] sticky top-0 bg-white dark:bg-gray-950 z-10 border-b border-gray-200 dark:border-gray-700"> 287 127 <Link 288 128 to=".." 289 129 className="px-3 py-1 rounded hover:bg-gray-100 dark:hover:bg-gray-900 font-bold text-lg" 290 130 onClick={(e) => { 291 131 e.preventDefault(); 292 - window.history.length > 1 293 - ? window.history.back() 294 - : window.location.assign("/"); 132 + if (window.history.length > 1) { 133 + window.history.back() 134 + } else { 135 + window.location.assign("/"); 136 + } 295 137 }} 296 138 aria-label="Go back" 297 139 > 298 140 โ† 299 141 </Link> 300 142 <span className="text-xl font-bold ml-2">Profile</span> 301 - </div> 143 + </div> */} 302 144 303 145 {/* Profile Header */} 304 - <div 305 - style={{ 306 - width: "100%", 307 - maxWidth: 600, 308 - margin: "0 auto", 309 - boxShadow: "0 2px 12px #0002", 310 - padding: 0, 311 - color: "#eee", 312 - fontFamily: "system-ui, sans-serif", 313 - // marginTop: 20, 314 - //background: '#181a20', 315 - borderRadius: 16, 316 - overflow: "hidden", 317 - position: "relative", 318 - }} 319 - className="bg-gray-200 dark:bg-gray-900" 320 - > 146 + <div className="w-full max-w-2xl mx-auto overflow-hidden relative bg-gray-100 dark:bg-gray-900"> 321 147 {/* Banner */} 322 148 <div 149 + className="w-full h-40 bg-gray-300 dark:bg-gray-700" 323 150 style={{ 324 - width: "100%", 325 - height: 160, 326 - background: `#222 url(${getBannerUrl(profile)}) center/cover no-repeat`, 327 - position: "relative", 151 + backgroundImage: `url(${getBannerUrl(profile)})`, 152 + backgroundSize: "cover", 153 + backgroundPosition: "center", 328 154 }} 329 155 /> 156 + 330 157 {/* Avatar (PFP) */} 331 - <div 332 - style={{ 333 - position: "absolute", 334 - left: "50%", 335 - top: 120, 336 - transform: "translateX(-50%)", 337 - zIndex: 2, 338 - borderRadius: "50%", 339 - border: "4px solid #181a20", 340 - boxShadow: "0 2px 8px #0006", 341 - background: "#222", 342 - }} 343 - > 158 + <div className="absolute left-[16px] top-[100px] "> 344 159 <img 345 160 src={getAvatarUrl(profile) || "/favicon.png"} 346 161 alt="avatar" 347 - style={{ 348 - width: 112, 349 - height: 112, 350 - borderRadius: "50%", 351 - objectFit: "cover", 352 - display: "block", 353 - }} 162 + className="w-28 h-28 rounded-full object-cover border-4 border-white dark:border-gray-950 bg-gray-300 dark:bg-gray-700" 354 163 /> 355 164 </div> 165 + 166 + <div className="absolute right-[16px] top-[170px] flex flex-row gap-2.5"> 167 + {/* 168 + todo: full follow and unfollow backfill (along with partial likes backfill, 169 + just enough for it to be useful) 170 + also delay the backfill to be on demand because it would be pretty intense 171 + also save it persistently 172 + */} 173 + <FollowButton targetdidorhandle={did} /> 174 + <Button className="rounded-full" variant={"secondary"}> 175 + ... {/* todo: icon */} 176 + </Button> 177 + </div> 178 + 356 179 {/* Info Card */} 357 - <div 358 - style={{ 359 - marginTop: 72, 360 - padding: "0 24px 24px 24px", 361 - textAlign: "center", 362 - }} 363 - > 364 - <div style={{ fontWeight: 700, fontSize: 24, marginBottom: 4 }}> 365 - {displayName} 366 - </div> 367 - <div style={{ color: "#aaa", fontSize: 16, marginBottom: 12 }}> 180 + <div className="mt-16 pb-2 px-4 text-gray-900 dark:text-gray-100"> 181 + <div className="font-bold text-2xl">{displayName}</div> 182 + <div className="text-gray-500 dark:text-gray-400 text-base mb-3 flex flex-row gap-1"> 183 + <Mutual targetdidorhandle={did} /> 368 184 {handle} 369 185 </div> 370 186 {description && ( 371 - <div 372 - style={{ 373 - fontSize: 16, 374 - lineHeight: 1.5, 375 - color: "#ddd", 376 - marginBottom: 20, 377 - }} 378 - > 379 - {description} 187 + <div className="text-base leading-relaxed text-gray-800 dark:text-gray-300 mb-5 whitespace-pre-wrap break-words text-[15px]"> 188 + {/* {description} */} 189 + <RichTextRenderer key={did} description={description} /> 380 190 </div> 381 191 )} 382 - {!profile && !error && ( 383 - <div style={{ color: "#888", padding: 16 }}>Loading profile...</div> 384 - )} 385 192 </div> 386 193 </div> 387 194 388 - {/* Posts */} 389 - <div style={{ maxWidth: 600, margin: "0px auto 0", padding: 0 }}> 390 - <div 391 - className="text-gray-500 dark:text-gray-400 text-sm font-bold" 392 - style={{ 393 - fontSize: 18, 394 - margin: "12px 16px 12px 16px", 395 - fontWeight: 600, 396 - }} 397 - > 195 + {/* Posts Section */} 196 + <div className="max-w-2xl mx-auto"> 197 + <div className="text-gray-500 dark:text-gray-400 text-lg font-semibold my-3 mx-4"> 398 198 Posts 399 199 </div> 400 - <div style={{ display: "flex", flexDirection: "column", gap: 0 }}> 401 - {postsCached && 402 - posts.map((post) => { 403 - return ( 404 - <UniversalPostRendererATURILoader 405 - key={post.uri} 406 - atUri={post.uri} 407 - feedviewpost={true} 408 - /> 409 - ); 410 - })} 200 + <div> 201 + {posts.map((post) => ( 202 + <UniversalPostRendererATURILoader 203 + key={post.uri} 204 + atUri={post.uri} 205 + feedviewpost={true} 206 + /> 207 + ))} 411 208 </div> 412 - {postsLoading && ( 413 - <div style={{ color: "#888", padding: 16, textAlign: "center" }}> 414 - Loading posts... 415 - </div> 209 + 210 + {/* Loading and "Load More" states */} 211 + {arePostsLoading && posts.length === 0 && ( 212 + <div className="p-4 text-center text-gray-500">Loading posts...</div> 213 + )} 214 + {isFetchingNextPage && ( 215 + <div className="p-4 text-center text-gray-500">Loading more...</div> 416 216 )} 417 - {hasMore && !postsLoading && ( 217 + {hasNextPage && !isFetchingNextPage && ( 418 218 <button 419 - onClick={() => setCursor(cursor)} 420 - style={{ 421 - width: "100%", 422 - padding: 12, 423 - background: "#222", 424 - color: "#eee", 425 - border: "none", 426 - borderRadius: 8, 427 - cursor: "pointer", 428 - fontSize: 16, 429 - marginTop: 16, 430 - }} 219 + onClick={() => fetchNextPage()} 220 + className="w-[calc(100%-2rem)] mx-4 my-4 px-4 py-2 bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-gray-200 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-700 font-semibold" 431 221 > 432 222 Load More Posts 433 223 </button> 434 224 )} 435 - {posts.length === 0 && !postsLoading && !error && ( 436 - <div style={{ color: "#888", padding: 16, textAlign: "center" }}> 437 - No posts found 438 - </div> 225 + {posts.length === 0 && !arePostsLoading && ( 226 + <div className="p-4 text-center text-gray-500">No posts found.</div> 439 227 )} 440 228 </div> 441 229 </> 442 230 ); 443 231 } 232 + 233 + export function FollowButton({ 234 + targetdidorhandle, 235 + }: { 236 + targetdidorhandle: string; 237 + }) { 238 + const { agent } = useAuth(); 239 + const { data: identity } = useQueryIdentity(targetdidorhandle); 240 + const queryClient = useQueryClient(); 241 + 242 + const followRecords = useGetFollowState({ 243 + target: identity?.did ?? targetdidorhandle, 244 + user: agent?.did, 245 + }); 246 + 247 + return ( 248 + <> 249 + {identity?.did !== agent?.did ? ( 250 + <> 251 + {!(followRecords?.length && followRecords?.length > 0) ? ( 252 + <Button 253 + onClick={(e) => { 254 + e.stopPropagation(); 255 + toggleFollow({ 256 + agent: agent || undefined, 257 + targetDid: identity?.did, 258 + followRecords: followRecords, 259 + queryClient: queryClient, 260 + }); 261 + }} 262 + > 263 + Follow 264 + </Button> 265 + ) : ( 266 + <Button 267 + onClick={(e) => { 268 + e.stopPropagation(); 269 + toggleFollow({ 270 + agent: agent || undefined, 271 + targetDid: identity?.did, 272 + followRecords: followRecords, 273 + queryClient: queryClient, 274 + }); 275 + }} 276 + > 277 + Unfollow 278 + </Button> 279 + )} 280 + </> 281 + ) : ( 282 + <Button variant={"secondary"}>Edit Profile</Button> 283 + )} 284 + </> 285 + ); 286 + } 287 + 288 + export function Mutual({ targetdidorhandle }: { targetdidorhandle: string }) { 289 + const { agent } = useAuth(); 290 + const { data: identity } = useQueryIdentity(targetdidorhandle); 291 + 292 + const theyFollowYouRes = useGetOneToOneState( 293 + agent?.did 294 + ? { 295 + target: agent?.did, 296 + user: identity?.did ?? targetdidorhandle, 297 + collection: "app.bsky.graph.follow", 298 + path: ".subject", 299 + } 300 + : undefined 301 + ); 302 + 303 + const youFollowThemRes = useGetFollowState({ 304 + target: identity?.did ?? targetdidorhandle, 305 + user: agent?.did, 306 + }); 307 + 308 + const theyFollowYou: boolean = 309 + !!theyFollowYouRes?.length && theyFollowYouRes.length > 0; 310 + const youFollowThem: boolean = 311 + !!youFollowThemRes?.length && youFollowThemRes.length > 0; 312 + 313 + return ( 314 + <> 315 + {/* if not self */} 316 + {identity?.did !== agent?.did ? ( 317 + <> 318 + {theyFollowYou ? ( 319 + <> 320 + {youFollowThem ? ( 321 + <div className=" text-sm px-1.5 py-0.5 text-gray-500 bg-gray-200 dark:text-gray-400 dark:bg-gray-800 rounded-lg flex flex-row items-center justify-center"> 322 + mutuals 323 + </div> 324 + ) : ( 325 + <div className=" text-sm px-1.5 py-0.5 text-gray-500 bg-gray-200 dark:text-gray-400 dark:bg-gray-800 rounded-lg flex flex-row items-center justify-center"> 326 + follows you 327 + </div> 328 + )} 329 + </> 330 + ) : ( 331 + <></> 332 + )} 333 + </> 334 + ) : ( 335 + // lmao can someone be mutuals with themselves ?? 336 + <></> 337 + )} 338 + </> 339 + ); 340 + } 341 + 342 + export function RichTextRenderer({ description }: { description: string }) { 343 + const [richDescription, setRichDescription] = useState<string | ReactNode[]>( 344 + description 345 + ); 346 + const { agent } = useAuth(); 347 + const navigate = useNavigate(); 348 + 349 + useEffect(() => { 350 + let mounted = true; 351 + 352 + // setRichDescription(description); 353 + 354 + async function processRichText() { 355 + try { 356 + if (!agent?.did) return; 357 + const rt = new RichText({ text: description }); 358 + await rt.detectFacets(agent); 359 + 360 + if (!mounted) return; 361 + 362 + if (rt.facets) { 363 + setRichDescription( 364 + renderTextWithFacets({ text: rt.text, facets: rt.facets, navigate }) 365 + ); 366 + } else { 367 + setRichDescription(rt.text); 368 + } 369 + } catch (error) { 370 + console.error("Failed to detect facets:", error); 371 + if (mounted) { 372 + setRichDescription(description); 373 + } 374 + } 375 + } 376 + 377 + processRichText(); 378 + 379 + return () => { 380 + mounted = false; 381 + }; 382 + }, [description, agent, navigate]); 383 + 384 + return <>{richDescription}</>; 385 + }
+165
src/routes/profile.$did/post.$rkey.image.$i.tsx
··· 1 + import { 2 + createFileRoute, 3 + useNavigate, 4 + type UseNavigateResult, 5 + } from "@tanstack/react-router"; 6 + import { useEffect, useState } from "react"; 7 + import { createPortal } from "react-dom"; 8 + 9 + import { ProfilePostComponent } from "./post.$rkey"; 10 + 11 + export const Route = createFileRoute("/profile/$did/post/$rkey/image/$i")({ 12 + component: Lightbox, 13 + }); 14 + 15 + export type LightboxProps = { 16 + images: { src: string; alt?: string }[]; 17 + }; 18 + 19 + function nextprev({ 20 + index, 21 + images, 22 + navigate, 23 + did, 24 + rkey, 25 + prev, 26 + }: { 27 + index?: number; 28 + images?: LightboxProps["images"]; 29 + navigate: UseNavigateResult<string>; 30 + did: string; 31 + rkey: string; 32 + prev?: boolean; 33 + }) { 34 + const len = images?.length ?? 0; 35 + if (len === 0) return; 36 + 37 + const nextIndex = ((index ?? 0) + (prev ? -1 : 1) + len) % len; 38 + 39 + navigate({ 40 + to: "/profile/$did/post/$rkey/image/$i", 41 + params: { 42 + did, 43 + rkey, 44 + i: nextIndex.toString(), 45 + }, 46 + replace: true, 47 + }); 48 + } 49 + 50 + export function Lightbox() { 51 + console.log("hey the $i route is loaded w!!!"); 52 + const { did, rkey, i } = Route.useParams(); 53 + const [images, setImages] = useState<LightboxProps["images"] | undefined>( 54 + undefined 55 + ); 56 + const index = Number(i); 57 + const navigate = useNavigate(); 58 + const post = true; 59 + const image = images?.[index] ?? undefined; 60 + 61 + function lightboxCallback(d: LightboxProps) { 62 + console.log("callback actually called!"); 63 + setImages(d.images); 64 + } 65 + 66 + useEffect(() => { 67 + function handleKey(e: KeyboardEvent) { 68 + if (e.key === "Escape") window.history.back(); 69 + if (e.key === "ArrowRight") 70 + nextprev({ index, images, navigate, did, rkey }); 71 + //onNavigate((index + 1) % images.length); 72 + if (e.key === "ArrowLeft") 73 + nextprev({ index, images, navigate, did, rkey, prev: true }); 74 + //onNavigate((index - 1 + images.length) % images.length); 75 + } 76 + window.addEventListener("keydown", handleKey); 77 + return () => window.removeEventListener("keydown", handleKey); 78 + }, [index, navigate, did, rkey, images]); 79 + 80 + return createPortal( 81 + <> 82 + {post && ( 83 + <div 84 + onClick={(e) => { 85 + e.stopPropagation(); 86 + e.nativeEvent.stopImmediatePropagation(); 87 + }} 88 + className="lightbox-sidebar hidden lg:flex overscroll-none disablegutter disablescroll border-l dark:border-gray-800 was7 border-gray-300 fixed z-50 top-0 right-0 flex-col max-w-[350px] min-w-[350px] max-h-screen overflow-y-scroll dark:bg-gray-950 bg-white" 89 + > 90 + <ProfilePostComponent 91 + key={`/profile/${did}/post/${rkey}`} 92 + did={did} 93 + rkey={rkey} 94 + nopics 95 + lightboxCallback={lightboxCallback} 96 + /> 97 + </div> 98 + )} 99 + <div 100 + className="lightbox fixed inset-0 z-50 flex items-center justify-center bg-black/80 w-screen lg:w-[calc(100vw-350px)] lg:max-w-[calc(100vw-350px)]" 101 + onClick={(e) => { 102 + e.stopPropagation(); 103 + window.history.back(); 104 + }} 105 + > 106 + <img 107 + src={image?.src} 108 + alt={image?.alt} 109 + className="max-h-[90%] max-w-[90%] object-contain rounded-lg shadow-lg" 110 + onClick={(e) => e.stopPropagation()} 111 + /> 112 + 113 + {(images?.length ?? 0) > 1 && ( 114 + <> 115 + <button 116 + onClick={(e) => { 117 + e.stopPropagation(); 118 + nextprev({ index, images, navigate, did, rkey, prev: true }); 119 + }} 120 + className="absolute left-4 top-1/2 -translate-y-1/2 text-white text-4xl h-8 w-8 rounded-full bg-gray-900 flex items-center justify-center" 121 + > 122 + <svg 123 + xmlns="http://www.w3.org/2000/svg" 124 + width={28} 125 + height={28} 126 + viewBox="0 0 24 24" 127 + > 128 + <g fill="none" fillRule="evenodd"> 129 + <path d="M24 0v24H0V0zM12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.019-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"></path> 130 + <path 131 + fill="currentColor" 132 + d="M8.293 12.707a1 1 0 0 1 0-1.414l5.657-5.657a1 1 0 1 1 1.414 1.414L10.414 12l4.95 4.95a1 1 0 0 1-1.414 1.414z" 133 + ></path> 134 + </g> 135 + </svg> 136 + </button> 137 + <button 138 + onClick={(e) => { 139 + e.stopPropagation(); 140 + nextprev({ index, images, navigate, did, rkey }); 141 + }} 142 + className="absolute right-4 top-1/2 -translate-y-1/2 text-white text-4xl h-8 w-8 rounded-full bg-gray-900 flex items-center justify-center" 143 + > 144 + <svg 145 + xmlns="http://www.w3.org/2000/svg" 146 + width={28} 147 + height={28} 148 + viewBox="0 0 24 24" 149 + > 150 + <g fill="none" fillRule="evenodd"> 151 + <path d="M24 0v24H0V0zM12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.019-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"></path> 152 + <path 153 + fill="currentColor" 154 + d="M15.707 11.293a1 1 0 0 1 0 1.414l-5.657 5.657a1 1 0 1 1-1.414-1.414l4.95-4.95l-4.95-4.95a1 1 0 0 1 1.414-1.414z" 155 + ></path> 156 + </g> 157 + </svg> 158 + </button> 159 + </> 160 + )} 161 + </div> 162 + </>, 163 + document.body 164 + ); 165 + }
+482 -143
src/routes/profile.$did/post.$rkey.tsx
··· 1 - import { createFileRoute, Link } from '@tanstack/react-router'; 2 - import React from 'react'; 3 - import { UniversalPostRendererATURILoader, cachedGetRecord } from '~/components/UniversalPostRenderer'; 4 - import { usePersistentStore } from '~/providers/PersistentStoreProvider'; 1 + import { AtUri } from "@atproto/api"; 2 + import { useInfiniteQuery, useQueryClient } from "@tanstack/react-query"; 3 + import { createFileRoute, Outlet } from "@tanstack/react-router"; 4 + import { useAtom } from "jotai"; 5 + import React, { useLayoutEffect } from "react"; 5 6 6 - const HANDLE_DID_CACHE_TIMEOUT = 60 * 60 * 1000; // 1 hour 7 + import { Header } from "~/components/Header"; 8 + import { UniversalPostRendererATURILoader } from "~/components/UniversalPostRenderer"; 9 + import { constellationURLAtom, slingshotURLAtom } from "~/utils/atoms"; 10 + //import { usePersistentStore } from '~/providers/PersistentStoreProvider'; 11 + import { 12 + constructPostQuery, 13 + type linksAllResponse, 14 + type linksRecordsResponse, 15 + useQueryConstellation, 16 + useQueryIdentity, 17 + useQueryPost, 18 + yknowIReallyHateThisButWhateverGuardedConstructConstellationInfiniteQueryLinks, 19 + } from "~/utils/useQuery"; 7 20 8 - export const Route = createFileRoute('/profile/$did/post/$rkey')({ 21 + import type { LightboxProps } from "./post.$rkey.image.$i"; 22 + 23 + //const HANDLE_DID_CACHE_TIMEOUT = 60 * 60 * 1000; // 1 hour 24 + 25 + export const Route = createFileRoute("/profile/$did/post/$rkey")({ 9 26 component: RouterWrapper, 10 27 }); 11 28 12 29 function RouterWrapper() { 13 30 const { did, rkey } = Route.useParams(); 14 31 15 - return <ProfilePostComponent key={`/profile/${did}/post/${rkey}`} did={did} rkey={rkey} />; 32 + return ( 33 + <> 34 + <ProfilePostComponent 35 + key={`/profile/${did}/post/${rkey}`} 36 + did={did} 37 + rkey={rkey} 38 + /> 39 + {/* <ShrinkingBox /> */} 40 + </> 41 + ); 16 42 } 17 43 18 - function ProfilePostComponent({ did, rkey }: { did: string; rkey: string }) { 19 - const { get, set } = usePersistentStore(); 20 - const [resolvedDid, setResolvedDid] = React.useState<string | null>(null); 21 - const [loading, setLoading] = React.useState(false); 22 - const [error, setError] = React.useState<string | null>(null); 44 + export function ProfilePostComponent({ 45 + did, 46 + rkey, 47 + nopics, 48 + lightboxCallback, 49 + }: { 50 + did: string; 51 + rkey: string; 52 + nopics?: boolean; 53 + lightboxCallback?: (d: LightboxProps) => void; 54 + }) { 55 + //const { get, set } = usePersistentStore(); 56 + const queryClient = useQueryClient(); 57 + // const [resolvedDid, setResolvedDid] = React.useState<string | null>(null); 58 + // const [loading, setLoading] = React.useState(false); 59 + // const [error, setError] = React.useState<string | null>(null); 60 + 61 + // const [mainPost, setMainPost] = React.useState<any | null>(null); 62 + // const [parents, setParents] = React.useState<any[]>([]); 63 + // const [parentsLoading, setParentsLoading] = React.useState(false); 64 + // const [replies, setReplies] = React.useState<any[]>([]); 65 + 66 + // React.useEffect(() => { 67 + // let ignore = false; 68 + // async function resolveDidIfNeeded() { 69 + // if (!did) { 70 + // setResolvedDid(null); 71 + // return; 72 + // } 73 + // if (did.startsWith('did:')) { 74 + // setResolvedDid(did); 75 + // return; 76 + // } 77 + // setLoading(true); 78 + // setError(null); 79 + // const cacheKey = `handleDid:${did}`; 80 + // const now = Date.now(); 81 + // const cached = await get(cacheKey); // <-- await here 82 + // if (cached && cached.value && cached.time && now - cached.time < HANDLE_DID_CACHE_TIMEOUT) { 83 + // try { 84 + // const data = JSON.parse(cached.value); 85 + // if (!ignore) setResolvedDid(data.did); 86 + // setLoading(false); 87 + // return; 88 + // } catch {} 89 + // } 90 + // try { 91 + // const url = `https://free-fly-24.deno.dev/?handle=${encodeURIComponent(did)}`; 92 + // const res = await fetch(url); 93 + // if (!res.ok) throw new Error('Failed to resolve handle'); 94 + // const data = await res.json(); 95 + // await set(cacheKey, JSON.stringify(data)); // <-- await here 96 + // if (!ignore) setResolvedDid(data.did); 97 + // } catch (e: any) { 98 + // if (!ignore) setError('Failed to resolve handle: ' + (e?.message || e)); 99 + // } finally { 100 + // setLoading(false); 101 + // } 102 + // } 103 + // resolveDidIfNeeded(); 104 + // return () => { 105 + // ignore = true; 106 + // }; 107 + // }, [did, get, set]); 108 + 109 + // const atUri = resolvedDid && rkey ? `at://${decodeURIComponent(resolvedDid)}/app.bsky.feed.post/${rkey}` : ''; 110 + 111 + // React.useEffect(() => { 112 + // if (!atUri) return; 113 + // let ignore = false; 114 + // async function fetchMainPost() { 115 + // try { 116 + // const postData = await cachedGetRecord({ atUri, get, set }); 117 + // if (!ignore) { 118 + // setMainPost(postData); 119 + // } 120 + // } catch (e) { 121 + // console.error('Failed to fetch main post record:', e); 122 + // } 123 + // } 124 + // fetchMainPost(); 125 + // return () => { 126 + // ignore = true; 127 + // }; 128 + // }, [atUri, get, set]); 129 + 130 + // React.useEffect(() => { 131 + // if (!mainPost) return; 132 + // let ignore = false; 133 + // async function fetchParents() { 134 + // setParentsLoading(true); 135 + // const parentChain: any[] = []; 136 + // let currentParentUri = mainPost.value?.reply?.parent?.uri; 137 + // const MAX_PARENTS = 25; // Important to know theres a limit 138 + // let safetyCounter = 0; 139 + 140 + // while (currentParentUri && safetyCounter < MAX_PARENTS) { 141 + // try { 142 + // const parentPost = await cachedGetRecord({ atUri: currentParentUri, get, set }); 143 + // if (!parentPost) break; 144 + // parentChain.push(parentPost); 145 + // currentParentUri = parentPost.value?.reply?.parent?.uri; 146 + // safetyCounter++; 147 + // } catch (error) { 148 + // console.error('Failed to fetch a parent post:', error); 149 + // break; 150 + // } 151 + // } 152 + 153 + // if (!ignore) { 154 + // setParents(parentChain.reverse()); 155 + // setParentsLoading(false); 156 + // } 157 + // } 158 + 159 + // fetchParents(); 160 + // return () => { 161 + // ignore = true; 162 + // }; 163 + // }, [mainPost, get, set]); 23 164 24 - const [mainPost, setMainPost] = React.useState<any | null>(null); 25 - const [parents, setParents] = React.useState<any[]>([]); 26 - const [parentsLoading, setParentsLoading] = React.useState(false); 27 - const [replies, setReplies] = React.useState<any[]>([]); 165 + // React.useEffect(() => { 166 + // if (!atUri) return; 167 + // let ignore = false; 168 + // async function fetchReplies() { 169 + // try { 170 + // const url = `https://constellation.microcosm.blue/links?target=${encodeURIComponent( 171 + // atUri, 172 + // )}&collection=app.bsky.feed.post&path=.reply.parent.uri`; 173 + // const res = await fetch(url); 174 + // if (!res.ok) throw new Error('Failed to fetch replies'); 175 + // const data = await res.json(); 176 + // if (!ignore && data.linking_records) { 177 + // setReplies(data.linking_records.slice(0, 50)); 178 + // } 179 + // } catch (e) { 180 + // if (!ignore) setReplies([]); 181 + // } 182 + // } 183 + // fetchReplies(); 184 + // return () => { 185 + // ignore = true; 186 + // }; 187 + // }, [atUri]); 188 + 189 + const { 190 + data: identity, 191 + isLoading: isIdentityLoading, 192 + error: identityError, 193 + } = useQueryIdentity(did); 194 + 195 + const resolvedDid = did.startsWith("did:") ? did : identity?.did; 196 + 197 + const atUri = React.useMemo( 198 + () => 199 + resolvedDid 200 + ? `at://${decodeURIComponent(resolvedDid)}/app.bsky.feed.post/${rkey}` 201 + : undefined, 202 + [resolvedDid, rkey] 203 + ); 204 + 205 + const { data: mainPost } = useQueryPost(atUri); 206 + 207 + console.log("atUri",atUri) 208 + 209 + const opdid = React.useMemo( 210 + () => 211 + atUri 212 + ? new AtUri(atUri).host 213 + : undefined, 214 + [atUri] 215 + ); 216 + 217 + // @ts-expect-error i hate overloads 218 + const { data: links } = useQueryConstellation(atUri?{ 219 + method: "/links/all", 220 + target: atUri, 221 + } : { 222 + method: "undefined", 223 + target: "" 224 + })as { data: linksAllResponse | undefined }; 225 + 226 + //const [likes, setLikes] = React.useState<number | null>(null); 227 + //const [reposts, setReposts] = React.useState<number | null>(null); 228 + const [replyCount, setReplyCount] = React.useState<number | null>(null); 28 229 29 230 React.useEffect(() => { 30 - let ignore = false; 31 - async function resolveDidIfNeeded() { 32 - if (!did) { 33 - setResolvedDid(null); 34 - return; 231 + // /*mass comment*/ console.log(JSON.stringify(links, null, 2)); 232 + // setLikes( 233 + // links 234 + // ? links?.links?.["app.bsky.feed.like"]?.[".subject.uri"]?.records || 0 235 + // : null 236 + // ); 237 + // setReposts( 238 + // links 239 + // ? links?.links?.["app.bsky.feed.repost"]?.[".subject.uri"]?.records || 0 240 + // : null 241 + // ); 242 + setReplyCount( 243 + links 244 + ? links?.links?.["app.bsky.feed.post"]?.[".reply.parent.uri"] 245 + ?.records || 0 246 + : null 247 + ); 248 + }, [links]); 249 + 250 + const { data: opreplies } = useQueryConstellation( 251 + !!opdid && replyCount && replyCount >= 25 252 + ? { 253 + method: "/links", 254 + target: atUri, 255 + // @ts-expect-error overloading sucks so much 256 + collection: "app.bsky.feed.post", 257 + path: ".reply.parent.uri", 258 + //cursor?: string; 259 + dids: [opdid], 260 + } 261 + : { 262 + method: "undefined", 263 + target: "", 264 + } 265 + ) as { data: linksRecordsResponse | undefined }; 266 + 267 + const opReplyAturis = 268 + opreplies?.linking_records.map( 269 + (r) => `at://${r.did}/${r.collection}/${r.rkey}`, 270 + ) ?? []; 271 + 272 + 273 + // const { data: repliesData } = useQueryConstellation({ 274 + // method: "/links", 275 + // target: atUri, 276 + // collection: "app.bsky.feed.post", 277 + // path: ".reply.parent.uri", 278 + // }); 279 + // const replies = repliesData?.linking_records.slice(0, 50) ?? []; 280 + const [constellationurl] = useAtom(constellationURLAtom) 281 + 282 + const infinitequeryresults = useInfiniteQuery({ 283 + ...yknowIReallyHateThisButWhateverGuardedConstructConstellationInfiniteQueryLinks( 284 + { 285 + constellation: constellationurl, 286 + method: "/links", 287 + target: atUri, 288 + collection: "app.bsky.feed.post", 289 + path: ".reply.parent.uri", 35 290 } 36 - if (did.startsWith('did:')) { 37 - setResolvedDid(did); 38 - return; 39 - } 40 - setLoading(true); 41 - setError(null); 42 - const cacheKey = `handleDid:${did}`; 43 - const now = Date.now(); 44 - const cached = await get(cacheKey); // <-- await here 45 - if (cached && cached.value && cached.time && now - cached.time < HANDLE_DID_CACHE_TIMEOUT) { 46 - try { 47 - const data = JSON.parse(cached.value); 48 - if (!ignore) setResolvedDid(data.did); 49 - setLoading(false); 50 - return; 51 - } catch {} 291 + ), 292 + enabled: !!atUri, 293 + }); 294 + 295 + const { 296 + data: infiniteRepliesData, 297 + fetchNextPage, 298 + hasNextPage, 299 + isFetchingNextPage, 300 + } = infinitequeryresults; 301 + 302 + // // auto-fetch all pages 303 + // useEffect(() => { 304 + // if ( 305 + // infinitequeryresults.hasNextPage && 306 + // !infinitequeryresults.isFetchingNextPage 307 + // ) { 308 + // console.log("Fetching the next page..."); 309 + // infinitequeryresults.fetchNextPage(); 310 + // } 311 + // }, [infinitequeryresults]); 312 + 313 + // const replyAturis = repliesData 314 + // ? repliesData.pages.flatMap((page) => 315 + // page 316 + // ? page.linking_records.map((record) => { 317 + // const aturi = `at://${record.did}/${record.collection}/${record.rkey}`; 318 + // return aturi; 319 + // }) 320 + // : [] 321 + // ) 322 + // : []; 323 + 324 + const replyAturis = React.useMemo(() => { 325 + // Get all replies from the standard infinite query 326 + const allReplies = 327 + infiniteRepliesData?.pages.flatMap( 328 + (page) => 329 + page?.linking_records.map( 330 + (r) => `at://${r.did}/${r.collection}/${r.rkey}`, 331 + ) ?? [], 332 + ) ?? []; 333 + 334 + if (replyCount && (replyCount < 25)) { 335 + // If count is low, just use the standard list and find the oldest OP reply to move to the top 336 + const opdidFromUri = atUri ? new AtUri(atUri).host : undefined; 337 + const oldestOpsIndex = allReplies.findIndex( 338 + (aturi) => new AtUri(aturi).host === opdidFromUri, 339 + ); 340 + if (oldestOpsIndex > 0) { 341 + const [oldestOpsReply] = allReplies.splice(oldestOpsIndex, 1); 342 + allReplies.unshift(oldestOpsReply); 52 343 } 53 - try { 54 - const url = `https://free-fly-24.deno.dev/?handle=${encodeURIComponent(did)}`; 55 - const res = await fetch(url); 56 - if (!res.ok) throw new Error('Failed to resolve handle'); 57 - const data = await res.json(); 58 - await set(cacheKey, JSON.stringify(data)); // <-- await here 59 - if (!ignore) setResolvedDid(data.did); 60 - } catch (e: any) { 61 - if (!ignore) setError('Failed to resolve handle: ' + (e?.message || e)); 62 - } finally { 63 - setLoading(false); 344 + return allReplies; 345 + } else { 346 + // If count is high, prioritize OP replies from the special query 347 + // and filter them out from the main list to avoid duplication. 348 + const opReplySet = new Set(opReplyAturis); 349 + const otherReplies = allReplies.filter((uri) => !opReplySet.has(uri)); 350 + return [...opReplyAturis, ...otherReplies]; 351 + } 352 + }, [infiniteRepliesData, opReplyAturis, replyCount, atUri]); 353 + 354 + // Find oldest OP reply 355 + const oldestOpsIndex = replyAturis.findIndex( 356 + (aturi) => new AtUri(aturi).host === opdid 357 + ); 358 + 359 + // Reorder: move oldest OP reply to the front 360 + if (oldestOpsIndex > 0) { 361 + const [oldestOpsReply] = replyAturis.splice(oldestOpsIndex, 1); 362 + replyAturis.unshift(oldestOpsReply); 363 + } 364 + 365 + const [parents, setParents] = React.useState<any[]>([]); 366 + const [parentsLoading, setParentsLoading] = React.useState(false); 367 + 368 + const mainPostRef = React.useRef<HTMLDivElement>(null); 369 + const hasPerformedInitialLayout = React.useRef(false); 370 + 371 + const [layoutReady, setLayoutReady] = React.useState(false); 372 + 373 + useLayoutEffect(() => { 374 + if (parents.length > 0 && !layoutReady && mainPostRef.current) { 375 + const mainPostElement = mainPostRef.current; 376 + 377 + if (window.scrollY === 0 && !hasPerformedInitialLayout.current) { 378 + const elementTop = mainPostElement.getBoundingClientRect().top; 379 + const headerOffset = 70; 380 + 381 + const targetScrollY = elementTop - headerOffset; 382 + 383 + window.scrollBy(0, targetScrollY); 384 + 385 + hasPerformedInitialLayout.current = true; 64 386 } 387 + 388 + // todo idk what to do with this 389 + // eslint-disable-next-line react-hooks/set-state-in-effect 390 + setLayoutReady(true); 65 391 } 66 - resolveDidIfNeeded(); 67 - return () => { 68 - ignore = true; 69 - }; 70 - }, [did, get, set]); 392 + }, [parents, layoutReady]); 71 393 72 - const atUri = resolvedDid && rkey ? `at://${decodeURIComponent(resolvedDid)}/app.bsky.feed.post/${rkey}` : ''; 73 394 395 + const [slingshoturl] = useAtom(slingshotURLAtom) 396 + 74 397 React.useEffect(() => { 75 - if (!atUri) return; 76 - let ignore = false; 77 - async function fetchMainPost() { 78 - try { 79 - const postData = await cachedGetRecord({ atUri, get, set }); 80 - if (!ignore) { 81 - setMainPost(postData); 82 - } 83 - } catch (e) { 84 - console.error('Failed to fetch main post record:', e); 85 - } 398 + if (parentsLoading) { 399 + setLayoutReady(false); 86 400 } 87 - fetchMainPost(); 88 - return () => { 89 - ignore = true; 90 - }; 91 - }, [atUri, get, set]); 401 + 402 + if (!mainPost?.value?.reply?.parent?.uri && !parentsLoading) { 403 + setLayoutReady(true); 404 + hasPerformedInitialLayout.current = true; 405 + } 406 + }, [parentsLoading, mainPost]); 92 407 93 408 React.useEffect(() => { 94 - if (!mainPost) return; 409 + if (!mainPost?.value?.reply?.parent?.uri) { 410 + setParents([]); 411 + return; 412 + } 413 + 95 414 let ignore = false; 96 - async function fetchParents() { 415 + const fetchParents = async () => { 97 416 setParentsLoading(true); 98 417 const parentChain: any[] = []; 99 - let currentParentUri = mainPost.value?.reply?.parent?.uri; 100 - const MAX_PARENTS = 25; // Important to know theres a limit 418 + let currentParentUri = mainPost?.value.reply?.parent.uri; 419 + const MAX_PARENTS = 25; 101 420 let safetyCounter = 0; 102 421 103 422 while (currentParentUri && safetyCounter < MAX_PARENTS) { 104 423 try { 105 - const parentPost = await cachedGetRecord({ atUri: currentParentUri, get, set }); 424 + const parentPost = await queryClient.fetchQuery( 425 + constructPostQuery(currentParentUri, slingshoturl) 426 + ); 106 427 if (!parentPost) break; 107 428 parentChain.push(parentPost); 108 429 currentParentUri = parentPost.value?.reply?.parent?.uri; 109 - safetyCounter++; 110 430 } catch (error) { 111 - console.error('Failed to fetch a parent post:', error); 431 + console.error("Failed to fetch a parent post:", error); 112 432 break; 113 433 } 434 + safetyCounter++; 114 435 } 115 436 116 437 if (!ignore) { 117 438 setParents(parentChain.reverse()); 118 439 setParentsLoading(false); 119 440 } 120 - } 441 + }; 121 442 122 443 fetchParents(); 123 444 return () => { 124 445 ignore = true; 125 446 }; 126 - }, [mainPost, get, set]); 127 - 128 - React.useEffect(() => { 129 - if (!atUri) return; 130 - let ignore = false; 131 - async function fetchReplies() { 132 - try { 133 - const url = `https://constellation.microcosm.blue/links?target=${encodeURIComponent( 134 - atUri, 135 - )}&collection=app.bsky.feed.post&path=.reply.parent.uri`; 136 - const res = await fetch(url); 137 - if (!res.ok) throw new Error('Failed to fetch replies'); 138 - const data = await res.json(); 139 - if (!ignore && data.linking_records) { 140 - setReplies(data.linking_records.slice(0, 50)); 141 - } 142 - } catch (e) { 143 - if (!ignore) setReplies([]); 144 - } 145 - } 146 - fetchReplies(); 147 - return () => { 148 - ignore = true; 149 - }; 150 - }, [atUri]); 447 + }, [mainPost, queryClient]); 151 448 152 449 if (!did || !rkey) return <div>Invalid post URI</div>; 153 - if (loading) return <div>Resolving handle...</div>; 154 - if (error) return <div style={{ color: 'red' }}>{error}</div>; 155 - if (!atUri) return <div>Invalid post URI</div>; 450 + if (isIdentityLoading) return <div>Resolving handle...</div>; 451 + if (identityError) 452 + return <div style={{ color: "red" }}>{identityError.message}</div>; 453 + if (!atUri) return <div>Could not construct post URI.</div>; 156 454 157 455 return ( 158 456 <> 159 - <div className="flex items-center gap-2 px-4 py-2 h-[52px] sticky top-0 bg-white dark:bg-gray-950 z-10 border-b border-gray-200 dark:border-gray-700"> 160 - <Link 161 - to=".." 162 - className="px-3 py-1 rounded hover:bg-gray-100 dark:hover:bg-gray-900 font-bold text-lg" 163 - onClick={e => { 164 - e.preventDefault(); 165 - window.history.length > 1 ? window.history.back() : window.location.assign('/'); 166 - }} 167 - aria-label="Go back" 168 - > 169 - โ† 170 - </Link> 171 - <span className="text-xl font-bold ml-2">Post</span> 172 - </div> 457 + <Outlet /> 458 + <Header 459 + title={`Post`} 460 + backButtonCallback={() => { 461 + if (window.history.length > 1) { 462 + window.history.back(); 463 + } else { 464 + window.location.assign("/"); 465 + } 466 + }} 467 + /> 173 468 174 - {parentsLoading && <div className="p-4 text-center text-gray-500 dark:text-gray-400">Loading conversation...</div>} 469 + {parentsLoading && ( 470 + <div className="text-center text-gray-500 dark:text-gray-400 flex flex-row"> 471 + <div className="ml-4 w-[42px] flex justify-center"> 472 + <div 473 + style={{ width: 2, height: "100%", opacity: 0.5 }} 474 + className="bg-gray-500 dark:bg-gray-400" 475 + ></div> 476 + </div> 477 + Loading conversation... 478 + </div> 479 + )} 175 480 176 481 {/* we should use the reply lines here thats provided by UPR*/} 177 - <div style={{ maxWidth: 600, margin: '0px auto 0', padding: 0 }}> 482 + <div style={{ maxWidth: 600, padding: 0 }}> 178 483 {parents.map((parent, index) => ( 179 - <UniversalPostRendererATURILoader key={parent.uri} atUri={parent.uri} 180 - topReplyLine={index > 0} 484 + <UniversalPostRendererATURILoader 485 + key={parent.uri} 486 + atUri={parent.uri} 487 + topReplyLine={index > 0} 181 488 bottomReplyLine={true} 182 489 bottomBorder={false} 183 - /> 490 + /> 184 491 ))} 185 492 </div> 186 - 187 - <UniversalPostRendererATURILoader atUri={atUri} detailed={true} topReplyLine={parents.length > 0} /> 188 - 189 - {replies.length > 0 && ( 190 - <div style={{ maxWidth: 600, margin: '0px auto 0', padding: 0 }}> 191 - <div 192 - className="text-gray-500 dark:text-gray-400 text-sm font-bold" 193 - style={{ fontSize: 18, margin: '12px 16px 12px 16px', fontWeight: 600 }} 194 - > 195 - Replies 196 - </div> 197 - <div style={{ display: 'flex', flexDirection: 'column', gap: 0 }}> 198 - {replies.map(reply => { 199 - const replyAtUri = `at://${reply.did}/app.bsky.feed.post/${reply.rkey}`; 200 - return <UniversalPostRendererATURILoader key={replyAtUri} atUri={replyAtUri} />; 493 + <div ref={mainPostRef}> 494 + <UniversalPostRendererATURILoader 495 + atUri={atUri} 496 + detailed={true} 497 + topReplyLine={parentsLoading || parents.length > 0} 498 + nopics={!!nopics} 499 + lightboxCallback={lightboxCallback} 500 + /> 501 + </div> 502 + <div 503 + style={{ 504 + maxWidth: 600, 505 + //margin: "0px auto 0", 506 + padding: 0, 507 + minHeight: "80dvh", 508 + paddingBottom: "20dvh", 509 + }} 510 + > 511 + <div 512 + className="text-gray-500 dark:text-gray-400 text-sm font-bold" 513 + style={{ 514 + fontSize: 18, 515 + margin: "12px 16px 12px 16px", 516 + fontWeight: 600, 517 + }} 518 + > 519 + Replies 520 + </div> 521 + <div style={{ display: "flex", flexDirection: "column", gap: 0 }}> 522 + {replyAturis.length > 0 && 523 + replyAturis.map((reply) => { 524 + //const replyAtUri = `at://${reply.did}/app.bsky.feed.post/${reply.rkey}`; 525 + return ( 526 + <UniversalPostRendererATURILoader 527 + key={reply} 528 + atUri={reply} 529 + maxReplies={4} 530 + /> 531 + ); 201 532 })} 202 - </div> 533 + {hasNextPage && ( 534 + <button 535 + onClick={() => fetchNextPage()} 536 + disabled={isFetchingNextPage} 537 + className="w-[calc(100%-2rem)] mx-4 my-4 px-4 py-2 bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-gray-200 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-700 font-semibold disabled:opacity-50" 538 + > 539 + {isFetchingNextPage ? "Loading..." : "Load More"} 540 + </button> 541 + )} 203 542 </div> 204 - )} 543 + </div> 205 544 </> 206 545 ); 207 - } 546 + }
+50 -1
src/routes/search.tsx
··· 1 1 import { createFileRoute } from "@tanstack/react-router"; 2 2 3 + import { Header } from "~/components/Header"; 4 + import { Import } from "~/components/Import"; 5 + 3 6 export const Route = createFileRoute("/search")({ 4 7 component: Search, 5 8 }); 6 9 7 10 export function Search() { 8 - return <div className="p-6">Search page (coming soon)</div>; 11 + return ( 12 + <> 13 + <Header 14 + title="Explore" 15 + backButtonCallback={() => { 16 + if (window.history.length > 1) { 17 + window.history.back(); 18 + } else { 19 + window.location.assign("/"); 20 + } 21 + }} 22 + /> 23 + <div className=" flex flex-col items-center mt-4 mx-4 gap-4"> 24 + <Import /> 25 + <div className="flex flex-col"> 26 + <p className="text-gray-600 dark:text-gray-400"> 27 + Sorry we dont have search. But instead, you can load some of these 28 + types of content into Red Dwarf: 29 + </p> 30 + <ul className="list-disc list-inside mt-2 text-gray-600 dark:text-gray-400"> 31 + <li> 32 + Bluesky URLs from supported clients (like{" "} 33 + <code className="text-sm">bsky.app</code> or{" "} 34 + <code className="text-sm">deer.social</code>). 35 + </li> 36 + <li> 37 + AT-URIs (e.g.,{" "} 38 + <code className="text-sm">at://did:example/collection/item</code> 39 + ). 40 + </li> 41 + <li> 42 + Plain handles (like{" "} 43 + <code className="text-sm">@username.bsky.social</code>). 44 + </li> 45 + <li> 46 + Direct DIDs (Decentralized Identifiers, starting with{" "} 47 + <code className="text-sm">did:</code>). 48 + </li> 49 + </ul> 50 + <p className="mt-2 text-gray-600 dark:text-gray-400"> 51 + Simply paste one of these into the import field above and press 52 + Enter to load the content. 53 + </p> 54 + </div> 55 + </div> 56 + </> 57 + ); 9 58 }
+181 -1
src/routes/settings.tsx
··· 1 1 import { createFileRoute } from "@tanstack/react-router"; 2 + import { useAtom } from "jotai"; 3 + import { Slider } from "radix-ui"; 4 + 5 + import { Header } from "~/components/Header"; 6 + import Login from "~/components/Login"; 7 + import { 8 + constellationURLAtom, 9 + defaultconstellationURL, 10 + defaulthue, 11 + defaultImgCDN, 12 + defaultslingshotURL, 13 + defaultVideoCDN, 14 + hueAtom, 15 + imgCDNAtom, 16 + slingshotURLAtom, 17 + videoCDNAtom, 18 + } from "~/utils/atoms"; 2 19 3 20 export const Route = createFileRoute("/settings")({ 4 21 component: Settings, 5 22 }); 6 23 7 24 export function Settings() { 8 - return <div className="p-6">Settings page (coming soon)</div>; 25 + return ( 26 + <> 27 + <Header 28 + title="Settings" 29 + backButtonCallback={() => { 30 + if (window.history.length > 1) { 31 + window.history.back(); 32 + } else { 33 + window.location.assign("/"); 34 + } 35 + }} 36 + /> 37 + <div className="lg:hidden"> 38 + <Login /> 39 + </div> 40 + <div className="h-4" /> 41 + <TextInputSetting 42 + atom={constellationURLAtom} 43 + title={"Constellation"} 44 + description={ 45 + "Customize the Constellation instance to be used by Red Dwarf" 46 + } 47 + init={defaultconstellationURL} 48 + /> 49 + <TextInputSetting 50 + atom={slingshotURLAtom} 51 + title={"Slingshot"} 52 + description={"Customize the Slingshot instance to be used by Red Dwarf"} 53 + init={defaultslingshotURL} 54 + /> 55 + <TextInputSetting 56 + atom={imgCDNAtom} 57 + title={"Image CDN"} 58 + description={ 59 + "Customize the Constellation instance to be used by Red Dwarf" 60 + } 61 + init={defaultImgCDN} 62 + /> 63 + <TextInputSetting 64 + atom={videoCDNAtom} 65 + title={"Video CDN"} 66 + description={"Customize the Slingshot instance to be used by Red Dwarf"} 67 + init={defaultVideoCDN} 68 + /> 69 + 70 + <Hue /> 71 + <p className="text-gray-500 dark:text-gray-400 py-4 px-6 text-sm"> 72 + please restart/refresh the app if changes arent applying correctly 73 + </p> 74 + </> 75 + ); 76 + } 77 + function Hue() { 78 + const [hue, setHue] = useAtom(hueAtom); 79 + return ( 80 + <div className="flex flex-col px-4 mt-4 "> 81 + <span className="z-10">Hue</span> 82 + <div className="flex flex-row items-center gap-4"> 83 + <SliderComponent 84 + atom={hueAtom} 85 + max={360} 86 + /> 87 + <button 88 + onClick={() => setHue(defaulthue ?? 28)} 89 + className="px-6 py-2 h-12 rounded-full bg-gray-100 dark:bg-gray-800 90 + text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-700 transition" 91 + > 92 + Reset 93 + </button> 94 + </div> 95 + </div> 96 + ); 9 97 } 98 + 99 + export function TextInputSetting({ 100 + atom, 101 + title, 102 + description, 103 + init, 104 + }: { 105 + atom: typeof constellationURLAtom; 106 + title?: string; 107 + description?: string; 108 + init?: string; 109 + }) { 110 + const [value, setValue] = useAtom(atom); 111 + return ( 112 + <div className="flex flex-col gap-2 px-4 py-2"> 113 + {/* <div> 114 + {title && ( 115 + <h3 className="text-sm font-medium text-gray-900 dark:text-gray-100"> 116 + {title} 117 + </h3> 118 + )} 119 + {description && ( 120 + <p className="text-sm text-gray-500 dark:text-gray-400"> 121 + {description} 122 + </p> 123 + )} 124 + </div> */} 125 + 126 + <div className="flex flex-row gap-2 items-center"> 127 + <div className="m3input-field m3input-label m3input-border size-md flex-1"> 128 + <input 129 + type="text" 130 + placeholder=" " 131 + value={value} 132 + onChange={(e) => setValue(e.target.value)} 133 + /> 134 + <label>{title}</label> 135 + </div> 136 + {/* <input 137 + type="text" 138 + value={value} 139 + onChange={(e) => setValue(e.target.value)} 140 + className="flex-1 px-3 py-2 rounded-lg bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-700 141 + text-gray-900 dark:text-gray-100 placeholder:text-gray-500 dark:placeholder:text-gray-400 142 + focus:outline-none focus:ring-2 focus:ring-gray-400 dark:focus:ring-gray-600" 143 + placeholder="Enter value..." 144 + /> */} 145 + <button 146 + onClick={() => setValue(init ?? "")} 147 + className="px-6 py-2 h-12 rounded-full bg-gray-100 dark:bg-gray-800 148 + text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-700 transition" 149 + > 150 + Reset 151 + </button> 152 + </div> 153 + </div> 154 + ); 155 + } 156 + 157 + 158 + interface SliderProps { 159 + atom: typeof hueAtom; 160 + min?: number; 161 + max?: number; 162 + step?: number; 163 + } 164 + 165 + export const SliderComponent: React.FC<SliderProps> = ({ 166 + atom, 167 + min = 0, 168 + max = 100, 169 + step = 1, 170 + }) => { 171 + 172 + const [value, setValue] = useAtom(atom) 173 + 174 + return ( 175 + <Slider.Root 176 + className="relative flex items-center w-full h-4" 177 + value={[value]} 178 + min={min} 179 + max={max} 180 + step={step} 181 + onValueChange={(v: number[]) => setValue(v[0])} 182 + > 183 + <Slider.Track className="relative flex-grow h-4 bg-gray-300 dark:bg-gray-700 rounded-full"> 184 + <Slider.Range className="absolute h-full bg-gray-500 dark:bg-gray-400 rounded-l-full rounded-r-none" /> 185 + </Slider.Track> 186 + <Slider.Thumb className="shadow-[0_0_0_8px_var(--color-white)] dark:shadow-[0_0_0_8px_var(--color-gray-950)] block w-[3px] h-12 bg-gray-500 dark:bg-gray-400 rounded-md focus:outline-none" /> 187 + </Slider.Root> 188 + ); 189 + };
+184 -13
src/styles/app.css
··· 1 + @import url('https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&family=Roboto:ital,wght@0,100..900;1,100..900&family=Spectral+SC:wght@500&display=swap'); 1 2 @import "tailwindcss"; 2 3 3 4 /* @theme { ··· 14 15 --color-gray-950: oklch(0.129 0.050 222.000); 15 16 } */ 16 17 18 + :root { 19 + --safe-hue: var(--tw-gray-hue, 28) 20 + } 21 + 17 22 @theme { 18 - --color-gray-50: oklch(0.984 0.012 28); 19 - --color-gray-100: oklch(0.968 0.017 28); 20 - --color-gray-200: oklch(0.929 0.025 28); 21 - --color-gray-300: oklch(0.869 0.035 28); 22 - --color-gray-400: oklch(0.704 0.05 28); 23 - --color-gray-500: oklch(0.554 0.06 28); 24 - --color-gray-600: oklch(0.446 0.058 28); 25 - --color-gray-700: oklch(0.372 0.058 28); 26 - --color-gray-800: oklch(0.279 0.055 28); 27 - --color-gray-900: oklch(0.208 0.055 28); 28 - --color-gray-950: oklch(0.129 0.055 28); 23 + --color-gray-50: oklch(0.984 0.012 var(--safe-hue)); 24 + --color-gray-100: oklch(0.968 0.017 var(--safe-hue)); 25 + --color-gray-200: oklch(0.929 0.025 var(--safe-hue)); 26 + --color-gray-300: oklch(0.869 0.035 var(--safe-hue)); 27 + --color-gray-400: oklch(0.704 0.05 var(--safe-hue)); 28 + --color-gray-500: oklch(0.554 0.06 var(--safe-hue)); 29 + --color-gray-600: oklch(0.446 0.058 var(--safe-hue)); 30 + --color-gray-700: oklch(0.372 0.058 var(--safe-hue)); 31 + --color-gray-800: oklch(0.279 0.055 var(--safe-hue)); 32 + --color-gray-900: oklch(0.208 0.055 var(--safe-hue)); 33 + --color-gray-950: oklch(0.129 0.055 var(--safe-hue)); 29 34 } 30 35 31 36 @layer base { ··· 47 52 } 48 53 } 49 54 55 + .gutter{ 56 + scrollbar-gutter: stable both-edges; 57 + } 58 + 50 59 @media (width >= 64rem /* 1024px */) { 51 - html, 52 - body { 60 + html:not(:has(.disablegutter)), 61 + body:not(:has(.disablegutter)) { 53 62 scrollbar-gutter: stable both-edges !important; 54 63 } 64 + html:has(.disablescroll), 65 + body:has(.disablescroll) { 66 + scrollbar-width: none; 67 + overflow-y: hidden; 68 + } 69 + } 70 + 71 + .lightbox:has(+.lightbox-sidebar){ 72 + opacity: 0; 55 73 } 74 + 56 75 .scroll-thin { 57 76 scrollbar-width: thin; 58 77 /*scrollbar-gutter: stable both-edges !important;*/ ··· 61 80 .scroll-none { 62 81 scrollbar-width: none; 63 82 } 83 + 84 + .dangerousFediContent { 85 + & a[href]{ 86 + text-decoration: none; 87 + color: rgb(29, 122, 242); 88 + word-break: break-all; 89 + } 90 + } 91 + 92 + .font-inter { 93 + font-family: "Inter", sans-serif; 94 + } 95 + .font-roboto { 96 + font-family: "Roboto", sans-serif; 97 + } 98 + 99 + :root { 100 + --header-bg-light: color-mix(in srgb, var(--color-white) calc(var(--is-top) * 100%), var(--color-gray-50)); 101 + --header-bg-dark: color-mix(in srgb, var(--color-gray-950) calc(var(--is-top) * 100%), var(--color-gray-900)); 102 + } 103 + 104 + :root { 105 + --header-bg: var(--header-bg-light); 106 + } 107 + @media (prefers-color-scheme: dark) { 108 + :root { 109 + --header-bg: var(--header-bg-dark); 110 + } 111 + } 112 + 113 + :root { 114 + --shadow-opacity: calc(1 - var(--is-top)); 115 + --tw-shadow-header: 0 2px 8px hsl(0 0% 0% / calc(var(--shadow-opacity) * 0.15)); 116 + } 117 + 118 + 119 + /* m3 input */ 120 + :root { 121 + --m3input-radius: 6px; 122 + --m3input-border-width: .0625rem; 123 + --m3input-font-size: 16px; 124 + --m3input-transition: 150ms cubic-bezier(.2, .8, .2, 1); 125 + /* light theme */ 126 + --m3input-bg: var(--color-gray-50); 127 + --m3input-border-color: var(--color-gray-400); 128 + --m3input-label-color: var(--color-gray-500); 129 + --m3input-text-color: var(--color-gray-900); 130 + --m3input-focus-color: var(--color-gray-600); 131 + } 132 + 133 + @media (prefers-color-scheme: dark) { 134 + :root { 135 + --m3input-bg: var(--color-gray-950); 136 + --m3input-border-color: var(--color-gray-700); 137 + --m3input-label-color: var(--color-gray-400); 138 + --m3input-text-color: var(--color-gray-50); 139 + --m3input-focus-color: var(--color-gray-400); 140 + } 141 + } 142 + 143 + /* reset page *//* 144 + html, 145 + body { 146 + background: var(--m3input-bg); 147 + margin: 0; 148 + padding: 1rem; 149 + color: var(--m3input-text-color); 150 + font-family: system-ui, sans-serif; 151 + font-size: var(--m3input-font-size); 152 + }*/ 153 + 154 + /* base wrapper */ 155 + .m3input-field.m3input-label.m3input-border { 156 + position: relative; 157 + display: inline-block; 158 + width: 100%; 159 + /*max-width: 400px;*/ 160 + } 161 + 162 + /* size variants */ 163 + .m3input-field.size-sm { 164 + --m3input-h: 40px; 165 + } 166 + 167 + .m3input-field.size-md { 168 + --m3input-h: 48px; 169 + } 170 + 171 + .m3input-field.size-lg { 172 + --m3input-h: 56px; 173 + } 174 + 175 + .m3input-field.size-xl { 176 + --m3input-h: 64px; 177 + } 178 + 179 + .m3input-field.m3input-label.m3input-border:not(.size-sm):not(.size-md):not(.size-lg):not(.size-xl) { 180 + --m3input-h: 48px; 181 + } 182 + 183 + /* outlined input */ 184 + .m3input-field.m3input-label.m3input-border input { 185 + width: 100%; 186 + height: var(--m3input-h); 187 + border: var(--m3input-border-width) solid var(--m3input-border-color); 188 + border-radius: var(--m3input-radius); 189 + background: var(--m3input-bg); 190 + color: var(--m3input-text-color); 191 + font-size: var(--m3input-font-size); 192 + padding: 0 12px; 193 + box-sizing: border-box; 194 + outline: none; 195 + transition: border-color var(--m3input-transition), box-shadow var(--m3input-transition); 196 + } 197 + 198 + /* focus ring */ 199 + .m3input-field.m3input-label.m3input-border input:focus { 200 + border-color: var(--m3input-focus-color); 201 + /*box-shadow: 0 0 0 2px color-mix(in srgb, var(--focus-color) 20%, transparent);*/ 202 + } 203 + 204 + /* label */ 205 + .m3input-field.m3input-label.m3input-border label { 206 + position: absolute; 207 + left: 12px; 208 + top: 50%; 209 + transform: translateY(-50%); 210 + background: var(--m3input-bg); 211 + padding: 0 .25em; 212 + color: var(--m3input-label-color); 213 + pointer-events: none; 214 + transition: all var(--m3input-transition); 215 + } 216 + 217 + /* float on focus or when filled */ 218 + .m3input-field.m3input-label.m3input-border input:focus+label, 219 + .m3input-field.m3input-label.m3input-border input:not(:placeholder-shown)+label { 220 + top: 0; 221 + transform: translateY(-50%) scale(.78); 222 + left: 0; 223 + color: var(--m3input-focus-color); 224 + } 225 + 226 + /* placeholder trick */ 227 + .m3input-field.m3input-label.m3input-border input::placeholder { 228 + color: transparent; 229 + } 230 + 231 + /* radix i love you but like cmon man */ 232 + body[data-scroll-locked]{ 233 + margin-left: var(--removed-body-scroll-bar-size) !important; 234 + }
+82
src/utils/atoms.ts
··· 1 + import { atom, createStore, useAtomValue } from "jotai"; 2 + import { atomWithStorage } from "jotai/utils"; 3 + import { useEffect } from "react"; 4 + 5 + export const store = createStore(); 6 + 7 + export const quickAuthAtom = atomWithStorage<string | null>( 8 + "quickAuth", 9 + null 10 + ); 11 + 12 + export const selectedFeedUriAtom = atomWithStorage<string | null>( 13 + "selectedFeedUri", 14 + null 15 + ); 16 + 17 + //export const feedScrollPositionsAtom = atom<Record<string, number>>({}); 18 + 19 + export const feedScrollPositionsAtom = atomWithStorage<Record<string, number>>( 20 + "feedscrollpositions", 21 + {} 22 + ); 23 + 24 + export const likedPostsAtom = atomWithStorage<Record<string, string>>( 25 + "likedPosts", 26 + {} 27 + ); 28 + 29 + export const defaultconstellationURL = "constellation.microcosm.blue"; 30 + export const constellationURLAtom = atomWithStorage<string>( 31 + "constellationURL", 32 + defaultconstellationURL 33 + ); 34 + export const defaultslingshotURL = "slingshot.microcosm.blue"; 35 + export const slingshotURLAtom = atomWithStorage<string>( 36 + "slingshotURL", 37 + defaultslingshotURL 38 + ); 39 + export const defaultImgCDN = "cdn.bsky.app"; 40 + export const imgCDNAtom = atomWithStorage<string>("imgcdnurl", defaultImgCDN); 41 + export const defaultVideoCDN = "video.bsky.app"; 42 + export const videoCDNAtom = atomWithStorage<string>( 43 + "videocdnurl", 44 + defaultVideoCDN 45 + ); 46 + 47 + export const defaulthue = 28; 48 + export const hueAtom = atomWithStorage<number>("hue", defaulthue); 49 + 50 + export const isAtTopAtom = atom<boolean>(true); 51 + 52 + type ComposerState = 53 + | { kind: "closed" } 54 + | { kind: "root" } 55 + | { kind: "reply"; parent: string } 56 + | { kind: "quote"; subject: string }; 57 + export const composerAtom = atom<ComposerState>({ kind: "closed" }); 58 + 59 + //export const agentAtom = atom<Agent | null>(null); 60 + //export const authedAtom = atom<boolean>(false); 61 + 62 + export function useAtomCssVar(atom: typeof hueAtom, cssVar: string) { 63 + const value = useAtomValue(atom); 64 + 65 + useEffect(() => { 66 + document.documentElement.style.setProperty(cssVar, value.toString()); 67 + }, [value, cssVar]); 68 + 69 + useEffect(() => { 70 + document.documentElement.style.setProperty(cssVar, value.toString()); 71 + }, []); 72 + } 73 + 74 + hueAtom.onMount = (setAtom) => { 75 + const stored = localStorage.getItem("hue"); 76 + if (stored != null) setAtom(Number(stored)); 77 + }; 78 + // export function initAtomToCssVar(atom: typeof hueAtom, cssVar: string) { 79 + // const initial = store.get(atom); 80 + // console.log("atom get ", initial); 81 + // document.documentElement.style.setProperty(cssVar, initial.toString()); 82 + // }
+163
src/utils/followState.ts
··· 1 + import { type Agent,AtUri } from "@atproto/api"; 2 + import { TID } from "@atproto/common-web"; 3 + import type { QueryClient } from "@tanstack/react-query"; 4 + 5 + import { type linksRecordsResponse,useQueryConstellation } from "./useQuery"; 6 + 7 + export function useGetFollowState({ 8 + target, 9 + user, 10 + }: { 11 + target: string; 12 + user?: string; 13 + }): string[] | undefined { 14 + const { data: followData } = useQueryConstellation( 15 + user 16 + ? { 17 + method: "/links", 18 + target: target, 19 + // @ts-expect-error overloading sucks so much 20 + collection: "app.bsky.graph.follow", 21 + path: ".subject", 22 + dids: [user], 23 + } 24 + : { method: "undefined", target: "whatever" } 25 + // overloading sucks so much 26 + ) as { data: linksRecordsResponse | undefined }; 27 + const follows = followData?.linking_records.slice(0, 50) ?? []; 28 + 29 + if (follows.length > 0) { 30 + return follows.map((linksRecord) => { 31 + return `at://${linksRecord.did}/${linksRecord.collection}/${linksRecord.rkey}`; 32 + }); 33 + } 34 + 35 + return undefined; 36 + } 37 + 38 + export function toggleFollow({ 39 + agent, 40 + targetDid, 41 + followRecords, 42 + queryClient, 43 + }: { 44 + agent?: Agent; 45 + targetDid?: string; 46 + followRecords: undefined | string[]; 47 + queryClient: QueryClient; 48 + }) { 49 + if (!agent?.did || !targetDid) return; 50 + 51 + const queryKey = [ 52 + "constellation", 53 + "/links", 54 + targetDid, 55 + "app.bsky.graph.follow", 56 + ".subject", 57 + undefined, 58 + [agent.did], 59 + ] as const; 60 + 61 + const updateCache = ( 62 + updater: ( 63 + oldData: linksRecordsResponse | undefined 64 + ) => linksRecordsResponse | undefined 65 + ) => { 66 + queryClient.setQueryData( 67 + queryKey, 68 + (oldData: linksRecordsResponse | undefined) => updater(oldData) 69 + ); 70 + }; 71 + 72 + if (typeof followRecords === "undefined") { 73 + const newRecord = { 74 + repo: agent.did, 75 + collection: "app.bsky.graph.follow", 76 + rkey: TID.next().toString(), 77 + record: { 78 + $type: "app.bsky.graph.follow", 79 + subject: targetDid, 80 + createdAt: new Date().toISOString(), 81 + }, 82 + }; 83 + 84 + updateCache((old) => { 85 + const newLinkingRecords = [newRecord, ...(old?.linking_records ?? [])]; 86 + return { 87 + ...old, 88 + linking_records: newLinkingRecords, 89 + } as linksRecordsResponse; 90 + }); 91 + 92 + agent.com.atproto.repo.createRecord(newRecord).catch((err) => { 93 + console.error("Follow failed, reverting cache:", err); 94 + // rollback cache 95 + updateCache((old) => { 96 + return { 97 + ...old, 98 + linking_records: 99 + old?.linking_records.filter((r) => r.rkey !== newRecord.rkey) ?? [], 100 + } as linksRecordsResponse; 101 + }); 102 + }); 103 + 104 + return; 105 + } 106 + 107 + followRecords.forEach((followRecord) => { 108 + const aturi = new AtUri(followRecord); 109 + agent.com.atproto.repo 110 + .deleteRecord({ 111 + repo: agent.did!, 112 + collection: "app.bsky.graph.follow", 113 + rkey: aturi.rkey, 114 + }) 115 + .catch(console.error); 116 + }); 117 + 118 + updateCache((old) => { 119 + if (!old?.linking_records) return old; 120 + return { 121 + ...old, 122 + linking_records: old.linking_records.filter( 123 + (rec) => 124 + !followRecords.includes( 125 + `at://${rec.did}/${rec.collection}/${rec.rkey}` 126 + ) 127 + ), 128 + }; 129 + }); 130 + } 131 + 132 + 133 + 134 + export function useGetOneToOneState(params?: { 135 + target: string; 136 + user: string; 137 + collection: string; 138 + path: string; 139 + }): string[] | undefined { 140 + const { data: arbitrarydata } = useQueryConstellation( 141 + params && params.user 142 + ? { 143 + method: "/links", 144 + target: params.target, 145 + // @ts-expect-error overloading sucks so much 146 + collection: params.collection, 147 + path: params.path, 148 + dids: [params.user], 149 + } 150 + : { method: "undefined", target: "whatever" } 151 + // overloading sucks so much 152 + ) as { data: linksRecordsResponse | undefined }; 153 + if (!params || !params.user) return undefined; 154 + const data = arbitrarydata?.linking_records.slice(0, 50) ?? []; 155 + 156 + if (data.length > 0) { 157 + return data.map((linksRecord) => { 158 + return `at://${linksRecord.did}/${linksRecord.collection}/${linksRecord.rkey}`; 159 + }); 160 + } 161 + 162 + return undefined; 163 + }
+14
src/utils/oauthClient.ts
··· 1 + import { BrowserOAuthClient, type ClientMetadata } from '@atproto/oauth-client-browser'; 2 + 3 + // i tried making this https://pds-nd.whey.party but cors is annoying as fuck 4 + const handleResolverPDS = 'https://bsky.social'; 5 + 6 + // eslint-disable-next-line @typescript-eslint/ban-ts-comment 7 + // @ts-ignore this should be fine ? the vite plugin should generate this before errors 8 + import clientMetadata from '../../public/client-metadata.json' with { type: 'json' }; 9 + 10 + export const oauthClient = new BrowserOAuthClient({ 11 + // The type assertion is needed because the static import isn't strictly typed 12 + clientMetadata: clientMetadata as ClientMetadata, 13 + handleResolver: handleResolverPDS, 14 + });
+275
src/utils/useHydrated.ts
··· 1 + import { 2 + type $Typed, 3 + AppBskyActorDefs, 4 + AppBskyEmbedExternal, 5 + AppBskyEmbedImages, 6 + AppBskyEmbedRecord, 7 + AppBskyEmbedRecordWithMedia, 8 + AppBskyEmbedVideo, 9 + AppBskyFeedPost, 10 + AtUri, 11 + } from "@atproto/api"; 12 + import { useAtom } from "jotai"; 13 + import { useMemo } from "react"; 14 + 15 + import { imgCDNAtom, videoCDNAtom } from "./atoms"; 16 + import { useQueryIdentity, useQueryPost, useQueryProfile } from "./useQuery"; 17 + 18 + type QueryResultData<T extends (...args: any) => any> = 19 + ReturnType<T> extends { data: infer D } | undefined ? D : never; 20 + 21 + function asTyped<T extends { $type: string }>(obj: T): $Typed<T> { 22 + return obj as $Typed<T>; 23 + } 24 + 25 + export function hydrateEmbedImages( 26 + embed: AppBskyEmbedImages.Main, 27 + did: string, 28 + cdn: string 29 + ): $Typed<AppBskyEmbedImages.View> { 30 + return asTyped({ 31 + $type: "app.bsky.embed.images#view" as const, 32 + images: embed.images 33 + .map((img) => { 34 + const link = img.image.ref?.["$link"]; 35 + if (!link) return null; 36 + return { 37 + thumb: `https://${cdn}/img/feed_thumbnail/plain/${did}/${link}@jpeg`, 38 + fullsize: `https://${cdn}/img/feed_fullsize/plain/${did}/${link}@jpeg`, 39 + alt: img.alt || "", 40 + aspectRatio: img.aspectRatio, 41 + }; 42 + }) 43 + .filter(Boolean) as AppBskyEmbedImages.ViewImage[], 44 + }); 45 + } 46 + 47 + export function hydrateEmbedExternal( 48 + embed: AppBskyEmbedExternal.Main, 49 + did: string, 50 + cdn: string 51 + ): $Typed<AppBskyEmbedExternal.View> { 52 + return asTyped({ 53 + $type: "app.bsky.embed.external#view" as const, 54 + external: { 55 + uri: embed.external.uri, 56 + title: embed.external.title, 57 + description: embed.external.description, 58 + thumb: embed.external.thumb?.ref?.$link 59 + ? `https://${cdn}/img/feed_thumbnail/plain/${did}/${embed.external.thumb.ref.$link}@jpeg` 60 + : undefined, 61 + }, 62 + }); 63 + } 64 + 65 + export function hydrateEmbedVideo( 66 + embed: AppBskyEmbedVideo.Main, 67 + did: string, 68 + videocdn: string 69 + ): $Typed<AppBskyEmbedVideo.View> { 70 + const videoLink = embed.video.ref.$link; 71 + return asTyped({ 72 + $type: "app.bsky.embed.video#view" as const, 73 + playlist: `https://${videocdn}/watch/${did}/${videoLink}/playlist.m3u8`, 74 + thumbnail: `https://${videocdn}/watch/${did}/${videoLink}/thumbnail.jpg`, 75 + aspectRatio: embed.aspectRatio, 76 + cid: videoLink, 77 + }); 78 + } 79 + 80 + function hydrateEmbedRecord( 81 + embed: AppBskyEmbedRecord.Main, 82 + quotedPost: QueryResultData<typeof useQueryPost>, 83 + quotedProfile: QueryResultData<typeof useQueryProfile>, 84 + quotedIdentity: QueryResultData<typeof useQueryIdentity>, 85 + cdn: string 86 + ): $Typed<AppBskyEmbedRecord.View> | undefined { 87 + if (!quotedPost || !quotedProfile || !quotedIdentity) { 88 + return undefined; 89 + } 90 + 91 + const author: $Typed<AppBskyActorDefs.ProfileViewBasic> = asTyped({ 92 + $type: "app.bsky.actor.defs#profileViewBasic" as const, 93 + did: quotedIdentity.did, 94 + handle: quotedIdentity.handle, 95 + displayName: quotedProfile.value.displayName ?? quotedIdentity.handle, 96 + avatar: quotedProfile.value.avatar?.ref?.$link 97 + ? `https://${cdn}/img/avatar/plain/${quotedIdentity.did}/${quotedProfile.value.avatar.ref.$link}@jpeg` 98 + : undefined, 99 + viewer: {}, 100 + labels: [], 101 + }); 102 + 103 + const viewRecord: $Typed<AppBskyEmbedRecord.ViewRecord> = asTyped({ 104 + $type: "app.bsky.embed.record#viewRecord" as const, 105 + uri: quotedPost.uri, 106 + cid: quotedPost.cid, 107 + author, 108 + value: quotedPost.value, 109 + indexedAt: quotedPost.value.createdAt, 110 + embeds: quotedPost.value.embed ? [quotedPost.value.embed] : undefined, 111 + }); 112 + 113 + return asTyped({ 114 + $type: "app.bsky.embed.record#view" as const, 115 + record: viewRecord, 116 + }); 117 + } 118 + 119 + function hydrateEmbedRecordWithMedia( 120 + embed: AppBskyEmbedRecordWithMedia.Main, 121 + mediaHydratedEmbed: 122 + | $Typed<AppBskyEmbedImages.View> 123 + | $Typed<AppBskyEmbedVideo.View> 124 + | $Typed<AppBskyEmbedExternal.View>, 125 + quotedPost: QueryResultData<typeof useQueryPost>, 126 + quotedProfile: QueryResultData<typeof useQueryProfile>, 127 + quotedIdentity: QueryResultData<typeof useQueryIdentity>, 128 + cdn: string 129 + ): $Typed<AppBskyEmbedRecordWithMedia.View> | undefined { 130 + const hydratedRecord = hydrateEmbedRecord( 131 + embed.record, 132 + quotedPost, 133 + quotedProfile, 134 + quotedIdentity, 135 + cdn 136 + ); 137 + 138 + if (!hydratedRecord) return undefined; 139 + 140 + return asTyped({ 141 + $type: "app.bsky.embed.recordWithMedia#view" as const, 142 + record: hydratedRecord, 143 + media: mediaHydratedEmbed, 144 + }); 145 + } 146 + 147 + type HydratedEmbedView = 148 + | $Typed<AppBskyEmbedImages.View> 149 + | $Typed<AppBskyEmbedExternal.View> 150 + | $Typed<AppBskyEmbedVideo.View> 151 + | $Typed<AppBskyEmbedRecord.View> 152 + | $Typed<AppBskyEmbedRecordWithMedia.View>; 153 + 154 + export function useHydratedEmbed( 155 + embed: AppBskyFeedPost.Record["embed"], 156 + postAuthorDid: string | undefined 157 + ) { 158 + const recordInfo = useMemo(() => { 159 + if (AppBskyEmbedRecordWithMedia.isMain(embed)) { 160 + const recordUri = embed.record.record.uri; 161 + const quotedAuthorDid = new AtUri(recordUri).hostname; 162 + return { recordUri, quotedAuthorDid, isRecordType: true }; 163 + } else if (AppBskyEmbedRecord.isMain(embed)) { 164 + const recordUri = embed.record.uri; 165 + const quotedAuthorDid = new AtUri(recordUri).hostname; 166 + return { recordUri, quotedAuthorDid, isRecordType: true }; 167 + } 168 + return { 169 + recordUri: undefined, 170 + quotedAuthorDid: undefined, 171 + isRecordType: false, 172 + }; 173 + }, [embed]); 174 + 175 + const { isRecordType, recordUri, quotedAuthorDid } = recordInfo; 176 + 177 + const usequerypostresults = useQueryPost(recordUri); 178 + 179 + const profileUri = quotedAuthorDid 180 + ? `at://${quotedAuthorDid}/app.bsky.actor.profile/self` 181 + : undefined; 182 + 183 + const { 184 + data: quotedProfile, 185 + isLoading: isLoadingProfile, 186 + error: profileError, 187 + } = useQueryProfile(profileUri); 188 + 189 + const [imgcdn] = useAtom(imgCDNAtom); 190 + const [videocdn] = useAtom(videoCDNAtom); 191 + 192 + const queryidentityresult = useQueryIdentity(quotedAuthorDid); 193 + 194 + const hydratedEmbed: HydratedEmbedView | undefined = (() => { 195 + if (!embed || !postAuthorDid) return undefined; 196 + 197 + if ( 198 + isRecordType && 199 + (!usequerypostresults?.data || 200 + !quotedProfile || 201 + !queryidentityresult?.data) 202 + ) { 203 + return undefined; 204 + } 205 + 206 + try { 207 + if (AppBskyEmbedImages.isMain(embed)) { 208 + return hydrateEmbedImages(embed, postAuthorDid, imgcdn); 209 + } else if (AppBskyEmbedExternal.isMain(embed)) { 210 + return hydrateEmbedExternal(embed, postAuthorDid, imgcdn); 211 + } else if (AppBskyEmbedVideo.isMain(embed)) { 212 + return hydrateEmbedVideo(embed, postAuthorDid, videocdn); 213 + } else if (AppBskyEmbedRecord.isMain(embed)) { 214 + return hydrateEmbedRecord( 215 + embed, 216 + usequerypostresults?.data, 217 + quotedProfile, 218 + queryidentityresult?.data, 219 + imgcdn 220 + ); 221 + } else if (AppBskyEmbedRecordWithMedia.isMain(embed)) { 222 + let hydratedMedia: 223 + | $Typed<AppBskyEmbedImages.View> 224 + | $Typed<AppBskyEmbedVideo.View> 225 + | $Typed<AppBskyEmbedExternal.View> 226 + | undefined; 227 + 228 + if (AppBskyEmbedImages.isMain(embed.media)) { 229 + hydratedMedia = hydrateEmbedImages( 230 + embed.media, 231 + postAuthorDid, 232 + imgcdn 233 + ); 234 + } else if (AppBskyEmbedExternal.isMain(embed.media)) { 235 + hydratedMedia = hydrateEmbedExternal( 236 + embed.media, 237 + postAuthorDid, 238 + imgcdn 239 + ); 240 + } else if (AppBskyEmbedVideo.isMain(embed.media)) { 241 + hydratedMedia = hydrateEmbedVideo( 242 + embed.media, 243 + postAuthorDid, 244 + videocdn 245 + ); 246 + } 247 + 248 + if (hydratedMedia) { 249 + return hydrateEmbedRecordWithMedia( 250 + embed, 251 + hydratedMedia, 252 + usequerypostresults?.data, 253 + quotedProfile, 254 + queryidentityresult?.data, 255 + imgcdn 256 + ); 257 + } 258 + } 259 + } catch (e) { 260 + console.error("Error hydrating embed", e); 261 + return undefined; 262 + } 263 + })(); 264 + 265 + const isLoading = isRecordType 266 + ? usequerypostresults?.isLoading || 267 + isLoadingProfile || 268 + queryidentityresult?.isLoading 269 + : false; 270 + 271 + const error = 272 + usequerypostresults?.error || profileError || queryidentityresult?.error; 273 + 274 + return { data: hydratedEmbed, isLoading, error }; 275 + }
+681
src/utils/useQuery.ts
··· 1 + import * as ATPAPI from "@atproto/api"; 2 + import { 3 + infiniteQueryOptions, 4 + type QueryFunctionContext, 5 + queryOptions, 6 + useInfiniteQuery, 7 + useQuery, 8 + type UseQueryResult} from "@tanstack/react-query"; 9 + import { useAtom } from "jotai"; 10 + 11 + import { constellationURLAtom, slingshotURLAtom } from "./atoms"; 12 + 13 + export function constructIdentityQuery(didorhandle?: string, slingshoturl?: string) { 14 + return queryOptions({ 15 + queryKey: ["identity", didorhandle], 16 + queryFn: async () => { 17 + if (!didorhandle) return undefined as undefined 18 + const res = await fetch( 19 + `https://${slingshoturl}/xrpc/com.bad-example.identity.resolveMiniDoc?identifier=${encodeURIComponent(didorhandle)}` 20 + ); 21 + if (!res.ok) throw new Error("Failed to fetch post"); 22 + try { 23 + return (await res.json()) as { 24 + did: string; 25 + handle: string; 26 + pds: string; 27 + signing_key: string; 28 + }; 29 + } catch (_e) { 30 + return undefined; 31 + } 32 + }, 33 + staleTime: /*0,//*/ 5 * 60 * 1000, // 5 minutes 34 + gcTime: /*0//*/5 * 60 * 1000, 35 + }); 36 + } 37 + export function useQueryIdentity(didorhandle: string): UseQueryResult< 38 + { 39 + did: string; 40 + handle: string; 41 + pds: string; 42 + signing_key: string; 43 + }, 44 + Error 45 + >; 46 + export function useQueryIdentity(): UseQueryResult< 47 + undefined, 48 + Error 49 + > 50 + export function useQueryIdentity(didorhandle?: string): 51 + UseQueryResult< 52 + { 53 + did: string; 54 + handle: string; 55 + pds: string; 56 + signing_key: string; 57 + } | undefined, 58 + Error 59 + > 60 + export function useQueryIdentity(didorhandle?: string) { 61 + const [slingshoturl] = useAtom(slingshotURLAtom) 62 + return useQuery(constructIdentityQuery(didorhandle, slingshoturl)); 63 + } 64 + 65 + export function constructPostQuery(uri?: string, slingshoturl?: string) { 66 + return queryOptions({ 67 + queryKey: ["post", uri], 68 + queryFn: async () => { 69 + if (!uri) return undefined as undefined 70 + const res = await fetch( 71 + `https://${slingshoturl}/xrpc/com.bad-example.repo.getUriRecord?at_uri=${encodeURIComponent(uri)}` 72 + ); 73 + let data: any; 74 + try { 75 + data = await res.json(); 76 + } catch { 77 + return undefined; 78 + } 79 + if (res.status === 400) return undefined; 80 + if (data?.error === "InvalidRequest" && data.message?.includes("Could not find repo")) { 81 + return undefined; // cache โ€œnot foundโ€ 82 + } 83 + try { 84 + if (!res.ok) throw new Error("Failed to fetch post"); 85 + return (data) as { 86 + uri: string; 87 + cid: string; 88 + value: any; 89 + }; 90 + } catch (_e) { 91 + return undefined; 92 + } 93 + }, 94 + retry: (failureCount, error) => { 95 + // dont retry 400 errors 96 + if ((error as any)?.message?.includes("400")) return false; 97 + return failureCount < 2; 98 + }, 99 + staleTime: /*0,//*/ 5 * 60 * 1000, // 5 minutes 100 + gcTime: /*0//*/5 * 60 * 1000, 101 + }); 102 + } 103 + export function useQueryPost(uri: string): UseQueryResult< 104 + { 105 + uri: string; 106 + cid: string; 107 + value: ATPAPI.AppBskyFeedPost.Record; 108 + }, 109 + Error 110 + >; 111 + export function useQueryPost(): UseQueryResult< 112 + undefined, 113 + Error 114 + > 115 + export function useQueryPost(uri?: string): 116 + UseQueryResult< 117 + { 118 + uri: string; 119 + cid: string; 120 + value: ATPAPI.AppBskyFeedPost.Record; 121 + } | undefined, 122 + Error 123 + > 124 + export function useQueryPost(uri?: string) { 125 + const [slingshoturl] = useAtom(slingshotURLAtom) 126 + return useQuery(constructPostQuery(uri, slingshoturl)); 127 + } 128 + 129 + export function constructProfileQuery(uri?: string, slingshoturl?: string) { 130 + return queryOptions({ 131 + queryKey: ["profile", uri], 132 + queryFn: async () => { 133 + if (!uri) return undefined as undefined 134 + const res = await fetch( 135 + `https://${slingshoturl}/xrpc/com.bad-example.repo.getUriRecord?at_uri=${encodeURIComponent(uri)}` 136 + ); 137 + let data: any; 138 + try { 139 + data = await res.json(); 140 + } catch { 141 + return undefined; 142 + } 143 + if (res.status === 400) return undefined; 144 + if (data?.error === "InvalidRequest" && data.message?.includes("Could not find repo")) { 145 + return undefined; // cache โ€œnot foundโ€ 146 + } 147 + try { 148 + if (!res.ok) throw new Error("Failed to fetch post"); 149 + return (data) as { 150 + uri: string; 151 + cid: string; 152 + value: any; 153 + }; 154 + } catch (_e) { 155 + return undefined; 156 + } 157 + }, 158 + retry: (failureCount, error) => { 159 + // dont retry 400 errors 160 + if ((error as any)?.message?.includes("400")) return false; 161 + return failureCount < 2; 162 + }, 163 + staleTime: /*0,//*/ 5 * 60 * 1000, // 5 minutes 164 + gcTime: /*0//*/5 * 60 * 1000, 165 + }); 166 + } 167 + export function useQueryProfile(uri: string): UseQueryResult< 168 + { 169 + uri: string; 170 + cid: string; 171 + value: ATPAPI.AppBskyActorProfile.Record; 172 + }, 173 + Error 174 + >; 175 + export function useQueryProfile(): UseQueryResult< 176 + undefined, 177 + Error 178 + >; 179 + export function useQueryProfile(uri?: string): 180 + UseQueryResult< 181 + { 182 + uri: string; 183 + cid: string; 184 + value: ATPAPI.AppBskyActorProfile.Record; 185 + } | undefined, 186 + Error 187 + > 188 + export function useQueryProfile(uri?: string) { 189 + const [slingshoturl] = useAtom(slingshotURLAtom) 190 + return useQuery(constructProfileQuery(uri, slingshoturl)); 191 + } 192 + 193 + // export function constructConstellationQuery( 194 + // method: "/links", 195 + // target: string, 196 + // collection: string, 197 + // path: string, 198 + // cursor?: string 199 + // ): QueryOptions<linksRecordsResponse, Error>; 200 + // export function constructConstellationQuery( 201 + // method: "/links/distinct-dids", 202 + // target: string, 203 + // collection: string, 204 + // path: string, 205 + // cursor?: string 206 + // ): QueryOptions<linksDidsResponse, Error>; 207 + // export function constructConstellationQuery( 208 + // method: "/links/count", 209 + // target: string, 210 + // collection: string, 211 + // path: string, 212 + // cursor?: string 213 + // ): QueryOptions<linksCountResponse, Error>; 214 + // export function constructConstellationQuery( 215 + // method: "/links/count/distinct-dids", 216 + // target: string, 217 + // collection: string, 218 + // path: string, 219 + // cursor?: string 220 + // ): QueryOptions<linksCountResponse, Error>; 221 + // export function constructConstellationQuery( 222 + // method: "/links/all", 223 + // target: string 224 + // ): QueryOptions<linksAllResponse, Error>; 225 + export function constructConstellationQuery(query?:{ 226 + constellation: string, 227 + method: 228 + | "/links" 229 + | "/links/distinct-dids" 230 + | "/links/count" 231 + | "/links/count/distinct-dids" 232 + | "/links/all" 233 + | "undefined", 234 + target: string, 235 + collection?: string, 236 + path?: string, 237 + cursor?: string, 238 + dids?: string[] 239 + } 240 + ) { 241 + // : QueryOptions< 242 + // | linksRecordsResponse 243 + // | linksDidsResponse 244 + // | linksCountResponse 245 + // | linksAllResponse 246 + // | undefined, 247 + // Error 248 + // > 249 + return queryOptions({ 250 + queryKey: ["constellation", query?.method, query?.target, query?.collection, query?.path, query?.cursor, query?.dids] as const, 251 + queryFn: async () => { 252 + if (!query || query.method === "undefined") return undefined as undefined 253 + const method = query.method 254 + const target = query.target 255 + const collection = query?.collection 256 + const path = query?.path 257 + const cursor = query.cursor 258 + const dids = query?.dids 259 + const res = await fetch( 260 + `https://${query.constellation}${method}?target=${encodeURIComponent(target)}${collection ? `&collection=${encodeURIComponent(collection)}` : ""}${path ? `&path=${encodeURIComponent(path)}` : ""}${cursor ? `&cursor=${encodeURIComponent(cursor)}` : ""}${dids ? dids.map((did) => `&did=${encodeURIComponent(did)}`).join("") : ""}` 261 + ); 262 + if (!res.ok) throw new Error("Failed to fetch post"); 263 + try { 264 + switch (method) { 265 + case "/links": 266 + return (await res.json()) as linksRecordsResponse; 267 + case "/links/distinct-dids": 268 + return (await res.json()) as linksDidsResponse; 269 + case "/links/count": 270 + return (await res.json()) as linksCountResponse; 271 + case "/links/count/distinct-dids": 272 + return (await res.json()) as linksCountResponse; 273 + case "/links/all": 274 + return (await res.json()) as linksAllResponse; 275 + default: 276 + return undefined; 277 + } 278 + } catch (_e) { 279 + return undefined; 280 + } 281 + }, 282 + // enforce short lifespan 283 + staleTime: /*0,//*/ 5 * 60 * 1000, // 5 minutes 284 + gcTime: /*0//*/5 * 60 * 1000, 285 + }); 286 + } 287 + export function useQueryConstellation(query: { 288 + method: "/links"; 289 + target: string; 290 + collection: string; 291 + path: string; 292 + cursor?: string; 293 + dids?: string[]; 294 + }): UseQueryResult<linksRecordsResponse, Error>; 295 + export function useQueryConstellation(query: { 296 + method: "/links/distinct-dids"; 297 + target: string; 298 + collection: string; 299 + path: string; 300 + cursor?: string; 301 + }): UseQueryResult<linksDidsResponse, Error>; 302 + export function useQueryConstellation(query: { 303 + method: "/links/count"; 304 + target: string; 305 + collection: string; 306 + path: string; 307 + cursor?: string; 308 + }): UseQueryResult<linksCountResponse, Error>; 309 + export function useQueryConstellation(query: { 310 + method: "/links/count/distinct-dids"; 311 + target: string; 312 + collection: string; 313 + path: string; 314 + cursor?: string; 315 + }): UseQueryResult<linksCountResponse, Error>; 316 + export function useQueryConstellation(query: { 317 + method: "/links/all"; 318 + target: string; 319 + }): UseQueryResult<linksAllResponse, Error>; 320 + export function useQueryConstellation(): undefined; 321 + export function useQueryConstellation(query: { 322 + method: "undefined"; 323 + target: string; 324 + }): undefined; 325 + export function useQueryConstellation(query?: { 326 + method: 327 + | "/links" 328 + | "/links/distinct-dids" 329 + | "/links/count" 330 + | "/links/count/distinct-dids" 331 + | "/links/all" 332 + | "undefined"; 333 + target: string; 334 + collection?: string; 335 + path?: string; 336 + cursor?: string; 337 + dids?: string[]; 338 + }): 339 + | UseQueryResult< 340 + | linksRecordsResponse 341 + | linksDidsResponse 342 + | linksCountResponse 343 + | linksAllResponse 344 + | undefined, 345 + Error 346 + > 347 + | undefined { 348 + //if (!query) return; 349 + const [constellationurl] = useAtom(constellationURLAtom) 350 + return useQuery( 351 + constructConstellationQuery(query && {constellation: constellationurl, ...query}) 352 + ); 353 + } 354 + 355 + type linksRecord = { 356 + did: string; 357 + collection: string; 358 + rkey: string; 359 + }; 360 + export type linksRecordsResponse = { 361 + total: string; 362 + linking_records: linksRecord[]; 363 + cursor?: string; 364 + }; 365 + type linksDidsResponse = { 366 + total: string; 367 + linking_dids: string[]; 368 + cursor?: string; 369 + }; 370 + type linksCountResponse = { 371 + total: string; 372 + }; 373 + export type linksAllResponse = { 374 + links: Record< 375 + string, 376 + Record< 377 + string, 378 + { 379 + records: number; 380 + distinct_dids: number; 381 + } 382 + > 383 + >; 384 + }; 385 + 386 + export function constructFeedSkeletonQuery(options?: { 387 + feedUri: string; 388 + agent?: ATPAPI.Agent; 389 + isAuthed: boolean; 390 + pdsUrl?: string; 391 + feedServiceDid?: string; 392 + }) { 393 + return queryOptions({ 394 + // The query key includes all dependencies to ensure it refetches when they change 395 + queryKey: ["feedSkeleton", options?.feedUri, { isAuthed: options?.isAuthed, did: options?.agent?.did }], 396 + queryFn: async () => { 397 + if (!options) return undefined as undefined 398 + const { feedUri, agent, isAuthed, pdsUrl, feedServiceDid } = options; 399 + if (isAuthed) { 400 + // Authenticated flow 401 + if (!agent || !pdsUrl || !feedServiceDid) { 402 + throw new Error("Missing required info for authenticated feed fetch."); 403 + } 404 + const url = `${pdsUrl}/xrpc/app.bsky.feed.getFeedSkeleton?feed=${encodeURIComponent(feedUri)}`; 405 + const res = await agent.fetchHandler(url, { 406 + method: "GET", 407 + headers: { 408 + "atproto-proxy": `${feedServiceDid}#bsky_fg`, 409 + "Content-Type": "application/json", 410 + }, 411 + }); 412 + if (!res.ok) throw new Error(`Authenticated feed fetch failed: ${res.statusText}`); 413 + return (await res.json()) as ATPAPI.AppBskyFeedGetFeedSkeleton.OutputSchema; 414 + } else { 415 + // Unauthenticated flow (using a public PDS/AppView) 416 + const url = `https://discover.bsky.app/xrpc/app.bsky.feed.getFeedSkeleton?feed=${encodeURIComponent(feedUri)}`; 417 + const res = await fetch(url); 418 + if (!res.ok) throw new Error(`Public feed fetch failed: ${res.statusText}`); 419 + return (await res.json()) as ATPAPI.AppBskyFeedGetFeedSkeleton.OutputSchema; 420 + } 421 + }, 422 + //enabled: !!feedUri && (isAuthed ? !!agent && !!pdsUrl && !!feedServiceDid : true), 423 + }); 424 + } 425 + 426 + export function useQueryFeedSkeleton(options?: { 427 + feedUri: string; 428 + agent?: ATPAPI.Agent; 429 + isAuthed: boolean; 430 + pdsUrl?: string; 431 + feedServiceDid?: string; 432 + }) { 433 + return useQuery(constructFeedSkeletonQuery(options)); 434 + } 435 + 436 + export function constructPreferencesQuery(agent?: ATPAPI.Agent | undefined, pdsUrl?: string | undefined) { 437 + return queryOptions({ 438 + queryKey: ['preferences', agent?.did], 439 + queryFn: async () => { 440 + if (!agent || !pdsUrl) throw new Error("Agent or PDS URL not available"); 441 + const url = `${pdsUrl}/xrpc/app.bsky.actor.getPreferences`; 442 + const res = await agent.fetchHandler(url, { method: "GET" }); 443 + if (!res.ok) throw new Error("Failed to fetch preferences"); 444 + return res.json(); 445 + }, 446 + }); 447 + } 448 + export function useQueryPreferences(options: { 449 + agent?: ATPAPI.Agent | undefined, pdsUrl?: string | undefined 450 + }) { 451 + return useQuery(constructPreferencesQuery(options.agent, options.pdsUrl)); 452 + } 453 + 454 + 455 + 456 + export function constructArbitraryQuery(uri?: string, slingshoturl?: string) { 457 + return queryOptions({ 458 + queryKey: ["arbitrary", uri], 459 + queryFn: async () => { 460 + if (!uri) return undefined as undefined 461 + const res = await fetch( 462 + `https://${slingshoturl}/xrpc/com.bad-example.repo.getUriRecord?at_uri=${encodeURIComponent(uri)}` 463 + ); 464 + let data: any; 465 + try { 466 + data = await res.json(); 467 + } catch { 468 + return undefined; 469 + } 470 + if (res.status === 400) return undefined; 471 + if (data?.error === "InvalidRequest" && data.message?.includes("Could not find repo")) { 472 + return undefined; // cache โ€œnot foundโ€ 473 + } 474 + try { 475 + if (!res.ok) throw new Error("Failed to fetch post"); 476 + return (data) as { 477 + uri: string; 478 + cid: string; 479 + value: any; 480 + }; 481 + } catch (_e) { 482 + return undefined; 483 + } 484 + }, 485 + retry: (failureCount, error) => { 486 + // dont retry 400 errors 487 + if ((error as any)?.message?.includes("400")) return false; 488 + return failureCount < 2; 489 + }, 490 + staleTime: /*0,//*/ 5 * 60 * 1000, // 5 minutes 491 + gcTime: /*0//*/5 * 60 * 1000, 492 + }); 493 + } 494 + export function useQueryArbitrary(uri: string): UseQueryResult< 495 + { 496 + uri: string; 497 + cid: string; 498 + value: any; 499 + }, 500 + Error 501 + >; 502 + export function useQueryArbitrary(): UseQueryResult< 503 + undefined, 504 + Error 505 + >; 506 + export function useQueryArbitrary(uri?: string): UseQueryResult< 507 + { 508 + uri: string; 509 + cid: string; 510 + value: any; 511 + } | undefined, 512 + Error 513 + >; 514 + export function useQueryArbitrary(uri?: string) { 515 + const [slingshoturl] = useAtom(slingshotURLAtom) 516 + return useQuery(constructArbitraryQuery(uri, slingshoturl)); 517 + } 518 + 519 + export function constructFallbackNothingQuery(){ 520 + return queryOptions({ 521 + queryKey: ["nothing"], 522 + queryFn: async () => { 523 + return undefined 524 + }, 525 + }); 526 + } 527 + 528 + type ListRecordsResponse = { 529 + cursor?: string; 530 + records: { 531 + uri: string; 532 + cid: string; 533 + value: ATPAPI.AppBskyFeedPost.Record; 534 + }[]; 535 + }; 536 + 537 + export function constructAuthorFeedQuery(did: string, pdsUrl: string) { 538 + return queryOptions({ 539 + queryKey: ['authorFeed', did], 540 + queryFn: async ({ pageParam }: QueryFunctionContext) => { 541 + const limit = 25; 542 + 543 + const cursor = pageParam as string | undefined; 544 + const cursorParam = cursor ? `&cursor=${cursor}` : ''; 545 + 546 + const url = `${pdsUrl}/xrpc/com.atproto.repo.listRecords?repo=${did}&collection=app.bsky.feed.post&limit=${limit}${cursorParam}`; 547 + 548 + const res = await fetch(url); 549 + if (!res.ok) throw new Error("Failed to fetch author's posts"); 550 + 551 + return res.json() as Promise<ListRecordsResponse>; 552 + }, 553 + }); 554 + } 555 + 556 + export function useInfiniteQueryAuthorFeed(did: string | undefined, pdsUrl: string | undefined) { 557 + const { queryKey, queryFn } = constructAuthorFeedQuery(did!, pdsUrl!); 558 + 559 + return useInfiniteQuery({ 560 + queryKey, 561 + queryFn, 562 + initialPageParam: undefined as never, // ???? what is this shit 563 + getNextPageParam: (lastPage) => lastPage.cursor as null | undefined, 564 + enabled: !!did && !!pdsUrl, 565 + }); 566 + } 567 + 568 + type FeedSkeletonPage = ATPAPI.AppBskyFeedGetFeedSkeleton.OutputSchema; 569 + 570 + export function constructInfiniteFeedSkeletonQuery(options: { 571 + feedUri: string; 572 + agent?: ATPAPI.Agent; 573 + isAuthed: boolean; 574 + pdsUrl?: string; 575 + feedServiceDid?: string; 576 + }) { 577 + const { feedUri, agent, isAuthed, pdsUrl, feedServiceDid } = options; 578 + 579 + return queryOptions({ 580 + queryKey: ["feedSkeleton", feedUri, { isAuthed, did: agent?.did }], 581 + 582 + queryFn: async ({ pageParam }: QueryFunctionContext): Promise<FeedSkeletonPage> => { 583 + const cursorParam = pageParam ? `&cursor=${pageParam}` : ""; 584 + 585 + if (isAuthed) { 586 + if (!agent || !pdsUrl || !feedServiceDid) { 587 + throw new Error("Missing required info for authenticated feed fetch."); 588 + } 589 + const url = `${pdsUrl}/xrpc/app.bsky.feed.getFeedSkeleton?feed=${encodeURIComponent(feedUri)}${cursorParam}`; 590 + const res = await agent.fetchHandler(url, { 591 + method: "GET", 592 + headers: { 593 + "atproto-proxy": `${feedServiceDid}#bsky_fg`, 594 + "Content-Type": "application/json", 595 + }, 596 + }); 597 + if (!res.ok) throw new Error(`Authenticated feed fetch failed: ${res.statusText}`); 598 + return (await res.json()) as FeedSkeletonPage; 599 + } else { 600 + const url = `https://discover.bsky.app/xrpc/app.bsky.feed.getFeedSkeleton?feed=${encodeURIComponent(feedUri)}${cursorParam}`; 601 + const res = await fetch(url); 602 + if (!res.ok) throw new Error(`Public feed fetch failed: ${res.statusText}`); 603 + return (await res.json()) as FeedSkeletonPage; 604 + } 605 + }, 606 + }); 607 + } 608 + 609 + export function useInfiniteQueryFeedSkeleton(options: { 610 + feedUri: string; 611 + agent?: ATPAPI.Agent; 612 + isAuthed: boolean; 613 + pdsUrl?: string; 614 + feedServiceDid?: string; 615 + }) { 616 + const { queryKey, queryFn } = constructInfiniteFeedSkeletonQuery(options); 617 + 618 + return {...useInfiniteQuery({ 619 + queryKey, 620 + queryFn, 621 + initialPageParam: undefined as never, 622 + getNextPageParam: (lastPage) => lastPage.cursor as null | undefined, 623 + staleTime: Infinity, 624 + refetchOnWindowFocus: false, 625 + enabled: !!options.feedUri && (options.isAuthed ? !!options.agent && !!options.pdsUrl && !!options.feedServiceDid : true), 626 + }), queryKey: queryKey}; 627 + } 628 + 629 + 630 + export function yknowIReallyHateThisButWhateverGuardedConstructConstellationInfiniteQueryLinks(query?: { 631 + constellation: string, 632 + method: '/links' 633 + target?: string 634 + collection: string 635 + path: string 636 + }) { 637 + console.log( 638 + 'yknowIReallyHateThisButWhateverGuardedConstructConstellationInfiniteQueryLinks', 639 + query, 640 + ) 641 + 642 + return infiniteQueryOptions({ 643 + enabled: !!query?.target, 644 + queryKey: [ 645 + 'reddwarf_constellation', 646 + query?.method, 647 + query?.target, 648 + query?.collection, 649 + query?.path, 650 + ] as const, 651 + 652 + queryFn: async ({pageParam}: {pageParam?: string}) => { 653 + if (!query || !query?.target) return undefined 654 + 655 + const method = query.method 656 + const target = query.target 657 + const collection = query.collection 658 + const path = query.path 659 + const cursor = pageParam 660 + 661 + const res = await fetch( 662 + `https://${query.constellation}${method}?target=${encodeURIComponent(target)}${ 663 + collection ? `&collection=${encodeURIComponent(collection)}` : '' 664 + }${path ? `&path=${encodeURIComponent(path)}` : ''}${ 665 + cursor ? `&cursor=${encodeURIComponent(cursor)}` : '' 666 + }`, 667 + ) 668 + 669 + if (!res.ok) throw new Error('Failed to fetch') 670 + 671 + return (await res.json()) as linksRecordsResponse 672 + }, 673 + 674 + getNextPageParam: lastPage => { 675 + return (lastPage as any)?.cursor ?? undefined 676 + }, 677 + initialPageParam: undefined, 678 + staleTime: 5 * 60 * 1000, 679 + gcTime: 5 * 60 * 1000, 680 + }) 681 + }
+1 -1
tsconfig.json
··· 5 5 "jsx": "react-jsx", 6 6 "module": "ESNext", 7 7 "lib": ["ES2022", "DOM", "DOM.Iterable"], 8 - "types": ["vite/client"], 8 + "types": ["vite/client", "unplugin-icons/types/react"], 9 9 10 10 /* Bundler mode */ 11 11 "moduleResolution": "bundler",
+49 -5
vite.config.ts
··· 1 - import { defineConfig } from "vite"; 1 + import { resolve } from "node:path"; 2 + 3 + import tailwindcss from "@tailwindcss/vite"; 4 + import { TanStackRouterVite } from "@tanstack/router-plugin/vite"; 2 5 import viteReact from "@vitejs/plugin-react"; 3 - import tailwindcss from "@tailwindcss/vite"; 6 + import AutoImport from 'unplugin-auto-import/vite' 7 + import IconsResolver from 'unplugin-icons/resolver' 8 + import Icons from 'unplugin-icons/vite' 9 + import { defineConfig } from "vite"; 10 + 11 + import { generateMetadataPlugin } from "./oauthdev.mts"; 12 + 13 + const PROD_URL = "https://reddwarf.app" 14 + const DEV_URL = "https://local3768forumtest.whey.party" 4 15 5 - import { TanStackRouterVite } from "@tanstack/router-plugin/vite"; 6 - import { resolve } from "node:path"; 16 + function shp(url: string): string { 17 + return url.replace(/^https?:\/\//, ''); 18 + } 7 19 8 20 // https://vitejs.dev/config/ 9 21 export default defineConfig({ 10 22 plugins: [ 23 + generateMetadataPlugin({ 24 + prod: PROD_URL, 25 + dev: DEV_URL, 26 + }), 11 27 TanStackRouterVite({ autoCodeSplitting: true }), 12 - viteReact(), 28 + viteReact({ 29 + babel: { 30 + plugins: ['babel-plugin-react-compiler'], 31 + }, 32 + }), 13 33 tailwindcss(), 34 + AutoImport({ 35 + include: [ 36 + /\.[tj]sx?$/, // .ts, .tsx, .js, .jsx 37 + ], 38 + resolvers: [ 39 + IconsResolver({ 40 + prefix: 'Icon', 41 + extension: 'jsx', 42 + enabledCollections: ['mdi','material-symbols'], 43 + }), 44 + ], 45 + dts: 'src/auto-imports.d.ts', 46 + }), 47 + Icons({ 48 + //autoInstall: true, 49 + compiler: 'jsx', 50 + jsx: 'react' 51 + }), 14 52 ], 15 53 // test: { 16 54 // globals: true, ··· 21 59 "@": resolve(__dirname, "./src"), 22 60 "~": resolve(__dirname, "./src"), 23 61 }, 62 + }, 63 + server: { 64 + allowedHosts: [shp(PROD_URL),shp(DEV_URL)], 65 + }, 66 + css: { 67 + devSourcemap: true, 24 68 }, 25 69 });