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 .env 8 .nitro 9 .tanstack
··· 7 .env 8 .nitro 9 .tanstack 10 + public/client-metadata.json
+39 -5
README.md
··· 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 4 - ![screenshot of red dwarf](/public/screenshot.png) 5 6 huge thanks to [Microcosm](https://microcosm.blue/) for making this possible 7 8 ## useQuery 9 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! 10 ··· 22 ### Slingshot 23 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 24 25 - ## PassAuthProvider 26 - 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 27 28 ## Custom Feeds 29 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 ··· 36 and for list feeds, you can just use something like graze or skyfeed to input a list of users and output a custom feed 37 38 ## Tanstack Router 39 - it does the job, nothing very specific was used here 40 41 - im planning to use the loader system on select pages to prevent loss of scroll positon and state though its really complex so i havent done it yet but the migration to tanstack query is a huge first step towards this goal
··· 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 4 + ![screenshot of red dwarf](/public/screenshot.jpg) 5 6 huge thanks to [Microcosm](https://microcosm.blue/) for making this possible 7 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 ··· 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 34 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. 37 + 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) 43 44 ## Custom Feeds 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 ··· 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 53 54 ## Tanstack Router 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 + ]);
+1 -2
index.html
··· 4 <meta charset="UTF-8" /> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 6 <link rel="icon" href="/favicon.ico" /> 7 - <meta name="theme-color" content="#000000" /> 8 <meta 9 name="description" 10 content="an appview-less Bluesky client using Constellation and PDS Queries" 11 /> 12 <link rel="apple-touch-icon" href="/redstar.png" /> 13 <link rel="manifest" href="/manifest.json" /> 14 - <link rel="stylesheet" href="/src/styles/app.css" /> 15 <title>Red Dwarf</title> 16 </head> 17 <body>
··· 4 <meta charset="UTF-8" /> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 6 <link rel="icon" href="/favicon.ico" /> 7 + <meta name="theme-color" content="#180001" /> 8 <meta 9 name="description" 10 content="an appview-less Bluesky client using Constellation and PDS Queries" 11 /> 12 <link rel="apple-touch-icon" href="/redstar.png" /> 13 <link rel="manifest" href="/manifest.json" /> 14 <title>Red Dwarf</title> 15 </head> 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 + }
+9033 -32
package-lock.json
··· 7 "name": "red-dwarf-tanstack", 8 "dependencies": { 9 "@atproto/api": "^0.16.6", 10 "@tailwindcss/vite": "^4.0.6", 11 "@tanstack/react-devtools": "^0.2.2", 12 "@tanstack/react-query": "^5.85.6", 13 "@tanstack/react-router": "^1.130.2", 14 "@tanstack/react-router-devtools": "^1.131.5", 15 "@tanstack/router-plugin": "^1.121.2", 16 "idb-keyval": "^6.2.2", 17 "jotai": "^2.13.1", 18 "react": "^19.0.0", 19 "react-dom": "^19.0.0", 20 "react-player": "^3.3.2", 21 - "tailwindcss": "^4.0.6" 22 }, 23 "devDependencies": { 24 "@testing-library/dom": "^10.4.0", 25 "@testing-library/react": "^16.2.0", 26 "@types/node": "^24.3.0", 27 "@types/react": "^19.0.8", 28 "@types/react-dom": "^19.0.3", 29 "@vitejs/plugin-react": "^4.3.4", 30 "jsdom": "^26.0.0", 31 "prettier": "^3.6.2", 32 "typescript": "^5.7.2", 33 "vite": "^6.3.5", 34 "vitest": "^3.0.5", 35 "web-vitals": "^4.2.4" ··· 46 }, 47 "engines": { 48 "node": ">=6.0.0" 49 } 50 }, 51 "node_modules/@asamuzakjp/css-color": { ··· 69 "dev": true, 70 "license": "ISC" 71 }, 72 "node_modules/@atproto/api": { 73 "version": "0.16.6", 74 "resolved": "https://registry.npmjs.org/@atproto/api/-/api-0.16.6.tgz", ··· 86 } 87 }, 88 "node_modules/@atproto/common-web": { 89 - "version": "0.4.2", 90 - "resolved": "https://registry.npmjs.org/@atproto/common-web/-/common-web-0.4.2.tgz", 91 - "integrity": "sha512-vrXwGNoFGogodjQvJDxAeP3QbGtawgZute2ed1XdRO0wMixLk3qewtikZm06H259QDJVu6voKC5mubml+WgQUw==", 92 "license": "MIT", 93 "dependencies": { 94 "graphemer": "^1.4.0", ··· 97 "zod": "^3.23.8" 98 } 99 }, 100 "node_modules/@atproto/lexicon": { 101 - "version": "0.5.0", 102 - "resolved": "https://registry.npmjs.org/@atproto/lexicon/-/lexicon-0.5.0.tgz", 103 - "integrity": "sha512-3aAzEAy9EAPs3CxznzMhEcqDd7m3vz1eze/ya9/ThbB7yleqJIhz5GY2q76tCCwHPhn5qDDMhlA9kKV6fG23gA==", 104 "license": "MIT", 105 "dependencies": { 106 - "@atproto/common-web": "^0.4.2", 107 "@atproto/syntax": "^0.4.1", 108 "iso-datestring-validator": "^2.2.2", 109 "multiformats": "^9.9.0", 110 "zod": "^3.23.8" 111 } 112 }, 113 "node_modules/@atproto/syntax": { 114 "version": "0.4.1", 115 "resolved": "https://registry.npmjs.org/@atproto/syntax/-/syntax-0.4.1.tgz", ··· 117 "license": "MIT" 118 }, 119 "node_modules/@atproto/xrpc": { 120 - "version": "0.7.4", 121 - "resolved": "https://registry.npmjs.org/@atproto/xrpc/-/xrpc-0.7.4.tgz", 122 - "integrity": "sha512-sDi68+QE1XHegTaNAndlX41Gp827pouSzSs8CyAwhrqZdsJUxE3P7TMtrA0z+zAjvxVyvzscRc0TsN/fGUGrhw==", 123 "license": "MIT", 124 "dependencies": { 125 - "@atproto/lexicon": "^0.5.0", 126 "zod": "^3.23.8" 127 } 128 }, ··· 1104 "node": ">=18" 1105 } 1106 }, 1107 "node_modules/@isaacs/fs-minipass": { 1108 "version": "4.0.1", 1109 "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", ··· 1229 "mux-embed": "^5.8.3" 1230 } 1231 }, 1232 "node_modules/@rolldown/pluginutils": { 1233 "version": "1.0.0-beta.27", 1234 "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", ··· 1543 "solid-js": "^1.6.12" 1544 } 1545 }, 1546 "node_modules/@svta/common-media-library": { 1547 "version": "0.12.4", 1548 "resolved": "https://registry.npmjs.org/@svta/common-media-library/-/common-media-library-0.12.4.tgz", ··· 1894 "url": "https://github.com/sponsors/tannerlinsley" 1895 } 1896 }, 1897 "node_modules/@tanstack/react-devtools": { 1898 "version": "0.2.2", 1899 "resolved": "https://registry.npmjs.org/@tanstack/react-devtools/-/react-devtools-0.2.2.tgz", ··· 1929 "url": "https://github.com/sponsors/tannerlinsley" 1930 }, 1931 "peerDependencies": { 1932 "react": "^18 || ^19" 1933 } 1934 }, ··· 2290 "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", 2291 "license": "MIT" 2292 }, 2293 "node_modules/@types/node": { 2294 "version": "24.3.0", 2295 "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.0.tgz", ··· 2318 "@types/react": "^19.0.0" 2319 } 2320 }, 2321 "node_modules/@vercel/edge": { 2322 "version": "1.2.2", 2323 "resolved": "https://registry.npmjs.org/@vercel/edge/-/edge-1.2.2.tgz", ··· 2482 "node": ">=0.4.0" 2483 } 2484 }, 2485 "node_modules/agent-base": { 2486 "version": "7.1.4", 2487 "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", ··· 2492 "node": ">= 14" 2493 } 2494 }, 2495 "node_modules/ansi-regex": { 2496 "version": "5.0.1", 2497 "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", ··· 2537 "node": ">= 8" 2538 } 2539 }, 2540 "node_modules/aria-query": { 2541 "version": "5.3.0", 2542 "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", ··· 2547 "dequal": "^2.0.3" 2548 } 2549 }, 2550 "node_modules/assertion-error": { 2551 "version": "2.0.1", 2552 "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", ··· 2569 "node": ">=4" 2570 } 2571 }, 2572 "node_modules/await-lock": { 2573 "version": "2.2.2", 2574 "resolved": "https://registry.npmjs.org/await-lock/-/await-lock-2.2.2.tgz", ··· 2586 "@babel/traverse": "^7.23.7", 2587 "@babel/types": "^7.23.6" 2588 } 2589 }, 2590 "node_modules/bcp-47": { 2591 "version": "2.1.0", ··· 2638 "url": "https://github.com/sponsors/sindresorhus" 2639 } 2640 }, 2641 "node_modules/braces": { 2642 "version": "3.0.3", 2643 "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", ··· 2692 "node": ">=8" 2693 } 2694 }, 2695 "node_modules/caniuse-lite": { 2696 "version": "1.0.30001737", 2697 "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001737.tgz", ··· 2747 "node": ">=18" 2748 } 2749 }, 2750 "node_modules/check-error": { 2751 "version": "2.1.1", 2752 "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", ··· 2811 "integrity": "sha512-eNk3TRV+xQMJ1PEj0FQGY8KD4m0GPxT487XJ+Iftm7mVa9WpPFDMWqPt+46buiP5j5Wzqe5oMIhqBcAeKfygSA==", 2812 "license": "MIT" 2813 }, 2814 "node_modules/convert-source-map": { 2815 "version": "2.0.0", 2816 "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", ··· 2823 "integrity": "sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==", 2824 "license": "MIT" 2825 }, 2826 "node_modules/cssstyle": { 2827 "version": "4.6.0", 2828 "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.6.0.tgz", ··· 2891 "node": ">=18" 2892 } 2893 }, 2894 "node_modules/debug": { 2895 - "version": "4.4.1", 2896 - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", 2897 - "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", 2898 "license": "MIT", 2899 "dependencies": { 2900 "ms": "^2.1.3" ··· 2925 "node": ">=6" 2926 } 2927 }, 2928 "node_modules/dequal": { 2929 "version": "2.0.3", 2930 "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", ··· 2944 "node": ">=8" 2945 } 2946 }, 2947 "node_modules/diff": { 2948 "version": "8.0.2", 2949 "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.2.tgz", ··· 2953 "node": ">=0.3.1" 2954 } 2955 }, 2956 "node_modules/dom-accessibility-api": { 2957 "version": "0.5.16", 2958 "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", ··· 2960 "dev": true, 2961 "license": "MIT" 2962 }, 2963 "node_modules/electron-to-chromium": { 2964 "version": "1.5.211", 2965 "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.211.tgz", ··· 2992 "url": "https://github.com/fb55/entities?sponsor=1" 2993 } 2994 }, 2995 "node_modules/es-module-lexer": { 2996 "version": "1.7.0", 2997 "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", ··· 2999 "dev": true, 3000 "license": "MIT" 3001 }, 3002 "node_modules/esbuild": { 3003 "version": "0.25.9", 3004 "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz", ··· 3049 "node": ">=6" 3050 } 3051 }, 3052 "node_modules/esprima": { 3053 "version": "4.0.1", 3054 "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", ··· 3062 "node": ">=4" 3063 } 3064 }, 3065 "node_modules/estree-walker": { 3066 "version": "3.0.3", 3067 "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", ··· 3072 "@types/estree": "^1.0.0" 3073 } 3074 }, 3075 "node_modules/expect-type": { 3076 "version": "1.2.2", 3077 "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz", ··· 3082 "node": ">=12.0.0" 3083 } 3084 }, 3085 "node_modules/fast-deep-equal": { 3086 "version": "3.1.3", 3087 "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", 3088 "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", 3089 "license": "MIT" 3090 }, 3091 "node_modules/fill-range": { 3092 "version": "7.1.1", 3093 "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", ··· 3100 "node": ">=8" 3101 } 3102 }, 3103 "node_modules/fsevents": { 3104 "version": "2.3.3", 3105 "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", ··· 3114 "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 3115 } 3116 }, 3117 "node_modules/gensync": { 3118 "version": "1.0.0-beta.2", 3119 "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", ··· 3123 "node": ">=6.9.0" 3124 } 3125 }, 3126 "node_modules/get-tsconfig": { 3127 "version": "4.10.1", 3128 "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz", ··· 3147 "node": ">= 6" 3148 } 3149 }, 3150 "node_modules/goober": { 3151 "version": "2.1.16", 3152 "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.16.tgz", ··· 3156 "csstype": "^3.0.10" 3157 } 3158 }, 3159 "node_modules/graceful-fs": { 3160 "version": "4.2.11", 3161 "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", ··· 3168 "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", 3169 "license": "MIT" 3170 }, 3171 "node_modules/hls-video-element": { 3172 "version": "1.5.7", 3173 "resolved": "https://registry.npmjs.org/hls-video-element/-/hls-video-element-1.5.7.tgz", ··· 3242 "node": ">= 14" 3243 } 3244 }, 3245 "node_modules/iconv-lite": { 3246 "version": "0.6.3", 3247 "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", ··· 3261 "integrity": "sha512-yjD9nARJ/jb1g+CvD0tlhUHOrJ9Sy0P8T9MF3YaLlHnSRpwPfpTX0XIvpmw3gAJUmEu3FiICLBDPXVwyEvrleg==", 3262 "license": "Apache-2.0" 3263 }, 3264 "node_modules/immediate": { 3265 "version": "3.0.6", 3266 "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", 3267 "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", 3268 "license": "MIT" 3269 }, 3270 "node_modules/imsc": { 3271 "version": "1.1.5", 3272 "resolved": "https://registry.npmjs.org/imsc/-/imsc-1.1.5.tgz", ··· 3276 "sax": "1.2.1" 3277 } 3278 }, 3279 "node_modules/is-alphabetical": { 3280 "version": "2.0.1", 3281 "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", ··· 3300 "url": "https://github.com/sponsors/wooorm" 3301 } 3302 }, 3303 "node_modules/is-binary-path": { 3304 "version": "2.1.0", 3305 "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", ··· 3312 "node": ">=8" 3313 } 3314 }, 3315 "node_modules/is-decimal": { 3316 "version": "2.0.1", 3317 "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", ··· 3331 "node": ">=0.10.0" 3332 } 3333 }, 3334 "node_modules/is-glob": { 3335 "version": "4.0.3", 3336 "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", ··· 3343 "node": ">=0.10.0" 3344 } 3345 }, 3346 "node_modules/is-number": { 3347 "version": "7.0.0", 3348 "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", ··· 3352 "node": ">=0.12.0" 3353 } 3354 }, 3355 "node_modules/is-potential-custom-element-name": { 3356 "version": "1.0.1", 3357 "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", ··· 3359 "dev": true, 3360 "license": "MIT" 3361 }, 3362 "node_modules/isbot": { 3363 "version": "5.1.30", 3364 "resolved": "https://registry.npmjs.org/isbot/-/isbot-5.1.30.tgz", ··· 3368 "node": ">=18" 3369 } 3370 }, 3371 "node_modules/iso-datestring-validator": { 3372 "version": "2.2.2", 3373 "resolved": "https://registry.npmjs.org/iso-datestring-validator/-/iso-datestring-validator-2.2.2.tgz", 3374 "integrity": "sha512-yLEMkBbLZTlVQqOnQ4FiMujR6T4DEcCb1xizmvXS+OxuhwcbtynoosRzdMA69zZCShCNAbi+gJ71FxZBBXx1SA==", 3375 "license": "MIT" 3376 }, 3377 "node_modules/jiti": { 3378 "version": "2.5.1", 3379 "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz", ··· 3381 "license": "MIT", 3382 "bin": { 3383 "jiti": "lib/jiti-cli.mjs" 3384 } 3385 }, 3386 "node_modules/jotai": { ··· 3418 "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", 3419 "license": "MIT" 3420 }, 3421 "node_modules/jsdom": { 3422 "version": "26.1.0", 3423 "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-26.1.0.tgz", ··· 3470 "node": ">=6" 3471 } 3472 }, 3473 "node_modules/json5": { 3474 "version": "2.2.3", 3475 "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", ··· 3482 "node": ">=6" 3483 } 3484 }, 3485 "node_modules/lie": { 3486 "version": "3.1.1", 3487 "resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz", ··· 3719 "url": "https://opencollective.com/parcel" 3720 } 3721 }, 3722 "node_modules/localforage": { 3723 "version": "1.10.0", 3724 "resolved": "https://registry.npmjs.org/localforage/-/localforage-1.10.0.tgz", ··· 3728 "lie": "3.1.1" 3729 } 3730 }, 3731 "node_modules/loose-envify": { 3732 "version": "1.4.0", 3733 "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", ··· 3747 "dev": true, 3748 "license": "MIT" 3749 }, 3750 "node_modules/lru-cache": { 3751 "version": "5.1.1", 3752 "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", ··· 3767 } 3768 }, 3769 "node_modules/magic-string": { 3770 - "version": "0.30.18", 3771 - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.18.tgz", 3772 - "integrity": "sha512-yi8swmWbO17qHhwIBNeeZxTceJMeBvWJaId6dyvTSOwTipqeHhMhOrz6513r1sOKnpvQ7zkhlG8tPrpilwTxHQ==", 3773 "license": "MIT", 3774 "dependencies": { 3775 "@jridgewell/sourcemap-codec": "^1.5.5" 3776 } 3777 }, 3778 "node_modules/media-chrome": { ··· 3791 "integrity": "sha512-9P2FuUHnZZ3iji+2RQk7Zkh5AmZTnOG5fODACnjhCVveX1McY3jmCRHofIEI+yTBqplz7LXy48c7fQ3Uigp88w==", 3792 "license": "MIT" 3793 }, 3794 "node_modules/minipass": { 3795 "version": "7.1.2", 3796 "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", ··· 3827 "url": "https://github.com/sponsors/isaacs" 3828 } 3829 }, 3830 "node_modules/ms": { 3831 "version": "2.1.3", 3832 "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", ··· 3869 "integrity": "sha512-zkVhZUA3y8mbz652WrL5x0fB0ehrBkulWT3TomAQ9iDtyXZvzKeEA6GPxAItBYeNYl5yngKRX612qHOhvMkDeg==", 3870 "license": "MIT" 3871 }, 3872 "node_modules/node-releases": { 3873 "version": "2.0.19", 3874 "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", ··· 3884 "node": ">=0.10.0" 3885 } 3886 }, 3887 "node_modules/nwsapi": { 3888 "version": "2.2.21", 3889 "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.21.tgz", ··· 3900 "node": ">=0.10.0" 3901 } 3902 }, 3903 "node_modules/parse5": { 3904 "version": "7.3.0", 3905 "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", ··· 3919 "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", 3920 "license": "MIT" 3921 }, 3922 "node_modules/pathe": { 3923 "version": "2.0.3", 3924 "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", ··· 3954 "url": "https://github.com/sponsors/jonschlinkert" 3955 } 3956 }, 3957 "node_modules/player.style": { 3958 "version": "0.1.10", 3959 "resolved": "https://registry.npmjs.org/player.style/-/player.style-0.1.10.tgz", ··· 3970 "media-chrome": "~4.11.0" 3971 } 3972 }, 3973 "node_modules/postcss": { 3974 "version": "8.5.6", 3975 "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", ··· 3998 "node": "^10 || ^12 || >=14" 3999 } 4000 }, 4001 "node_modules/prettier": { 4002 "version": "3.6.2", 4003 "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", ··· 4055 "node": ">=6" 4056 } 4057 }, 4058 "node_modules/react": { 4059 "version": "19.1.1", 4060 "resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz", ··· 4116 "node": ">=0.10.0" 4117 } 4118 }, 4119 "node_modules/readdirp": { 4120 "version": "3.6.0", 4121 "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", ··· 4153 "node": ">=0.10.0" 4154 } 4155 }, 4156 "node_modules/resolve-pkg-maps": { 4157 "version": "1.0.0", 4158 "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", ··· 4162 "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" 4163 } 4164 }, 4165 "node_modules/rollup": { 4166 "version": "4.49.0", 4167 "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.49.0.tgz", ··· 4208 "dev": true, 4209 "license": "MIT" 4210 }, 4211 "node_modules/safer-buffer": { 4212 "version": "2.1.2", 4213 "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", ··· 4240 "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", 4241 "license": "MIT" 4242 }, 4243 "node_modules/semver": { 4244 "version": "6.3.1", 4245 "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", ··· 4270 "seroval": "^1.0" 4271 } 4272 }, 4273 "node_modules/siginfo": { 4274 "version": "2.0.0", 4275 "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", ··· 4277 "dev": true, 4278 "license": "ISC" 4279 }, 4280 "node_modules/solid-js": { 4281 "version": "1.9.9", 4282 "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.9.9.tgz", ··· 4326 "dev": true, 4327 "license": "MIT" 4328 }, 4329 "node_modules/strip-literal": { 4330 - "version": "3.0.0", 4331 - "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.0.0.tgz", 4332 - "integrity": "sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==", 4333 "dev": true, 4334 "license": "MIT", 4335 "dependencies": { ··· 4352 "integrity": "sha512-9pP/CVNp4NF2MNlRzLwQkjiTgKKe9WYXrLh9+8QokWmMxz+zt2mf1utkWLco26IuA3AfVcTb//qtlTIjY3VHxA==", 4353 "license": "MIT" 4354 }, 4355 "node_modules/symbol-tree": { 4356 "version": "3.2.4", 4357 "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", ··· 4364 "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.12.tgz", 4365 "integrity": "sha512-DzFtxOi+7NsFf7DBtI3BJsynR+0Yp6etH+nRPTbpWnS2pZBaSksv/JGctNwSWzbFjp0vxSqknaUylseZqMDGrA==", 4366 "license": "MIT" 4367 }, 4368 "node_modules/tapable": { 4369 "version": "2.2.3", ··· 4437 "license": "MIT" 4438 }, 4439 "node_modules/tinyglobby": { 4440 - "version": "0.2.14", 4441 - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", 4442 - "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", 4443 "license": "MIT", 4444 "dependencies": { 4445 - "fdir": "^6.4.4", 4446 - "picomatch": "^4.0.2" 4447 }, 4448 "engines": { 4449 "node": ">=12.0.0" ··· 4578 "node": ">=18" 4579 } 4580 }, 4581 "node_modules/tslib": { 4582 "version": "2.8.1", 4583 "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", ··· 4609 "integrity": "sha512-SDpZ4f7sZmwHF6XG5PF0KWuP18pH/kNG04MhTcpqJby7Lk/D3TS/lCYd+RSg0rIAAVi1LDgSIo1yJs9kmHlhgw==", 4610 "license": "MIT" 4611 }, 4612 "node_modules/typescript": { 4613 - "version": "5.9.2", 4614 - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", 4615 - "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", 4616 "dev": true, 4617 "license": "Apache-2.0", 4618 "bin": { ··· 4623 "node": ">=14.17" 4624 } 4625 }, 4626 "node_modules/ua-parser-js": { 4627 "version": "1.0.41", 4628 "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.41.tgz", ··· 4649 "node": "*" 4650 } 4651 }, 4652 "node_modules/uint8arrays": { 4653 "version": "3.0.0", 4654 "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.0.0.tgz", ··· 4658 "multiformats": "^9.4.2" 4659 } 4660 }, 4661 "node_modules/undici-types": { 4662 "version": "7.10.0", 4663 "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", ··· 4665 "devOptional": true, 4666 "license": "MIT" 4667 }, 4668 "node_modules/unplugin": { 4669 - "version": "2.3.9", 4670 - "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.9.tgz", 4671 - "integrity": "sha512-2dcbZq6aprwXTkzptq3k5qm5B8cvpjG9ynPd5fyM2wDJuuF7PeUK64Sxf0d+X1ZyDOeGydbNzMqBSIVlH8GIfA==", 4672 "license": "MIT", 4673 "dependencies": { 4674 "@jridgewell/remapping": "^2.3.5", ··· 4680 "node": ">=18.12.0" 4681 } 4682 }, 4683 "node_modules/unplugin/node_modules/picomatch": { 4684 "version": "4.0.3", 4685 "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", ··· 4720 }, 4721 "peerDependencies": { 4722 "browserslist": ">= 4.21.0" 4723 } 4724 }, 4725 "node_modules/use-sync-external-store": { ··· 5034 "node": ">=18" 5035 } 5036 }, 5037 "node_modules/why-is-node-running": { 5038 "version": "2.3.0", 5039 "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", ··· 5060 "super-media-element": "~1.4.2" 5061 } 5062 }, 5063 "node_modules/ws": { 5064 "version": "8.18.3", 5065 "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", ··· 5104 "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", 5105 "license": "ISC" 5106 }, 5107 "node_modules/youtube-video-element": { 5108 "version": "1.6.2", 5109 "resolved": "https://registry.npmjs.org/youtube-video-element/-/youtube-video-element-1.6.2.tgz", ··· 5117 "license": "MIT", 5118 "funding": { 5119 "url": "https://github.com/sponsors/colinhacks" 5120 } 5121 } 5122 }
··· 7 "name": "red-dwarf-tanstack", 8 "dependencies": { 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", 15 "@tailwindcss/vite": "^4.0.6", 16 + "@tanstack/query-sync-storage-persister": "^5.85.6", 17 "@tanstack/react-devtools": "^0.2.2", 18 "@tanstack/react-query": "^5.85.6", 19 + "@tanstack/react-query-persist-client": "^5.85.6", 20 "@tanstack/react-router": "^1.130.2", 21 "@tanstack/react-router-devtools": "^1.131.5", 22 "@tanstack/router-plugin": "^1.121.2", 23 + "dompurify": "^3.3.0", 24 + "i": "^0.3.7", 25 "idb-keyval": "^6.2.2", 26 "jotai": "^2.13.1", 27 + "npm": "^11.6.2", 28 + "radix-ui": "^1.4.3", 29 "react": "^19.0.0", 30 "react-dom": "^19.0.0", 31 "react-player": "^3.3.2", 32 + "tailwindcss": "^4.0.6", 33 + "tanstack-router-keepalive": "^1.0.0" 34 }, 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", 43 "@testing-library/dom": "^10.4.0", 44 "@testing-library/react": "^16.2.0", 45 "@types/node": "^24.3.0", 46 "@types/react": "^19.0.8", 47 "@types/react-dom": "^19.0.3", 48 + "@typescript-eslint/eslint-plugin": "^8.46.1", 49 + "@typescript-eslint/parser": "^8.46.1", 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", 56 "jsdom": "^26.0.0", 57 "prettier": "^3.6.2", 58 "typescript": "^5.7.2", 59 + "typescript-eslint": "^8.46.1", 60 + "unplugin-auto-import": "^20.2.0", 61 + "unplugin-icons": "^22.4.2", 62 "vite": "^6.3.5", 63 "vitest": "^3.0.5", 64 "web-vitals": "^4.2.4" ··· 75 }, 76 "engines": { 77 "node": ">=6.0.0" 78 + } 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 }, 111 "node_modules/@asamuzakjp/css-color": { ··· 129 "dev": true, 130 "license": "ISC" 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 + }, 205 "node_modules/@atproto/api": { 206 "version": "0.16.6", 207 "resolved": "https://registry.npmjs.org/@atproto/api/-/api-0.16.6.tgz", ··· 219 } 220 }, 221 "node_modules/@atproto/common-web": { 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==", 225 "license": "MIT", 226 "dependencies": { 227 "graphemer": "^1.4.0", ··· 230 "zod": "^3.23.8" 231 } 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 + }, 273 "node_modules/@atproto/lexicon": { 274 + "version": "0.5.1", 275 + "resolved": "https://registry.npmjs.org/@atproto/lexicon/-/lexicon-0.5.1.tgz", 276 + "integrity": "sha512-y8AEtYmfgVl4fqFxqXAeGvhesiGkxiy3CWoJIfsFDDdTlZUC8DFnZrYhcqkIop3OlCkkljvpSJi1hbeC1tbi8A==", 277 "license": "MIT", 278 "dependencies": { 279 + "@atproto/common-web": "^0.4.3", 280 "@atproto/syntax": "^0.4.1", 281 "iso-datestring-validator": "^2.2.2", 282 "multiformats": "^9.9.0", 283 "zod": "^3.23.8" 284 } 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 + }, 335 "node_modules/@atproto/syntax": { 336 "version": "0.4.1", 337 "resolved": "https://registry.npmjs.org/@atproto/syntax/-/syntax-0.4.1.tgz", ··· 339 "license": "MIT" 340 }, 341 "node_modules/@atproto/xrpc": { 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==", 345 "license": "MIT", 346 "dependencies": { 347 + "@atproto/lexicon": "^0.5.1", 348 "zod": "^3.23.8" 349 } 350 }, ··· 1326 "node": ">=18" 1327 } 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 + }, 1774 "node_modules/@isaacs/fs-minipass": { 1775 "version": "4.0.1", 1776 "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", ··· 1896 "mux-embed": "^5.8.3" 1897 } 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 + }, 3376 "node_modules/@rolldown/pluginutils": { 3377 "version": "1.0.0-beta.27", 3378 "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", ··· 3687 "solid-js": "^1.6.12" 3688 } 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 + }, 3928 "node_modules/@svta/common-media-library": { 3929 "version": "0.12.4", 3930 "resolved": "https://registry.npmjs.org/@svta/common-media-library/-/common-media-library-0.12.4.tgz", ··· 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 + }, 4306 "node_modules/@tanstack/react-devtools": { 4307 "version": "0.2.2", 4308 "resolved": "https://registry.npmjs.org/@tanstack/react-devtools/-/react-devtools-0.2.2.tgz", ··· 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" 4359 } 4360 }, ··· 4716 "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", 4717 "license": "MIT" 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 + }, 4727 "node_modules/@types/node": { 4728 "version": "24.3.0", 4729 "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.0.tgz", ··· 4752 "@types/react": "^19.0.0" 4753 } 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 + }, 5033 "node_modules/@vercel/edge": { 5034 "version": "1.2.2", 5035 "resolved": "https://registry.npmjs.org/@vercel/edge/-/edge-1.2.2.tgz", ··· 5194 "node": ">=0.4.0" 5195 } 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 + }, 5208 "node_modules/agent-base": { 5209 "version": "7.1.4", 5210 "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", ··· 5215 "node": ">= 14" 5216 } 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 + }, 5236 "node_modules/ansi-regex": { 5237 "version": "5.0.1", 5238 "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", ··· 5278 "node": ">= 8" 5279 } 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 + }, 5299 "node_modules/aria-query": { 5300 "version": "5.3.0", 5301 "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", ··· 5306 "dequal": "^2.0.3" 5307 } 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 + }, 5447 "node_modules/assertion-error": { 5448 "version": "2.0.1", 5449 "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", ··· 5466 "node": ">=4" 5467 } 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 + }, 5495 "node_modules/await-lock": { 5496 "version": "2.2.2", 5497 "resolved": "https://registry.npmjs.org/await-lock/-/await-lock-2.2.2.tgz", ··· 5509 "@babel/traverse": "^7.23.7", 5510 "@babel/types": "^7.23.6" 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" 5529 }, 5530 "node_modules/bcp-47": { 5531 "version": "2.1.0", ··· 5578 "url": "https://github.com/sponsors/sindresorhus" 5579 } 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 + }, 5599 "node_modules/braces": { 5600 "version": "3.0.3", 5601 "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", ··· 5650 "node": ">=8" 5651 } 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 + }, 5726 "node_modules/caniuse-lite": { 5727 "version": "1.0.30001737", 5728 "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001737.tgz", ··· 5778 "node": ">=18" 5779 } 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 + }, 5816 "node_modules/check-error": { 5817 "version": "2.1.1", 5818 "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", ··· 5877 "integrity": "sha512-eNk3TRV+xQMJ1PEj0FQGY8KD4m0GPxT487XJ+Iftm7mVa9WpPFDMWqPt+46buiP5j5Wzqe5oMIhqBcAeKfygSA==", 5878 "license": "MIT" 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 + }, 5923 "node_modules/convert-source-map": { 5924 "version": "2.0.0", 5925 "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", ··· 5932 "integrity": "sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==", 5933 "license": "MIT" 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 + }, 5989 "node_modules/cssstyle": { 5990 "version": "4.6.0", 5991 "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.6.0.tgz", ··· 6054 "node": ">=18" 6055 } 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 + }, 6111 "node_modules/debug": { 6112 + "version": "4.4.3", 6113 + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", 6114 + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", 6115 "license": "MIT", 6116 "dependencies": { 6117 "ms": "^2.1.3" ··· 6142 "node": ">=6" 6143 } 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 + }, 6189 "node_modules/dequal": { 6190 "version": "2.0.3", 6191 "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", ··· 6205 "node": ">=8" 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==" 6212 + }, 6213 "node_modules/diff": { 6214 "version": "8.0.2", 6215 "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.2.tgz", ··· 6219 "node": ">=0.3.1" 6220 } 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 + }, 6235 "node_modules/dom-accessibility-api": { 6236 "version": "0.5.16", 6237 "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", ··· 6239 "dev": true, 6240 "license": "MIT" 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 + }, 6277 "node_modules/electron-to-chromium": { 6278 "version": "1.5.211", 6279 "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.211.tgz", ··· 6306 "url": "https://github.com/fb55/entities?sponsor=1" 6307 } 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 + }, 6436 "node_modules/es-module-lexer": { 6437 "version": "1.7.0", 6438 "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", ··· 6440 "dev": true, 6441 "license": "MIT" 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 + }, 6503 "node_modules/esbuild": { 6504 "version": "0.25.9", 6505 "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz", ··· 6550 "node": ">=6" 6551 } 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 + }, 6909 "node_modules/esprima": { 6910 "version": "4.0.1", 6911 "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", ··· 6919 "node": ">=4" 6920 } 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 + }, 6960 "node_modules/estree-walker": { 6961 "version": "3.0.3", 6962 "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", ··· 6967 "@types/estree": "^1.0.0" 6968 } 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 + }, 6986 "node_modules/expect-type": { 6987 "version": "1.2.2", 6988 "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz", ··· 6993 "node": ">=12.0.0" 6994 } 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 + }, 7003 "node_modules/fast-deep-equal": { 7004 "version": "3.1.3", 7005 "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", 7006 "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", 7007 "license": "MIT" 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 + }, 7066 "node_modules/fill-range": { 7067 "version": "7.1.1", 7068 "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", ··· 7075 "node": ">=8" 7076 } 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 + }, 7135 "node_modules/fsevents": { 7136 "version": "2.3.3", 7137 "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", ··· 7146 "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 7147 } 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 + }, 7200 "node_modules/gensync": { 7201 "version": "1.0.0-beta.2", 7202 "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", ··· 7206 "node": ">=6.9.0" 7207 } 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 + }, 7274 "node_modules/get-tsconfig": { 7275 "version": "4.10.1", 7276 "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz", ··· 7295 "node": ">= 6" 7296 } 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 + }, 7329 "node_modules/goober": { 7330 "version": "2.1.16", 7331 "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.16.tgz", ··· 7335 "csstype": "^3.0.10" 7336 } 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 + }, 7351 "node_modules/graceful-fs": { 7352 "version": "4.2.11", 7353 "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", ··· 7360 "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", 7361 "license": "MIT" 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 + }, 7475 "node_modules/hls-video-element": { 7476 "version": "1.5.7", 7477 "resolved": "https://registry.npmjs.org/hls-video-element/-/hls-video-element-1.5.7.tgz", ··· 7546 "node": ">= 14" 7547 } 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 + }, 7570 "node_modules/iconv-lite": { 7571 "version": "0.6.3", 7572 "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", ··· 7586 "integrity": "sha512-yjD9nARJ/jb1g+CvD0tlhUHOrJ9Sy0P8T9MF3YaLlHnSRpwPfpTX0XIvpmw3gAJUmEu3FiICLBDPXVwyEvrleg==", 7587 "license": "Apache-2.0" 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 + }, 7600 "node_modules/immediate": { 7601 "version": "3.0.6", 7602 "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", 7603 "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", 7604 "license": "MIT" 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 + }, 7623 "node_modules/imsc": { 7624 "version": "1.1.5", 7625 "resolved": "https://registry.npmjs.org/imsc/-/imsc-1.1.5.tgz", ··· 7629 "sax": "1.2.1" 7630 } 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 + }, 7658 "node_modules/is-alphabetical": { 7659 "version": "2.0.1", 7660 "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", ··· 7679 "url": "https://github.com/sponsors/wooorm" 7680 } 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 + }, 7743 "node_modules/is-binary-path": { 7744 "version": "2.1.0", 7745 "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", ··· 7752 "node": ">=8" 7753 } 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 + }, 7836 "node_modules/is-decimal": { 7837 "version": "2.0.1", 7838 "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", ··· 7852 "node": ">=0.10.0" 7853 } 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 + }, 7891 "node_modules/is-glob": { 7892 "version": "4.0.3", 7893 "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", ··· 7900 "node": ">=0.10.0" 7901 } 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 + }, 7945 "node_modules/is-number": { 7946 "version": "7.0.0", 7947 "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", ··· 7951 "node": ">=0.12.0" 7952 } 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 + }, 7971 "node_modules/is-potential-custom-element-name": { 7972 "version": "1.0.1", 7973 "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", ··· 7975 "dev": true, 7976 "license": "MIT" 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 + }, 8130 "node_modules/isbot": { 8131 "version": "5.1.30", 8132 "resolved": "https://registry.npmjs.org/isbot/-/isbot-5.1.30.tgz", ··· 8136 "node": ">=18" 8137 } 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 + }, 8147 "node_modules/iso-datestring-validator": { 8148 "version": "2.2.2", 8149 "resolved": "https://registry.npmjs.org/iso-datestring-validator/-/iso-datestring-validator-2.2.2.tgz", 8150 "integrity": "sha512-yLEMkBbLZTlVQqOnQ4FiMujR6T4DEcCb1xizmvXS+OxuhwcbtynoosRzdMA69zZCShCNAbi+gJ71FxZBBXx1SA==", 8151 "license": "MIT" 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 + }, 8171 "node_modules/jiti": { 8172 "version": "2.5.1", 8173 "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz", ··· 8175 "license": "MIT", 8176 "bin": { 8177 "jiti": "lib/jiti-cli.mjs" 8178 + } 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": { ··· 8221 "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", 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 + } 8236 + }, 8237 "node_modules/jsdom": { 8238 "version": "26.1.0", 8239 "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-26.1.0.tgz", ··· 8286 "node": ">=6" 8287 } 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 + }, 8320 "node_modules/json5": { 8321 "version": "2.2.3", 8322 "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", ··· 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" 8379 + } 8380 + }, 8381 "node_modules/lie": { 8382 "version": "3.1.1", 8383 "resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz", ··· 8615 "url": "https://opencollective.com/parcel" 8616 } 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 + }, 8643 "node_modules/localforage": { 8644 "version": "1.10.0", 8645 "resolved": "https://registry.npmjs.org/localforage/-/localforage-1.10.0.tgz", ··· 8649 "lie": "3.1.1" 8650 } 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 + }, 8683 "node_modules/loose-envify": { 8684 "version": "1.4.0", 8685 "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", ··· 8699 "dev": true, 8700 "license": "MIT" 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 + }, 8712 "node_modules/lru-cache": { 8713 "version": "5.1.1", 8714 "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", ··· 8729 } 8730 }, 8731 "node_modules/magic-string": { 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==", 8735 "license": "MIT", 8736 "dependencies": { 8737 "@jridgewell/sourcemap-codec": "^1.5.5" 8738 + } 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 }, 8750 "node_modules/media-chrome": { ··· 8763 "integrity": "sha512-9P2FuUHnZZ3iji+2RQk7Zkh5AmZTnOG5fODACnjhCVveX1McY3jmCRHofIEI+yTBqplz7LXy48c7fQ3Uigp88w==", 8764 "license": "MIT" 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 + }, 8803 "node_modules/minipass": { 8804 "version": "7.1.2", 8805 "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", ··· 8836 "url": "https://github.com/sponsors/isaacs" 8837 } 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 + }, 8871 "node_modules/ms": { 8872 "version": "2.1.3", 8873 "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", ··· 8910 "integrity": "sha512-zkVhZUA3y8mbz652WrL5x0fB0ehrBkulWT3TomAQ9iDtyXZvzKeEA6GPxAItBYeNYl5yngKRX612qHOhvMkDeg==", 8911 "license": "MIT" 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 + }, 8931 "node_modules/node-releases": { 8932 "version": "2.0.19", 8933 "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", ··· 8943 "node": ">=0.10.0" 8944 } 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 + }, 11354 "node_modules/nwsapi": { 11355 "version": "2.2.21", 11356 "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.21.tgz", ··· 11367 "node": ">=0.10.0" 11368 } 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 + }, 11578 "node_modules/parse5": { 11579 "version": "7.3.0", 11580 "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", ··· 11594 "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", 11595 "license": "MIT" 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 + }, 11636 "node_modules/pathe": { 11637 "version": "2.0.3", 11638 "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", ··· 11668 "url": "https://github.com/sponsors/jonschlinkert" 11669 } 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 + }, 11683 "node_modules/player.style": { 11684 "version": "0.1.10", 11685 "resolved": "https://registry.npmjs.org/player.style/-/player.style-0.1.10.tgz", ··· 11696 "media-chrome": "~4.11.0" 11697 } 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 + }, 11709 "node_modules/postcss": { 11710 "version": "8.5.6", 11711 "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", ··· 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" 11746 + } 11747 + }, 11748 "node_modules/prettier": { 11749 "version": "3.6.2", 11750 "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", ··· 11802 "node": ">=6" 11803 } 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 + }, 11919 "node_modules/react": { 11920 "version": "19.1.1", 11921 "resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz", ··· 11977 "node": ">=0.10.0" 11978 } 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 + }, 12046 "node_modules/readdirp": { 12047 "version": "3.6.0", 12048 "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", ··· 12080 "node": ">=0.10.0" 12081 } 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 + }, 12155 "node_modules/resolve-pkg-maps": { 12156 "version": "1.0.0", 12157 "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", ··· 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" 12173 + } 12174 + }, 12175 "node_modules/rollup": { 12176 "version": "4.49.0", 12177 "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.49.0.tgz", ··· 12218 "dev": true, 12219 "license": "MIT" 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 + }, 12300 "node_modules/safer-buffer": { 12301 "version": "2.1.2", 12302 "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", ··· 12329 "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", 12330 "license": "MIT" 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 + }, 12339 "node_modules/semver": { 12340 "version": "6.3.1", 12341 "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", ··· 12366 "seroval": "^1.0" 12367 } 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 + }, 12519 "node_modules/siginfo": { 12520 "version": "2.0.0", 12521 "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", ··· 12523 "dev": true, 12524 "license": "ISC" 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 + }, 12537 "node_modules/solid-js": { 12538 "version": "1.9.9", 12539 "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.9.9.tgz", ··· 12583 "dev": true, 12584 "license": "MIT" 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 + }, 12719 "node_modules/strip-literal": { 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==", 12723 "dev": true, 12724 "license": "MIT", 12725 "dependencies": { ··· 12742 "integrity": "sha512-9pP/CVNp4NF2MNlRzLwQkjiTgKKe9WYXrLh9+8QokWmMxz+zt2mf1utkWLco26IuA3AfVcTb//qtlTIjY3VHxA==", 12743 "license": "MIT" 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 + }, 12779 "node_modules/symbol-tree": { 12780 "version": "3.2.4", 12781 "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", ··· 12788 "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.12.tgz", 12789 "integrity": "sha512-DzFtxOi+7NsFf7DBtI3BJsynR+0Yp6etH+nRPTbpWnS2pZBaSksv/JGctNwSWzbFjp0vxSqknaUylseZqMDGrA==", 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 + } 12801 }, 12802 "node_modules/tapable": { 12803 "version": "2.2.3", ··· 12871 "license": "MIT" 12872 }, 12873 "node_modules/tinyglobby": { 12874 + "version": "0.2.15", 12875 + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", 12876 + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", 12877 "license": "MIT", 12878 "dependencies": { 12879 + "fdir": "^6.5.0", 12880 + "picomatch": "^4.0.3" 12881 }, 12882 "engines": { 12883 "node": ">=12.0.0" ··· 13012 "node": ">=18" 13013 } 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 + }, 13071 "node_modules/tslib": { 13072 "version": "2.8.1", 13073 "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", ··· 13099 "integrity": "sha512-SDpZ4f7sZmwHF6XG5PF0KWuP18pH/kNG04MhTcpqJby7Lk/D3TS/lCYd+RSg0rIAAVi1LDgSIo1yJs9kmHlhgw==", 13100 "license": "MIT" 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 + }, 13194 "node_modules/typescript": { 13195 + "version": "5.9.3", 13196 + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", 13197 + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", 13198 "dev": true, 13199 "license": "Apache-2.0", 13200 "bin": { ··· 13205 "node": ">=14.17" 13206 } 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 + }, 13232 "node_modules/ua-parser-js": { 13233 "version": "1.0.41", 13234 "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.41.tgz", ··· 13255 "node": "*" 13256 } 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 + }, 13265 "node_modules/uint8arrays": { 13266 "version": "3.0.0", 13267 "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.0.0.tgz", ··· 13271 "multiformats": "^9.4.2" 13272 } 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 + }, 13293 "node_modules/undici-types": { 13294 "version": "7.10.0", 13295 "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", ··· 13297 "devOptional": true, 13298 "license": "MIT" 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 + }, 13352 "node_modules/unplugin": { 13353 + "version": "2.3.10", 13354 + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.10.tgz", 13355 + "integrity": "sha512-6NCPkv1ClwH+/BGE9QeoTIl09nuiAt0gS28nn1PvYXsGKRwM2TCbFA2QiilmehPDTXIe684k4rZI1yl3A1PCUw==", 13356 "license": "MIT", 13357 "dependencies": { 13358 "@jridgewell/remapping": "^2.3.5", ··· 13364 "node": ">=18.12.0" 13365 } 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 + }, 13488 "node_modules/unplugin/node_modules/picomatch": { 13489 "version": "4.0.3", 13490 "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", ··· 13525 }, 13526 "peerDependencies": { 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 + } 13580 } 13581 }, 13582 "node_modules/use-sync-external-store": { ··· 13891 "node": ">=18" 13892 } 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 + }, 14000 "node_modules/why-is-node-running": { 14001 "version": "2.3.0", 14002 "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", ··· 14023 "super-media-element": "~1.4.2" 14024 } 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 + }, 14037 "node_modules/ws": { 14038 "version": "8.18.3", 14039 "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", ··· 14078 "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", 14079 "license": "ISC" 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 + }, 14095 "node_modules/youtube-video-element": { 14096 "version": "1.6.2", 14097 "resolved": "https://registry.npmjs.org/youtube-video-element/-/youtube-video-element-1.6.2.tgz", ··· 14105 "license": "MIT", 14106 "funding": { 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" 14121 } 14122 } 14123 }
+32 -3
package.json
··· 3 "private": true, 4 "type": "module", 5 "scripts": { 6 - "dev": "vite --port 3000", 7 - "start": "vite --port 3000", 8 "build": "vite build && tsc", 9 "serve": "vite preview", 10 "test": "vitest run" 11 }, 12 "dependencies": { 13 "@atproto/api": "^0.16.6", 14 "@tailwindcss/vite": "^4.0.6", 15 "@tanstack/react-devtools": "^0.2.2", 16 "@tanstack/react-query": "^5.85.6", 17 "@tanstack/react-router": "^1.130.2", 18 "@tanstack/react-router-devtools": "^1.131.5", 19 "@tanstack/router-plugin": "^1.121.2", 20 "idb-keyval": "^6.2.2", 21 "jotai": "^2.13.1", 22 "react": "^19.0.0", 23 "react-dom": "^19.0.0", 24 "react-player": "^3.3.2", 25 - "tailwindcss": "^4.0.6" 26 }, 27 "devDependencies": { 28 "@testing-library/dom": "^10.4.0", 29 "@testing-library/react": "^16.2.0", 30 "@types/node": "^24.3.0", 31 "@types/react": "^19.0.8", 32 "@types/react-dom": "^19.0.3", 33 "@vitejs/plugin-react": "^4.3.4", 34 "jsdom": "^26.0.0", 35 "prettier": "^3.6.2", 36 "typescript": "^5.7.2", 37 "vite": "^6.3.5", 38 "vitest": "^3.0.5", 39 "web-vitals": "^4.2.4"
··· 3 "private": true, 4 "type": "module", 5 "scripts": { 6 + "dev": "vite --port 3768", 7 + "start": "vite --port 3768", 8 "build": "vite build && tsc", 9 "serve": "vite preview", 10 "test": "vitest run" 11 }, 12 "dependencies": { 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", 19 "@tailwindcss/vite": "^4.0.6", 20 + "@tanstack/query-sync-storage-persister": "^5.85.6", 21 "@tanstack/react-devtools": "^0.2.2", 22 "@tanstack/react-query": "^5.85.6", 23 + "@tanstack/react-query-persist-client": "^5.85.6", 24 "@tanstack/react-router": "^1.130.2", 25 "@tanstack/react-router-devtools": "^1.131.5", 26 "@tanstack/router-plugin": "^1.121.2", 27 + "dompurify": "^3.3.0", 28 + "i": "^0.3.7", 29 "idb-keyval": "^6.2.2", 30 "jotai": "^2.13.1", 31 + "npm": "^11.6.2", 32 + "radix-ui": "^1.4.3", 33 "react": "^19.0.0", 34 "react-dom": "^19.0.0", 35 "react-player": "^3.3.2", 36 + "tailwindcss": "^4.0.6", 37 + "tanstack-router-keepalive": "^1.0.0" 38 }, 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", 47 "@testing-library/dom": "^10.4.0", 48 "@testing-library/react": "^16.2.0", 49 "@types/node": "^24.3.0", 50 "@types/react": "^19.0.8", 51 "@types/react-dom": "^19.0.3", 52 + "@typescript-eslint/eslint-plugin": "^8.46.1", 53 + "@typescript-eslint/parser": "^8.46.1", 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", 60 "jsdom": "^26.0.0", 61 "prettier": "^3.6.2", 62 "typescript": "^5.7.2", 63 + "typescript-eslint": "^8.46.1", 64 + "unplugin-auto-import": "^20.2.0", 65 + "unplugin-icons": "^22.4.2", 66 "vite": "^6.3.5", 67 "vitest": "^3.0.5", 68 "web-vitals": "^4.2.4"
+2 -2
public/manifest.json
··· 20 ], 21 "start_url": ".", 22 "display": "standalone", 23 - "theme_color": "#000000", 24 - "background_color": "#ffffff" 25 }
··· 20 ], 21 "start_url": ".", 22 "display": "standalone", 23 + "theme_color": "#180001", 24 + "background_color": "#180001" 25 }
public/screenshot.jpg

This is a binary file and will not be displayed.

public/screenshot.png

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 + }
+100 -13
src/components/InfiniteCustomFeed.tsx
··· 1 import * as React from "react"; 2 //import { useInView } from "react-intersection-observer"; 3 import { UniversalPostRendererATURILoader } from "~/components/UniversalPostRenderer"; 4 - import { useAuth } from "~/providers/PassAuthProvider"; 5 - import { useQueryArbitrary, useQueryIdentity, useInfiniteQueryFeedSkeleton } from "~/utils/useQuery"; 6 7 interface InfiniteCustomFeedProps { 8 feedUri: string; ··· 10 feedServiceDid?: string; 11 } 12 13 - export function InfiniteCustomFeed({ feedUri, pdsUrl, feedServiceDid }: InfiniteCustomFeedProps) { 14 - const { agent, authed } = useAuth(); 15 - 16 // const identityresultmaybe = useQueryIdentity(agent?.did); 17 // const identity = identityresultmaybe?.data; 18 // const feedGenGetRecordQuery = useQueryArbitrary(feedUri); ··· 25 hasNextPage, 26 fetchNextPage, 27 isFetchingNextPage, 28 } = useInfiniteQueryFeedSkeleton({ 29 feedUri: feedUri, 30 agent: agent ?? undefined, ··· 32 pdsUrl: pdsUrl, 33 feedServiceDid: feedServiceDid, 34 }); 35 36 //const { ref, inView } = useInView(); 37 ··· 46 } 47 48 if (isError) { 49 - return <div className="p-4 text-center text-red-500">Error: {error.message}</div>; 50 } 51 52 - const allPosts = data?.pages.flatMap((page) => {if (page) return page.feed}) ?? []; 53 54 if (!allPosts || typeof allPosts !== "object" || allPosts.length === 0) { 55 - return <div className="p-4 text-center text-gray-500">No posts in this feed.</div>; 56 } 57 58 return ( 59 <> 60 {allPosts.map((item, i) => { 61 - if (item) return ( 62 - <UniversalPostRendererATURILoader key={item.post || i} atUri={item.post} /> 63 - )})} 64 {/* allPosts?: {allPosts ? "true" : "false"} 65 hasNextPage?: {hasNextPage ? "true" : "false"} 66 isFetchingNextPage?: {isFetchingNextPage ? "true" : "false"} */} ··· 75 Load More Posts 76 </button> 77 )} 78 - {!hasNextPage && <div className="p-4 text-center text-gray-500">End of feed.</div>} 79 </> 80 ); 81 - }
··· 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; ··· 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); ··· 36 hasNextPage, 37 fetchNextPage, 38 isFetchingNextPage, 39 + refetch, 40 + isRefetching, 41 + queryKey, 42 } = useInfiniteQueryFeedSkeleton({ 43 feedUri: feedUri, 44 agent: agent ?? undefined, ··· 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 ··· 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"} */} ··· 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"; 3 4 - interface LoginProps { 5 compact?: boolean; 6 } 7 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); 14 const formRef = useRef<HTMLDivElement>(null); 15 16 useEffect(() => { 17 function handleClickOutside(event: MouseEvent) { 18 if (formRef.current && !formRef.current.contains(event.target as Node)) { 19 - setShowLoginForm(false); 20 } 21 } 22 - 23 - if (showLoginForm) { 24 document.addEventListener("mousedown", handleClickOutside); 25 } 26 - 27 return () => { 28 document.removeEventListener("mousedown", handleClickOutside); 29 }; 30 - }, [showLoginForm]); 31 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 - } 39 40 - if (compact) { 41 - if (authed) { 42 - return ( 43 <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" 46 > 47 - Log out 48 </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 - ); 108 } 109 - } 110 111 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> 138 <input 139 type="text" 140 - placeholder="Username" 141 value={user} 142 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 /> 146 <input 147 - type="password" 148 - placeholder="Password" 149 value={password} 150 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 /> 154 <input 155 type="text" 156 - placeholder="bsky.social" 157 value={serviceURL} 158 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 /> 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> 170 ); 171 - } 172 173 - export const ProfileThing = () => { 174 - const { agent, loading, loginStatus, authed } = useAuth(); 175 - const [response, setResponse] = useState<any>(null); 176 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 - }; 194 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 - ); 203 } 204 205 - if (!response) { 206 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> 210 </div> 211 ); 212 } 213 214 return ( 215 - <div className="flex flex-row items-start gap-1.5"> 216 <img 217 - src={response?.avatar} 218 alt="avatar" 219 - className="w-[30px] h-[30px] rounded-full object-cover" 220 /> 221 - <div> 222 - <div className="text-gray-100 text-xs">{response?.displayName}</div> 223 - <div className="text-gray-100 text-xs">@{response?.handle}</div> 224 </div> 225 </div> 226 );
··· 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"; 5 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 + }: { 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} />; 90 } 91 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); 120 const formRef = useRef<HTMLDivElement>(null); 121 122 useEffect(() => { 123 function handleClickOutside(event: MouseEvent) { 124 if (formRef.current && !formRef.current.contains(event.target as Node)) { 125 + setShowForm(false); 126 } 127 } 128 + if (showForm) { 129 document.addEventListener("mousedown", handleClickOutside); 130 } 131 return () => { 132 document.removeEventListener("mousedown", handleClickOutside); 133 }; 134 + }, [showForm]); 135 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 + }; 154 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> 214 <button 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" 217 > 218 + Log in 219 </button> 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."); 245 } 246 + }; 247 248 return ( 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"> 277 <input 278 type="text" 279 + placeholder=" " 280 value={user} 281 onChange={(e) => setUser(e.target.value)} 282 /> 283 + <label>AT Handle</label> 284 + </div> 285 + <div className="m3input-field m3input-label m3input-border size-md flex-1"> 286 <input 287 + type="text" 288 + placeholder=" " 289 value={password} 290 onChange={(e) => setPassword(e.target.value)} 291 /> 292 + <label>App Password</label> 293 + </div> 294 + <div className="m3input-field m3input-label m3input-border size-md flex-1"> 295 <input 296 type="text" 297 + placeholder=" " 298 value={serviceURL} 299 onChange={(e) => setServiceURL(e.target.value)} 300 /> 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> 311 ); 312 + }; 313 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; 330 331 + const [imgcdn] = useAtom(imgCDNAtom) 332 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`; 337 } 338 339 + if (!profiledata) { 340 return ( 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> 356 </div> 357 ); 358 } 359 360 return ( 361 + <div 362 + className={`flex flex-row items-center gap-2.5 ${large ? "mb-1" : ""}`} 363 + > 364 <img 365 + src={getAvatarUrl(profile) ?? undefined} 366 alt="avatar" 367 + className={`object-cover rounded-full ${large ? "w-10 h-10" : "w-[30px] h-[30px]"}`} 368 /> 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> 380 </div> 381 </div> 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 + }
+911 -557
src/components/UniversalPostRenderer.tsx
··· 1 import * as React from "react"; 2 - import { usePersistentStore } from "~/providers/PersistentStoreProvider"; 3 - import { useNavigate } from "@tanstack/react-router"; 4 import { type SVGProps } from "react"; 5 import { useHydratedEmbed } from "~/utils/useHydrated"; 6 import { 7 useQueryPost, 8 - useQueryIdentity, 9 useQueryProfile, 10 - useQueryConstellation, 11 } from "~/utils/useQuery"; 12 13 function asTyped<T extends { $type: string }>(obj: T): $Typed<T> { ··· 25 topReplyLine?: boolean; 26 bottomBorder?: boolean; 27 feedviewpost?: boolean; 28 } 29 30 // export async function cachedGetRecord({ ··· 128 topReplyLine, 129 bottomBorder = true, 130 feedviewpost = false, 131 }: UniversalPostRendererATURILoaderProps) { 132 - console.log("atUri", atUri); 133 //const { get, set } = usePersistentStore(); 134 //const [record, setRecord] = React.useState<any>(null); 135 //const [links, setLinks] = React.useState<any>(null); ··· 142 // >(null); 143 //const router = useRouter(); 144 145 - const parsed = React.useMemo(() => parseAtUri(atUri), [atUri]); 146 - const did = parsed?.did; 147 const rkey = parsed?.rkey; 148 - console.log("did", did); 149 - console.log("rkey", rkey); 150 151 // React.useEffect(() => { 152 // const checkCache = async () => { ··· 154 // const cacheKey = `record:${postUri}`; 155 // const cached = await get(cacheKey); 156 // const now = Date.now(); 157 - // console.log( 158 // "UniversalPostRenderer checking cache for", 159 // cacheKey, 160 // "cached:", ··· 167 // now - cached.time < CACHE_TIMEOUT 168 // ) { 169 // try { 170 - // console.log("UniversalPostRenderer found cached data for", cacheKey); 171 // setRecord(JSON.parse(cached.value)); 172 // } catch { 173 // setRecord(null); ··· 353 const [replies, setReplies] = React.useState<number | null>(null); 354 355 React.useEffect(() => { 356 - console.log(JSON.stringify(links, null, 2)); 357 setLikes( 358 links 359 ? links?.links?.["app.bsky.feed.like"]?.[".subject.uri"]?.records || 0 ··· 372 ); 373 }, [links]); 374 375 // const navigateToProfile = (e: React.MouseEvent) => { 376 // e.stopPropagation(); 377 // if (resolved?.did) { ··· 381 // }); 382 // } 383 // }; 384 385 return ( 386 - <UniversalPostRendererRawRecordShim 387 - detailed={detailed} 388 - postRecord={postQuery} 389 - profileRecord={opProfile} 390 - aturi={atUri} 391 - resolved={resolved} 392 - likesCount={likes} 393 - repostsCount={reposts} 394 - repliesCount={replies} 395 - bottomReplyLine={bottomReplyLine} 396 - topReplyLine={topReplyLine} 397 - bottomBorder={bottomBorder} 398 - feedviewpost={feedviewpost} 399 - /> 400 ); 401 } 402 403 export function UniversalPostRendererRawRecordShim({ 404 postRecord, 405 profileRecord, ··· 413 topReplyLine = false, 414 bottomBorder = true, 415 feedviewpost = false, 416 }: { 417 postRecord: any; 418 profileRecord: any; ··· 426 topReplyLine?: boolean; 427 bottomBorder?: boolean; 428 feedviewpost?: boolean; 429 }) { 430 - console.log(`received aturi: ${aturi} of post content: ${postRecord}`); 431 const navigate = useNavigate(); 432 433 //const { get, set } = usePersistentStore(); 434 - function getAvatarUrl(opProfile: any) { 435 - const link = opProfile?.value?.avatar?.ref?.["$link"]; 436 - if (!link) return null; 437 - return `https://cdn.bsky.app/img/avatar/plain/${resolved?.did}/${link}@jpeg`; 438 - } 439 - 440 // const [hydratedEmbed, setHydratedEmbed] = useState<any>(undefined); 441 442 // useEffect(() => { ··· 489 // result = hydrated instanceof Promise ? await hydrated : hydrated; 490 // } 491 492 - // console.log( 493 // String(result) + " hydrateEmbedRecordWithMedia hey hyeh ye", 494 // ); 495 // setHydratedEmbed(result); ··· 508 error: embedError, 509 } = useHydratedEmbed(postRecord?.value?.embed, resolved?.did); 510 511 - const parsedaturi = parseAtUri(aturi); 512 513 const fakepost = React.useMemo<AppBskyFeedDefs.PostView>( 514 () => ({ 515 $type: "app.bsky.feed.defs#postView", 516 uri: aturi, 517 cid: postRecord?.cid || "", 518 - author: { 519 - did: resolved?.did || "", 520 - handle: resolved?.handle || "", 521 - displayName: profileRecord?.value?.displayName || "", 522 - avatar: getAvatarUrl(profileRecord) || "", 523 - viewer: undefined, 524 - labels: profileRecord?.labels || undefined, 525 - verification: undefined, 526 - }, 527 record: postRecord?.value || {}, 528 embed: hydratedEmbed ?? undefined, 529 replyCount: repliesCount ?? 0, ··· 537 }), 538 [ 539 aturi, 540 - postRecord, 541 - profileRecord, 542 hydratedEmbed, 543 repliesCount, 544 repostsCount, 545 likesCount, 546 - resolved, 547 ] 548 ); 549 ··· 583 feedviewpost ? feedviewpostreplydid : undefined 584 ); 585 const feedviewpostreplyhandle = replyhookvalue?.data?.handle; 586 return ( 587 <> 588 {/* <p> ··· 594 parsedaturi && 595 navigate({ 596 to: "/profile/$did/post/$rkey", 597 - params: { did: parsedaturi.did, rkey: parsedaturi.rkey }, 598 }) 599 } 600 // onProfileClick={() => parsedaturi && navigate({to: "/profile/$did", ··· 605 if (parsedaturi) { 606 navigate({ 607 to: "/profile/$did", 608 - params: { did: parsedaturi.did }, 609 }); 610 } 611 }} 612 post={fakepost} 613 salt={aturi} 614 bottomReplyLine={bottomReplyLine} 615 topReplyLine={topReplyLine} 616 bottomBorder={bottomBorder} 617 //extraOptionalItemInfo={{reply: postRecord?.value?.reply as AppBskyFeedDefs.ReplyRef, post: fakepost}} 618 feedviewpostreplyhandle={feedviewpostreplyhandle} 619 /> 620 </> 621 ); 622 } 623 624 - export function parseAtUri( 625 - atUri: string 626 - ): { did: string; collection: string; rkey: string } | null { 627 - const PREFIX = "at://"; 628 - if (!atUri.startsWith(PREFIX)) { 629 - return null; 630 - } 631 632 - const parts = atUri.slice(PREFIX.length).split("/"); 633 634 - if (parts.length !== 3) { 635 - return null; 636 - } 637 638 - const [did, collection, rkey] = parts; 639 640 - if (!did || !collection || !rkey) { 641 - return null; 642 - } 643 644 - return { did, collection, rkey }; 645 - } 646 647 export function MdiCommentOutline(props: SVGProps<SVGSVGElement>) { 648 return ( ··· 654 {...props} 655 > 656 <path 657 - fill="oklch(0.704 0.05 28)" 658 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" 659 ></path> 660 </svg> ··· 671 {...props} 672 > 673 <path 674 - fill="oklch(0.704 0.05 28)" 675 d="M17 17H7v-3l-4 4l4 4v-3h12v-6h-2M7 7h10v3l4-4l-4-4v3H5v6h2z" 676 ></path> 677 </svg> ··· 722 {...props} 723 > 724 <path 725 - fill="oklch(0.704 0.05 28)" 726 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" 727 ></path> 728 </svg> ··· 739 {...props} 740 > 741 <path 742 - fill="oklch(0.704 0.05 28)" 743 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" 744 ></path> 745 </svg> ··· 756 {...props} 757 > 758 <path 759 - fill="oklch(0.704 0.05 28)" 760 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" 761 ></path> 762 </svg> ··· 773 {...props} 774 > 775 <path 776 - fill="oklch(0.704 0.05 28)" 777 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" 778 ></path> 779 </svg> ··· 807 {...props} 808 > 809 <path 810 - fill="oklch(0.704 0.05 28)" 811 d="M10 9V5l-7 7l7 7v-4.1c5 0 8.5 1.6 11 5.1c-1-5-4-10-11-11" 812 ></path> 813 </svg> ··· 861 {...props} 862 > 863 <path 864 - fill="oklch(0.704 0.05 28)" 865 d="M17 17H7v-3l-4 4l4 4v-3h12v-6h-2M7 7h10v3l4-4l-4-4v3H5v6h2z" 866 ></path> 867 </svg> ··· 878 {...props} 879 > 880 <path 881 - fill="oklch(0.704 0.05 28)" 882 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" 883 ></path> 884 </svg> ··· 903 } 904 905 /* what imported from testfront */ 906 - import defaultpfp from "~/../public/favicon.png"; 907 - 908 //import Masonry from "@mui/lab/Masonry"; 909 import { 910 AppBskyActorDefs, 911 - AppBskyActorProfile, 912 AppBskyEmbedDefs, 913 AppBskyEmbedExternal, 914 AppBskyEmbedImages, ··· 919 AppBskyFeedPost, 920 AppBskyGraphDefs, 921 AtUri, 922 //AppBskyLabelerDefs, 923 //AtUri, 924 //ComAtprotoRepoStrongRef, 925 ModerationDecision, 926 - type $Typed, 927 - type Facet, 928 } from "@atproto/api"; 929 import type { 930 //BlockedPost, ··· 933 PostView, 934 //ThreadViewPost, 935 } from "@atproto/api/dist/client/types/app/bsky/feed/defs"; 936 import { useEffect, useRef, useState } from "react"; 937 import ReactPlayer from "react-player"; 938 - import { useAuth } from "~/providers/PassAuthProvider"; 939 // import type { OutputSchema } from "@atproto/api/dist/client/types/app/bsky/feed/getFeed"; 940 // import type { 941 // ViewRecord, ··· 1043 1044 function UniversalPostRenderer({ 1045 post, 1046 //setMainItem, 1047 //isMainItem, 1048 onPostClick, ··· 1058 bottomBorder = true, 1059 feedviewpostreplyhandle, 1060 depth = 0, 1061 }: { 1062 post: PostView; 1063 // optional for now because i havent ported every use to this yet 1064 // setMainItem?: React.Dispatch< 1065 // React.SetStateAction<AppBskyFeedDefs.FeedViewPost> ··· 1076 bottomBorder?: boolean; 1077 feedviewpostreplyhandle?: string; 1078 depth?: number; 1079 }) { 1080 const navigate = useNavigate(); 1081 - const [hasRetweeted, setHasRetweeted] = useState<Boolean>( 1082 post.viewer?.repost ? true : false 1083 ); 1084 - const [hasLiked, setHasLiked] = useState<Boolean>( 1085 - post.viewer?.like ? true : false 1086 ); 1087 const { agent } = useAuth(); 1088 const [likeUri, setLikeUri] = useState<string | undefined>(post.viewer?.like); 1089 const [retweetUri, setRetweetUri] = useState<string | undefined>( ··· 1091 ); 1092 1093 const likeOrUnlikePost = async () => { 1094 if (!agent) { 1095 console.error("Agent is null or undefined"); 1096 return; 1097 } 1098 if (hasLiked) { 1099 if (likeUri) { 1100 await agent.deleteLike(likeUri); 1101 setHasLiked(false); 1102 } 1103 } else { 1104 const { uri } = await agent.like(post.uri, post.cid); 1105 setLikeUri(uri); 1106 setHasLiked(true); 1107 } 1108 }; 1109 1110 const repostOrUnrepostPost = async () => { ··· 1124 } 1125 }; 1126 1127 - const isRepost = extraOptionalItemInfo 1128 - ? AppBskyFeedDefs.isReasonRepost(extraOptionalItemInfo.reason) 1129 - ? extraOptionalItemInfo.reason?.by.displayName 1130 - : undefined 1131 - : undefined; 1132 const isReply = extraOptionalItemInfo 1133 ? extraOptionalItemInfo.reply 1134 : undefined; 1135 1136 const emergencySalt = randomString(); 1137 1138 /* fuck you */ 1139 const isMainItem = false; 1140 const setMainItem = (any: any) => {}; 1141 return ( 1142 - <div 1143 - key={salt + "-" + (post.uri || emergencySalt)} 1144 - onClick={ 1145 - isMainItem 1146 - ? onPostClick 1147 - : setMainItem 1148 ? onPostClick 1149 - ? (e) => { 1150 - setMainItem({ post: post }); 1151 - onPostClick(e); 1152 - } 1153 - : () => { 1154 - setMainItem({ post: post }); 1155 - } 1156 - : undefined 1157 - } 1158 - style={{ 1159 - //border: "1px solid #e1e8ed", 1160 - //borderRadius: 12, 1161 - opacity: "1 !important", 1162 - background: "transparent", 1163 - paddingLeft: isQuote ? 12 : 16, 1164 - paddingRight: isQuote ? 12 : 16, 1165 - //paddingTop: 16, 1166 - paddingTop: isRepost ? 10 : isQuote ? 12 : 16, 1167 - //paddingBottom: bottomReplyLine ? 0 : 16, 1168 - paddingBottom: 0, 1169 - fontFamily: "system-ui, sans-serif", 1170 - //boxShadow: "0 2px 8px rgba(0,0,0,0.04)", 1171 - position: "relative", 1172 - // dont cursor: "pointer", 1173 - borderBottomWidth: bottomBorder ? (isQuote ? 0 : 1) : 0, 1174 - }} 1175 - className="border-gray-300 dark:border-gray-600" 1176 - > 1177 - {isRepost && ( 1178 - <div 1179 - style={{ 1180 - marginLeft: 36, 1181 - display: "flex", 1182 - borderRadius: 12, 1183 - paddingBottom: "calc(22px - 1rem)", 1184 - fontSize: 14, 1185 - maxHeight: "1rem", 1186 - justifyContent: "flex-start", 1187 - //color: theme.textSecondary, 1188 - gap: 4, 1189 - alignItems: "center", 1190 - }} 1191 - className="text-gray-500 dark:text-gray-400" 1192 - > 1193 - <MdiRepost /> Reposted by {isRepost}{" "} 1194 - </div> 1195 - )} 1196 - {!isQuote && ( 1197 - <div 1198 - style={{ 1199 - opacity: topReplyLine || (isReply && (true || expanded)) ? 0.5 : 0, 1200 - position: "absolute", 1201 - top: 0, 1202 - left: 36, // why 36 ??? 1203 - //left: 16 + (42 / 2), 1204 - width: 2, 1205 - //height: "100%", 1206 - height: isRepost ? "calc(16px + 1rem - 6px)" : 16 - 6, 1207 - // background: theme.textSecondary, 1208 - //opacity: 0.5, 1209 - // no flex here 1210 - }} 1211 - className="bg-gray-500 dark:bg-gray-400" 1212 - /> 1213 - )} 1214 - <div 1215 style={{ 1216 - position: "absolute", 1217 - //top: isRepost ? "calc(16px + 1rem)" : 16, 1218 - //left: 16, 1219 - zIndex: 1, 1220 - top: isRepost ? "calc(16px + 1rem)" : isQuote ? 12 : 16, 1221 - left: isQuote ? 12 : 16, 1222 }} 1223 - onClick={onProfileClick} 1224 > 1225 - <img 1226 - src={post.author.avatar || defaultpfp} 1227 - alt="avatar" 1228 - // transition={{ 1229 - // type: "spring", 1230 - // stiffness: 260, 1231 - // damping: 20, 1232 - // }} 1233 - style={{ 1234 - borderRadius: "50%", 1235 - marginRight: 12, 1236 - objectFit: "cover", 1237 - //background: theme.border, 1238 - //border: `1px solid ${theme.border}`, 1239 - width: isQuote ? 16 : 42, 1240 - height: isQuote ? 16 : 42, 1241 - }} 1242 - className="border border-gray-300 dark:border-gray-600 bg-gray-300 dark:bg-gray-600" 1243 - /> 1244 - </div> 1245 - <div style={{ display: "flex", alignItems: "flex-start", zIndex: 2 }}> 1246 - <div 1247 - style={{ 1248 - display: "flex", 1249 - flexDirection: "column", 1250 - alignSelf: "stretch", 1251 - alignItems: "center", 1252 - overflow: "hidden", 1253 - width: expanded || isQuote ? 0 : "auto", 1254 - marginRight: expanded || isQuote ? 0 : 12, 1255 - }} 1256 - > 1257 - {/* dummy for later use */} 1258 - <div style={{ width: 42, height: 42 + 8, minHeight: 42 + 8 }} /> 1259 - {/* reply line !!!! bottomReplyLine */} 1260 - {bottomReplyLine && ( 1261 <div 1262 style={{ 1263 - width: 2, 1264 - height: "100%", 1265 - //background: theme.textSecondary, 1266 - opacity: 0.5, 1267 - // no flex here 1268 - //color: "Red", 1269 - //zIndex: 99 1270 }} 1271 - className="bg-gray-500 dark:bg-gray-400" 1272 - /> 1273 - )} 1274 - {/* <div 1275 layout 1276 transition={{ duration: 0.2 }} 1277 animate={{ height: expanded ? 0 : '100%' }} ··· 1281 // no flex here 1282 }} 1283 /> */} 1284 - </div> 1285 - <div style={{ flex: 1, maxWidth: "100%" }}> 1286 - <div 1287 - style={{ 1288 - display: "flex", 1289 - flexDirection: "row", 1290 - alignItems: "center", 1291 - flexWrap: "nowrap", 1292 - maxWidth: `calc(100% - ${!expanded ? (isQuote ? 26 : 0) : 54}px)`, 1293 - width: `calc(100% - ${!expanded ? (isQuote ? 26 : 0) : 54}px)`, 1294 - marginLeft: !expanded ? (isQuote ? 26 : 0) : 54, 1295 - marginBottom: !expanded ? 4 : 0, 1296 - }} 1297 - > 1298 <div 1299 style={{ 1300 display: "flex", 1301 - //overflow: "hidden", // hey why is overflow hidden unapplied 1302 - overflow: "hidden", 1303 - textOverflow: "ellipsis", 1304 - flexShrink: 1, 1305 - flexGrow: 1, 1306 - flexBasis: 0, 1307 - width: 0, 1308 - gap: expanded ? 0 : 6, 1309 - alignItems: expanded ? "flex-start" : "center", 1310 - flexDirection: expanded ? "column" : "row", 1311 - height: expanded ? 48 : "1rem", 1312 }} 1313 > 1314 - <span 1315 style={{ 1316 display: "flex", 1317 - fontWeight: 700, 1318 - fontSize: 16, 1319 overflow: "hidden", 1320 textOverflow: "ellipsis", 1321 - whiteSpace: "nowrap", 1322 flexShrink: 1, 1323 - minWidth: 0, 1324 - gap: 4, 1325 - alignItems: "center", 1326 - //color: theme.text, 1327 }} 1328 - className="text-gray-900 dark:text-gray-100" 1329 > 1330 - {/* verified checkmark */} 1331 - {post.author.displayName || post.author.handle}{" "} 1332 - {post.author.verification?.verifiedStatus == "valid" && ( 1333 - <MdiVerified /> 1334 - )} 1335 - </span> 1336 1337 - <span 1338 style={{ 1339 - //color: theme.textSecondary, 1340 - fontSize: 16, 1341 - overflowX: "hidden", 1342 - textOverflow: "ellipsis", 1343 - whiteSpace: "nowrap", 1344 - flexShrink: 1, 1345 - flexGrow: 0, 1346 - minWidth: 0, 1347 }} 1348 - className="text-gray-500 dark:text-gray-400" 1349 > 1350 - @{post.author.handle} 1351 - </span> 1352 </div> 1353 - <div 1354 - style={{ 1355 - display: "flex", 1356 - alignItems: "center", 1357 - height: "1rem", 1358 - }} 1359 - > 1360 - <span 1361 style={{ 1362 //color: theme.textSecondary, 1363 - fontSize: 16, 1364 - marginLeft: 8, 1365 - whiteSpace: "nowrap", 1366 - flexShrink: 0, 1367 - maxWidth: "100%", 1368 }} 1369 className="text-gray-500 dark:text-gray-400" 1370 > 1371 - ยท {/* time placeholder */} 1372 - {shortTimeAgo(post.indexedAt)} 1373 - </span> 1374 - </div> 1375 - </div> 1376 - {/* reply indicator */} 1377 - {!!feedviewpostreplyhandle && ( 1378 <div 1379 style={{ 1380 - display: "flex", 1381 - borderRadius: 12, 1382 - paddingBottom: 2, 1383 - fontSize: 14, 1384 - justifyContent: "flex-start", 1385 - //color: theme.textSecondary, 1386 - gap: 4, 1387 - alignItems: "center", 1388 - //marginLeft: 36, 1389 - height: 1390 - !(expanded || isQuote) && !!feedviewpostreplyhandle 1391 - ? "1rem" 1392 - : 0, 1393 - opacity: 1394 - !(expanded || isQuote) && !!feedviewpostreplyhandle ? 1 : 0, 1395 }} 1396 - className="text-gray-500 dark:text-gray-400" 1397 > 1398 - <MdiReply /> Reply to {feedviewpostreplyhandle} 1399 </div> 1400 - )} 1401 - <div 1402 - style={{ 1403 - fontSize: 16, 1404 - marginBottom: !post.embed /*|| depth > 0*/ ? 0 : 8, 1405 - whiteSpace: "pre-wrap", 1406 - textAlign: "left", 1407 - overflowWrap: "anywhere", 1408 - wordBreak: "break-word", 1409 - //color: theme.text, 1410 - }} 1411 - className="text-gray-900 dark:text-gray-100" 1412 - > 1413 - {renderTextWithFacets({ 1414 - text: (post.record as { text?: string }).text ?? "", 1415 - facets: (post.record.facets as Facet[]) ?? [], 1416 - navigate: navigate 1417 - })} 1418 - {} 1419 - </div> 1420 - {post.embed && depth < 1 ? ( 1421 - <PostEmbeds 1422 - embed={post.embed} 1423 - //moderation={moderation} 1424 - viewContext={PostEmbedViewContext.Feed} 1425 - salt={salt} 1426 - navigate={navigate} 1427 - /> 1428 - ) : null} 1429 - {post.embed && depth > 0 && ( 1430 - <> 1431 - <div className="border-gray-300 dark:border-gray-600 p-3 rounded-xl border italic text-gray-400"> 1432 - (there is an embed here thats too deep to render) 1433 - </div> 1434 - </> 1435 - )} 1436 - <div style={{ paddingTop: post.embed && depth < 1 ? 4 : 0 }}> 1437 - <> 1438 - {expanded && ( 1439 <div 1440 style={{ 1441 - overflow: "hidden", 1442 - //color: theme.textSecondary, 1443 - fontSize: 14, 1444 display: "flex", 1445 - borderBottomStyle: "solid", 1446 - //borderBottomColor: theme.border, 1447 - //background: "#f00", 1448 - // height: "1rem", 1449 - paddingTop: 4, 1450 - paddingBottom: 8, 1451 - borderBottomWidth: 1, 1452 - marginBottom: 8, 1453 - }} // important for height animation 1454 - className="text-gray-500 dark:text-gray-400 border-gray-200 dark:border-gray-700" 1455 - > 1456 - {fullDateTimeFormat(post.indexedAt)} 1457 - </div> 1458 - )} 1459 - </> 1460 - {!isQuote && ( 1461 - <div 1462 - style={{ 1463 - display: "flex", 1464 - gap: 32, 1465 - paddingTop: 8, 1466 - //color: theme.textSecondary, 1467 - fontSize: 15, 1468 - justifyContent: "space-between", 1469 - //background: "#0f0", 1470 - }} 1471 - className="text-gray-500 dark:text-gray-400" 1472 - > 1473 - <span style={btnstyle}> 1474 - <MdiCommentOutline /> 1475 - {post.replyCount} 1476 - </span> 1477 - <HitSlopButton 1478 - onClick={() => { 1479 - repostOrUnrepostPost(); 1480 - }} 1481 - style={{ 1482 - ...btnstyle, 1483 - ...(hasRetweeted ? { color: "#5CEFAA" } : {}), 1484 }} 1485 - > 1486 - {hasRetweeted ? <MdiRepeatGreen /> : <MdiRepeat />} 1487 - {(post.repostCount || 0) + (hasRetweeted ? 1 : 0)} 1488 - </HitSlopButton> 1489 - <HitSlopButton 1490 - onClick={() => { 1491 - likeOrUnlikePost(); 1492 - }} 1493 - style={{ 1494 - ...btnstyle, 1495 - ...(hasLiked ? { color: "#EC4899" } : {}), 1496 - }} 1497 > 1498 - {hasLiked ? <MdiCardsHeart /> : <MdiCardsHeartOutline />} 1499 - {(post.likeCount || 0) + (hasLiked ? 1 : 0)} 1500 - </HitSlopButton> 1501 - <div style={{ display: "flex", gap: 8 }}> 1502 <HitSlopButton 1503 - onClick={async (e) => { 1504 - e.stopPropagation(); 1505 - try { 1506 - await navigator.clipboard.writeText( 1507 - "https://bsky.app" + 1508 - "/profile/" + 1509 - post.author.handle + 1510 - "/post/" + 1511 - post.uri.split("/").pop() 1512 - ); 1513 - } catch {} 1514 }} 1515 style={{ 1516 ...btnstyle, 1517 }} 1518 > 1519 - <MdiShareVariant /> 1520 </HitSlopButton> 1521 - <span style={btnstyle}> 1522 - <MdiMoreHoriz /> 1523 - </span> 1524 </div> 1525 - </div> 1526 - )} 1527 </div> 1528 - <div 1529 - style={{ 1530 - //height: bottomReplyLine ? 16 : 0 1531 - height: isQuote ? 12 : 16, 1532 - }} 1533 - /> 1534 </div> 1535 </div> 1536 </div> ··· 1622 viewContext, 1623 salt, 1624 navigate, 1625 }: { 1626 embed?: Embed; 1627 moderation?: ModerationDecision; ··· 1629 allowNestedQuotes?: boolean; 1630 viewContext?: PostEmbedViewContext; 1631 salt: string; 1632 - navigate: ({}: any) => void; 1633 }) { 1634 - const [lightboxIndex, setLightboxIndex] = useState<number | null>(null); 1635 if ( 1636 AppBskyEmbedRecordWithMedia.isView(embed) && 1637 AppBskyEmbedRecord.isViewRecord(embed.record.record) && ··· 1665 viewContext={viewContext} 1666 salt={salt} 1667 navigate={navigate} 1668 /> 1669 {/* padding empty div of 8px height */} 1670 <div style={{ height: 12 }} /> ··· 1678 //boxShadow: theme.cardShadow, 1679 overflow: "hidden", 1680 }} 1681 - className="shadow border border-gray-200 dark:border-gray-700" 1682 > 1683 <UniversalPostRenderer 1684 post={post} ··· 1686 salt={salt} 1687 onPostClick={(e) => { 1688 e.stopPropagation(); 1689 - const parsed = parseAtUri(post.uri); 1690 if (parsed) { 1691 navigate({ 1692 to: "/profile/$did/post/$rkey", 1693 - params: { did: parsed.did, rkey: parsed.rkey }, 1694 }); 1695 } 1696 }} ··· 1795 //boxShadow: theme.cardShadow, 1796 overflow: "hidden", 1797 }} 1798 - className="shadow border border-gray-200 dark:border-gray-700" 1799 > 1800 <UniversalPostRenderer 1801 post={post} ··· 1803 salt={salt} 1804 onPostClick={(e) => { 1805 e.stopPropagation(); 1806 - const parsed = parseAtUri(post.uri); 1807 if (parsed) { 1808 navigate({ 1809 to: "/profile/$did/post/$rkey", 1810 - params: { did: parsed.did, rkey: parsed.rkey }, 1811 }); 1812 } 1813 }} ··· 1839 src: img.fullsize, 1840 alt: img.alt, 1841 })); 1842 1843 if (images.length > 0) { 1844 // const items = embed.images.map(img => ({ ··· 1868 //border: `1px solid ${theme.border}`, 1869 overflow: "hidden", 1870 }} 1871 - className="border border-gray-200 dark:border-gray-700 bg-gray-200 dark:bg-gray-900" 1872 > 1873 - {lightboxIndex !== null && ( 1874 <Lightbox 1875 images={lightboxImages} 1876 index={lightboxIndex} 1877 onClose={() => setLightboxIndex(null)} 1878 onNavigate={(newIndex) => setLightboxIndex(newIndex)} 1879 /> 1880 - )} 1881 <img 1882 src={image.fullsize} 1883 alt={image.alt} ··· 1908 overflow: "hidden", 1909 //border: `1px solid ${theme.border}`, 1910 }} 1911 - className="border border-gray-200 dark:border-gray-700" 1912 > 1913 - {lightboxIndex !== null && ( 1914 <Lightbox 1915 images={lightboxImages} 1916 index={lightboxIndex} 1917 onClose={() => setLightboxIndex(null)} 1918 onNavigate={(newIndex) => setLightboxIndex(newIndex)} 1919 /> 1920 - )} 1921 {images.map((img, i) => ( 1922 <div 1923 key={i} ··· 1957 //border: `1px solid ${theme.border}`, 1958 // height: 240, // fixed height for cropping 1959 }} 1960 - className="border border-gray-200 dark:border-gray-700" 1961 > 1962 - {lightboxIndex !== null && ( 1963 <Lightbox 1964 images={lightboxImages} 1965 index={lightboxIndex} 1966 onClose={() => setLightboxIndex(null)} 1967 onNavigate={(newIndex) => setLightboxIndex(newIndex)} 1968 /> 1969 - )} 1970 {/* Left: 1:1 */} 1971 <div 1972 style={{ flex: 1, aspectRatio: "1 / 1", position: "relative" }} ··· 2041 //border: `1px solid ${theme.border}`, 2042 //aspectRatio: "3 / 2", // overall grid aspect 2043 }} 2044 - className="border border-gray-200 dark:border-gray-700" 2045 > 2046 - {lightboxIndex !== null && ( 2047 <Lightbox 2048 images={lightboxImages} 2049 index={lightboxIndex} 2050 onClose={() => setLightboxIndex(null)} 2051 onNavigate={(newIndex) => setLightboxIndex(newIndex)} 2052 /> 2053 - )} 2054 {images.map((img, i) => ( 2055 <div 2056 key={i} ··· 2141 return <div />; 2142 } 2143 2144 - import { createPortal } from "react-dom"; 2145 - import type { Record } from "@atproto/api/dist/client/types/app/bsky/actor/profile"; 2146 - type LightboxProps = { 2147 - images: { src: string; alt?: string }[]; 2148 - index: number; 2149 - onClose: () => void; 2150 - onNavigate?: (newIndex: number) => void; 2151 - }; 2152 - export function Lightbox({ 2153 - images, 2154 - index, 2155 - onClose, 2156 - onNavigate, 2157 - }: LightboxProps) { 2158 - const image = images[index]; 2159 - 2160 - useEffect(() => { 2161 - function handleKey(e: KeyboardEvent) { 2162 - if (e.key === "Escape") onClose(); 2163 - if (e.key === "ArrowRight" && onNavigate) 2164 - onNavigate((index + 1) % images.length); 2165 - if (e.key === "ArrowLeft" && onNavigate) 2166 - onNavigate((index - 1 + images.length) % images.length); 2167 - } 2168 - window.addEventListener("keydown", handleKey); 2169 - return () => window.removeEventListener("keydown", handleKey); 2170 - }, [index, images.length, onClose, onNavigate]); 2171 - 2172 - return createPortal( 2173 - <div 2174 - className="fixed inset-0 z-50 flex items-center justify-center bg-black/80" 2175 - onClick={(e) => { 2176 - e.stopPropagation(); 2177 - onClose(); 2178 - }} 2179 - > 2180 - <img 2181 - src={image.src} 2182 - alt={image.alt} 2183 - className="max-h-[90vh] max-w-[90vw] object-contain rounded-lg shadow-lg" 2184 - onClick={(e) => e.stopPropagation()} 2185 - /> 2186 - 2187 - {images.length > 1 && ( 2188 - <> 2189 - <button 2190 - onClick={(e) => { 2191 - e.stopPropagation(); 2192 - onNavigate?.((index - 1 + images.length) % images.length); 2193 - }} 2194 - 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" 2195 - > 2196 - <svg 2197 - xmlns="http://www.w3.org/2000/svg" 2198 - width={28} 2199 - height={28} 2200 - viewBox="0 0 24 24" 2201 - > 2202 - <g fill="none" fillRule="evenodd"> 2203 - <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> 2204 - <path 2205 - fill="currentColor" 2206 - 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" 2207 - ></path> 2208 - </g> 2209 - </svg> 2210 - </button> 2211 - <button 2212 - onClick={(e) => { 2213 - e.stopPropagation(); 2214 - onNavigate?.((index + 1) % images.length); 2215 - }} 2216 - 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" 2217 - > 2218 - <svg 2219 - xmlns="http://www.w3.org/2000/svg" 2220 - width={28} 2221 - height={28} 2222 - viewBox="0 0 24 24" 2223 - > 2224 - <g fill="none" fillRule="evenodd"> 2225 - <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> 2226 - <path 2227 - fill="currentColor" 2228 - 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" 2229 - ></path> 2230 - </g> 2231 - </svg> 2232 - </button> 2233 - </> 2234 - )} 2235 - </div>, 2236 - document.body 2237 - ); 2238 - } 2239 - 2240 function getDomain(url: string) { 2241 try { 2242 const { hostname } = new URL(url); ··· 2267 for (let i = 0; i < bytes.length; i++) { 2268 map[byteIndex++] = charIndex; 2269 } 2270 - charIndex++; 2271 } 2272 2273 return map; ··· 2301 return { start, end, feature: f.features[0] }; 2302 }); 2303 } 2304 - function renderTextWithFacets({ 2305 text, 2306 facets, 2307 navigate, 2308 }: { 2309 text: string; 2310 facets: Facet[]; 2311 - navigate: ({}: any) => void; 2312 }) { 2313 const ranges = extractFacetRanges(text, facets).sort( 2314 (a: any, b: any) => a.start - b.start ··· 2323 } 2324 2325 const fragment = text.slice(start, end); 2326 - // @ts-ignore 2327 if (feature.$type === "app.bsky.richtext.facet#link" && feature.uri) { 2328 result.push( 2329 <a 2330 - // @ts-ignore 2331 href={feature.uri} 2332 key={start} 2333 className="link" ··· 2347 ); 2348 } else if ( 2349 feature.$type === "app.bsky.richtext.facet#mention" && 2350 - // @ts-ignore 2351 feature.did 2352 ) { 2353 result.push( ··· 2359 e.stopPropagation(); 2360 navigate({ 2361 to: "/profile/$did", 2362 - // @ts-ignore 2363 - params: { did: feature.did}, 2364 }); 2365 }} 2366 > ··· 2456 rel="noopener noreferrer" 2457 onClick={(e) => { 2458 e.stopPropagation(); 2459 - onOpen; 2460 }} 2461 - /* @ts-ignore */ 2462 style={linkStyle} 2463 className="text-gray-500 dark:text-gray-400" 2464 > 2465 - {/* @ts-ignore ehiaeih */} 2466 <div 2467 style={containerStyle as React.CSSProperties} 2468 - className="border border-gray-200 dark:border-gray-700" 2469 > 2470 {thumb && ( 2471 <div ··· 2479 marginBottom: 8, 2480 //borderBottom: `1px solid ${theme.border}`, 2481 }} 2482 - className="border-b border-gray-200 dark:border-gray-700" 2483 > 2484 <img 2485 src={thumb} ··· 2503 paddingTop: thumb ? 0 : 12, 2504 }} 2505 > 2506 - {/* @ts-ignore */} 2507 <div style={titleStyle} className="text-gray-900 dark:text-gray-100"> 2508 {title} 2509 </div> 2510 - {/* @ts-ignore */} 2511 <div 2512 style={descriptionStyle as React.CSSProperties} 2513 className="text-gray-500 dark:text-gray-400" ··· 2606 borderRadius: 12, 2607 //border: `1px solid ${theme.border}`, 2608 }} 2609 - className="border border-gray-200 dark:border-gray-700" 2610 onClick={async (e) => { 2611 e.stopPropagation(); 2612 setPlaying(true); ··· 2647 100 / (aspect ? aspect.width / aspect.height : 16 / 9) 2648 }%`, // 16:9 = 56.25%, 4:3 = 75% 2649 }} 2650 - className="border border-gray-200 dark:border-gray-700" 2651 > 2652 <ReactPlayer 2653 src={url}
··· 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"; 7 import { type SVGProps } from "react"; 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 24 function asTyped<T extends { $type: string }>(obj: T): $Typed<T> { ··· 36 topReplyLine?: 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; 47 } 48 49 // export async function cachedGetRecord({ ··· 147 topReplyLine, 148 bottomBorder = true, 149 feedviewpost = false, 150 + repostedby, 151 + style, 152 + ref, 153 + dataIndexPropPass, 154 + nopics, 155 + lightboxCallback, 156 + maxReplies, 157 + isQuote, 158 }: UniversalPostRendererATURILoaderProps) { 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); ··· 171 // >(null); 172 //const router = useRouter(); 173 174 + //const parsed = React.useMemo(() => parseAtUri(atUri), [atUri]); 175 + const parsed = new AtUri(atUri); 176 + const did = parsed?.host; 177 const rkey = parsed?.rkey; 178 + // /*mass comment*/ console.log("did", did); 179 + // /*mass comment*/ console.log("rkey", rkey); 180 181 // React.useEffect(() => { 182 // const checkCache = async () => { ··· 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:", ··· 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); ··· 383 const [replies, setReplies] = React.useState<number | null>(null); 384 385 React.useEffect(() => { 386 + // /*mass comment*/ console.log(JSON.stringify(links, null, 2)); 387 setLikes( 388 links 389 ? links?.links?.["app.bsky.feed.like"]?.[".subject.uri"]?.records || 0 ··· 402 ); 403 }, [links]); 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 + 490 // const navigateToProfile = (e: React.MouseEvent) => { 491 // e.stopPropagation(); 492 // if (resolved?.did) { ··· 496 // }); 497 // } 498 // }; 499 + if (!postQuery?.value) { 500 + // deleted post more often than a non-resolvable post 501 + return <></>; 502 + } 503 504 return ( 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> 612 + ); 613 + } 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 + 621 export function UniversalPostRendererRawRecordShim({ 622 postRecord, 623 profileRecord, ··· 631 topReplyLine = false, 632 bottomBorder = true, 633 feedviewpost = false, 634 + repostedby, 635 + style, 636 + ref, 637 + dataIndexPropPass, 638 + nopics, 639 + lightboxCallback, 640 + maxReplies, 641 + isQuote, 642 }: { 643 postRecord: any; 644 profileRecord: any; ··· 652 topReplyLine?: boolean; 653 bottomBorder?: boolean; 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; 663 }) { 664 + // /*mass comment*/ console.log(`received aturi: ${aturi} of post content: ${postRecord}`); 665 const navigate = useNavigate(); 666 667 //const { get, set } = usePersistentStore(); 668 // const [hydratedEmbed, setHydratedEmbed] = useState<any>(undefined); 669 670 // useEffect(() => { ··· 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); ··· 736 error: embedError, 737 } = useHydratedEmbed(postRecord?.value?.embed, resolved?.did); 738 739 + const [imgcdn] = useAtom(imgCDNAtom); 740 + 741 + const parsedaturi = new AtUri(aturi); //parseAtUri(aturi); 742 + 743 + const fakeprofileviewbasic = React.useMemo<AppBskyActorDefs.ProfileViewBasic>( 744 + () => ({ 745 + did: resolved?.did || "", 746 + handle: resolved?.handle || "", 747 + displayName: profileRecord?.value?.displayName || "", 748 + avatar: getAvatarUrl(profileRecord, resolved?.did, imgcdn) || "", 749 + viewer: undefined, 750 + labels: profileRecord?.labels || undefined, 751 + verification: undefined, 752 + }), 753 + [imgcdn, profileRecord, resolved?.did, resolved?.handle] 754 + ); 755 + 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 + ); 765 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, ··· 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 ); 795 ··· 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; 838 return ( 839 <> 840 {/* <p> ··· 846 parsedaturi && 847 navigate({ 848 to: "/profile/$did/post/$rkey", 849 + params: { did: parsedaturi.host, rkey: parsedaturi.rkey }, 850 }) 851 } 852 // onProfileClick={() => parsedaturi && navigate({to: "/profile/$did", ··· 857 if (parsedaturi) { 858 navigate({ 859 to: "/profile/$did", 860 + params: { did: parsedaturi.host }, 861 }); 862 } 863 }} 864 post={fakepost} 865 + uprrrsauthor={fakeprofileviewdetailed} 866 salt={aturi} 867 bottomReplyLine={bottomReplyLine} 868 topReplyLine={topReplyLine} 869 bottomBorder={bottomBorder} 870 //extraOptionalItemInfo={{reply: postRecord?.value?.reply as AppBskyFeedDefs.ReplyRef, post: fakepost}} 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} 880 /> 881 </> 882 ); 883 } 884 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 + // } 892 893 + // const parts = atUri.slice(PREFIX.length).split("/"); 894 895 + // if (parts.length !== 3) { 896 + // return null; 897 + // } 898 899 + // const [did, collection, rkey] = parts; 900 901 + // if (!did || !collection || !rkey) { 902 + // return null; 903 + // } 904 905 + // return { did, collection, rkey }; 906 + // } 907 908 export function MdiCommentOutline(props: SVGProps<SVGSVGElement>) { 909 return ( ··· 915 {...props} 916 > 917 <path 918 + fill="var(--color-gray-400)" 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" 920 ></path> 921 </svg> ··· 932 {...props} 933 > 934 <path 935 + fill="var(--color-gray-400)" 936 d="M17 17H7v-3l-4 4l4 4v-3h12v-6h-2M7 7h10v3l4-4l-4-4v3H5v6h2z" 937 ></path> 938 </svg> ··· 983 {...props} 984 > 985 <path 986 + fill="var(--color-gray-400)" 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" 988 ></path> 989 </svg> ··· 1000 {...props} 1001 > 1002 <path 1003 + fill="var(--color-gray-400)" 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" 1005 ></path> 1006 </svg> ··· 1017 {...props} 1018 > 1019 <path 1020 + fill="var(--color-gray-400)" 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" 1022 ></path> 1023 </svg> ··· 1034 {...props} 1035 > 1036 <path 1037 + fill="var(--color-gray-400)" 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" 1039 ></path> 1040 </svg> ··· 1068 {...props} 1069 > 1070 <path 1071 + fill="var(--color-gray-400)" 1072 d="M10 9V5l-7 7l7 7v-4.1c5 0 8.5 1.6 11 5.1c-1-5-4-10-11-11" 1073 ></path> 1074 </svg> ··· 1122 {...props} 1123 > 1124 <path 1125 + fill="var(--color-gray-400)" 1126 d="M17 17H7v-3l-4 4l4 4v-3h12v-6h-2M7 7h10v3l4-4l-4-4v3H5v6h2z" 1127 ></path> 1128 </svg> ··· 1139 {...props} 1140 > 1141 <path 1142 + fill="var(--color-gray-400)" 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" 1144 ></path> 1145 </svg> ··· 1164 } 1165 1166 /* what imported from testfront */ 1167 //import Masonry from "@mui/lab/Masonry"; 1168 import { 1169 + type $Typed, 1170 AppBskyActorDefs, 1171 AppBskyEmbedDefs, 1172 AppBskyEmbedExternal, 1173 AppBskyEmbedImages, ··· 1178 AppBskyFeedPost, 1179 AppBskyGraphDefs, 1180 AtUri, 1181 + type Facet, 1182 //AppBskyLabelerDefs, 1183 //AtUri, 1184 //ComAtprotoRepoStrongRef, 1185 ModerationDecision, 1186 } from "@atproto/api"; 1187 import type { 1188 //BlockedPost, ··· 1191 PostView, 1192 //ThreadViewPost, 1193 } from "@atproto/api/dist/client/types/app/bsky/feed/defs"; 1194 + import { useInfiniteQuery } from "@tanstack/react-query"; 1195 import { useEffect, useRef, useState } from "react"; 1196 import ReactPlayer from "react-player"; 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"; 1202 // import type { OutputSchema } from "@atproto/api/dist/client/types/app/bsky/feed/getFeed"; 1203 // import type { 1204 // ViewRecord, ··· 1306 1307 function UniversalPostRenderer({ 1308 post, 1309 + uprrrsauthor, 1310 //setMainItem, 1311 //isMainItem, 1312 onPostClick, ··· 1322 bottomBorder = true, 1323 feedviewpostreplyhandle, 1324 depth = 0, 1325 + repostedby, 1326 + style, 1327 + ref, 1328 + dataIndexPropPass, 1329 + nopics, 1330 + lightboxCallback, 1331 + maxReplies, 1332 }: { 1333 post: PostView; 1334 + uprrrsauthor?: AppBskyActorDefs.ProfileViewDetailed; 1335 // optional for now because i havent ported every use to this yet 1336 // setMainItem?: React.Dispatch< 1337 // React.SetStateAction<AppBskyFeedDefs.FeedViewPost> ··· 1348 bottomBorder?: boolean; 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; 1358 }) { 1359 + const parsed = new AtUri(post.uri); 1360 const navigate = useNavigate(); 1361 + const [likedPosts, setLikedPosts] = useAtom(likedPostsAtom); 1362 + const [hasRetweeted, setHasRetweeted] = useState<boolean>( 1363 post.viewer?.repost ? true : false 1364 ); 1365 + const [hasLiked, setHasLiked] = useState<boolean>( 1366 + post.uri in likedPosts || post.viewer?.like ? true : false 1367 ); 1368 + const [, setComposerPost] = useAtom(composerAtom); 1369 const { agent } = useAuth(); 1370 const [likeUri, setLikeUri] = useState<string | undefined>(post.viewer?.like); 1371 const [retweetUri, setRetweetUri] = useState<string | undefined>( ··· 1373 ); 1374 1375 const likeOrUnlikePost = async () => { 1376 + const newLikedPosts = { ...likedPosts }; 1377 if (!agent) { 1378 console.error("Agent is null or undefined"); 1379 return; 1380 } 1381 if (hasLiked) { 1382 + if (post.uri in likedPosts) { 1383 + const likeUri = likedPosts[post.uri]; 1384 + setLikeUri(likeUri); 1385 + } 1386 if (likeUri) { 1387 await agent.deleteLike(likeUri); 1388 setHasLiked(false); 1389 + delete newLikedPosts[post.uri]; 1390 } 1391 } else { 1392 const { uri } = await agent.like(post.uri, post.cid); 1393 setLikeUri(uri); 1394 setHasLiked(true); 1395 + newLikedPosts[post.uri] = uri; 1396 } 1397 + setLikedPosts(newLikedPosts); 1398 }; 1399 1400 const repostOrUnrepostPost = async () => { ··· 1414 } 1415 }; 1416 1417 + const isRepost = repostedby 1418 + ? repostedby 1419 + : extraOptionalItemInfo 1420 + ? AppBskyFeedDefs.isReasonRepost(extraOptionalItemInfo.reason) 1421 + ? extraOptionalItemInfo.reason?.by.displayName 1422 + : undefined 1423 + : undefined; 1424 const isReply = extraOptionalItemInfo 1425 ? extraOptionalItemInfo.reply 1426 : undefined; 1427 1428 const emergencySalt = randomString(); 1429 + const fedi = (post.record as { bridgyOriginalText?: string }) 1430 + .bridgyOriginalText; 1431 1432 /* fuck you */ 1433 const isMainItem = false; 1434 const setMainItem = (any: any) => {}; 1435 + // eslint-disable-next-line react-hooks/refs 1436 + console.log("Received ref in UniversalPostRenderer:", ref); 1437 return ( 1438 + <div ref={ref} style={style} data-index={dataIndexPropPass}> 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 + } 1456 style={{ 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, 1473 }} 1474 + className="border-gray-300 dark:border-gray-800" 1475 > 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> 1520 <div 1521 + className={`absolute`} 1522 style={{ 1523 + top: isRepost 1524 + ? "calc(16px + 1rem)" 1525 + : isQuote 1526 + ? 12 1527 + : topReplyLine 1528 + ? 8 1529 + : 16, 1530 + left: isQuote ? 12 : 16, 1531 }} 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 1635 layout 1636 transition={{ duration: 0.2 }} 1637 animate={{ height: expanded ? 0 : '100%' }} ··· 1641 // no flex here 1642 }} 1643 /> */} 1644 + </div> 1645 + <div style={{ flex: 1, maxWidth: "100%" }}> 1646 <div 1647 style={{ 1648 display: "flex", 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, 1656 }} 1657 > 1658 + <div 1659 style={{ 1660 display: "flex", 1661 + //overflow: "hidden", // hey why is overflow hidden unapplied 1662 overflow: "hidden", 1663 textOverflow: "ellipsis", 1664 flexShrink: 1, 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", 1672 }} 1673 > 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> 1696 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 1714 style={{ 1715 + display: "flex", 1716 + alignItems: "center", 1717 + height: "1rem", 1718 }} 1719 > 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> 1735 </div> 1736 + {/* reply indicator */} 1737 + {!!feedviewpostreplyhandle && ( 1738 + <div 1739 style={{ 1740 + display: "flex", 1741 + borderRadius: 12, 1742 + paddingBottom: 2, 1743 + fontSize: 14, 1744 + justifyContent: "flex-start", 1745 //color: theme.textSecondary, 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, 1755 }} 1756 className="text-gray-500 dark:text-gray-400" 1757 > 1758 + <MdiReply /> Reply to @{feedviewpostreplyhandle} 1759 + </div> 1760 + )} 1761 <div 1762 style={{ 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, 1770 }} 1771 + className="text-gray-900 dark:text-gray-100" 1772 > 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 + )} 1791 </div> 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 + </> 1813 + )} 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 && ( 1839 <div 1840 style={{ 1841 display: "flex", 1842 + gap: 32, 1843 + paddingTop: 8, 1844 + //color: theme.textSecondary, 1845 + fontSize: 15, 1846 + justifyContent: "space-between", 1847 + //background: "#0f0", 1848 }} 1849 + className="text-gray-500 dark:text-gray-400" 1850 > 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> 1908 + <HitSlopButton 1909 + onClick={() => { 1910 + likeOrUnlikePost(); 1911 + }} 1912 + style={{ 1913 + ...btnstyle, 1914 + ...(hasLiked ? { color: "#EC4899" } : {}), 1915 + }} 1916 + > 1917 + {hasLiked ? <MdiCardsHeart /> : <MdiCardsHeartOutline />} 1918 + {(post.likeCount || 0) + (hasLiked ? 1 : 0)} 1919 + </HitSlopButton> 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> 1946 </div> 1947 + )} 1948 + </div> 1949 + <div 1950 + style={{ 1951 + //height: bottomReplyLine ? 16 : 0 1952 + height: isQuote ? 12 : 16, 1953 + }} 1954 + /> 1955 </div> 1956 </div> 1957 </div> 1958 </div> ··· 2044 viewContext, 2045 salt, 2046 navigate, 2047 + postid, 2048 + nopics, 2049 + lightboxCallback, 2050 }: { 2051 embed?: Embed; 2052 moderation?: ModerationDecision; ··· 2054 allowNestedQuotes?: boolean; 2055 viewContext?: PostEmbedViewContext; 2056 salt: string; 2057 + navigate: (_: any) => void; 2058 + postid?: { did: string; rkey: string }; 2059 + nopics?: boolean; 2060 + lightboxCallback?: (d: LightboxProps) => void; 2061 }) { 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 + } 2073 if ( 2074 AppBskyEmbedRecordWithMedia.isView(embed) && 2075 AppBskyEmbedRecord.isViewRecord(embed.record.record) && ··· 2103 viewContext={viewContext} 2104 salt={salt} 2105 navigate={navigate} 2106 + postid={postid} 2107 + nopics={nopics} 2108 + lightboxCallback={lightboxCallback} 2109 /> 2110 {/* padding empty div of 8px height */} 2111 <div style={{ height: 12 }} /> ··· 2119 //boxShadow: theme.cardShadow, 2120 overflow: "hidden", 2121 }} 2122 + className="shadow border border-gray-200 dark:border-gray-800 was7" 2123 > 2124 <UniversalPostRenderer 2125 post={post} ··· 2127 salt={salt} 2128 onPostClick={(e) => { 2129 e.stopPropagation(); 2130 + const parsed = new AtUri(post.uri); //parseAtUri(post.uri); 2131 if (parsed) { 2132 navigate({ 2133 to: "/profile/$did/post/$rkey", 2134 + params: { did: parsed.host, rkey: parsed.rkey }, 2135 }); 2136 } 2137 }} ··· 2236 //boxShadow: theme.cardShadow, 2237 overflow: "hidden", 2238 }} 2239 + className="shadow border border-gray-200 dark:border-gray-800 was7" 2240 > 2241 <UniversalPostRenderer 2242 post={post} ··· 2244 salt={salt} 2245 onPostClick={(e) => { 2246 e.stopPropagation(); 2247 + const parsed = new AtUri(post.uri); //parseAtUri(post.uri); 2248 if (parsed) { 2249 navigate({ 2250 to: "/profile/$did/post/$rkey", 2251 + params: { did: parsed.host, rkey: parsed.rkey }, 2252 }); 2253 } 2254 }} ··· 2280 src: img.fullsize, 2281 alt: img.alt, 2282 })); 2283 + console.log("rendering images"); 2284 + if (lightboxCallback) { 2285 + lightboxCallback({ images: lightboxImages }); 2286 + console.log("rendering images"); 2287 + } 2288 + 2289 + if (nopics) return; 2290 2291 if (images.length > 0) { 2292 // const items = embed.images.map(img => ({ ··· 2316 //border: `1px solid ${theme.border}`, 2317 overflow: "hidden", 2318 }} 2319 + className="border border-gray-200 dark:border-gray-800 was7 bg-gray-200 dark:bg-gray-900" 2320 > 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 + )} */} 2330 <img 2331 src={image.fullsize} 2332 alt={image.alt} ··· 2357 overflow: "hidden", 2358 //border: `1px solid ${theme.border}`, 2359 }} 2360 + className="border border-gray-200 dark:border-gray-800 was7" 2361 > 2362 + {/* {lightboxIndex !== null && ( 2363 <Lightbox 2364 images={lightboxImages} 2365 index={lightboxIndex} 2366 onClose={() => setLightboxIndex(null)} 2367 onNavigate={(newIndex) => setLightboxIndex(newIndex)} 2368 + post={postid} 2369 /> 2370 + )} */} 2371 {images.map((img, i) => ( 2372 <div 2373 key={i} ··· 2407 //border: `1px solid ${theme.border}`, 2408 // height: 240, // fixed height for cropping 2409 }} 2410 + className="border border-gray-200 dark:border-gray-800 was7" 2411 > 2412 + {/* {lightboxIndex !== null && ( 2413 <Lightbox 2414 images={lightboxImages} 2415 index={lightboxIndex} 2416 onClose={() => setLightboxIndex(null)} 2417 onNavigate={(newIndex) => setLightboxIndex(newIndex)} 2418 + post={postid} 2419 /> 2420 + )} */} 2421 {/* Left: 1:1 */} 2422 <div 2423 style={{ flex: 1, aspectRatio: "1 / 1", position: "relative" }} ··· 2492 //border: `1px solid ${theme.border}`, 2493 //aspectRatio: "3 / 2", // overall grid aspect 2494 }} 2495 + className="border border-gray-200 dark:border-gray-800 was7" 2496 > 2497 + {/* {lightboxIndex !== null && ( 2498 <Lightbox 2499 images={lightboxImages} 2500 index={lightboxIndex} 2501 onClose={() => setLightboxIndex(null)} 2502 onNavigate={(newIndex) => setLightboxIndex(newIndex)} 2503 + post={postid} 2504 /> 2505 + )} */} 2506 {images.map((img, i) => ( 2507 <div 2508 key={i} ··· 2593 return <div />; 2594 } 2595 2596 function getDomain(url: string) { 2597 try { 2598 const { hostname } = new URL(url); ··· 2623 for (let i = 0; i < bytes.length; i++) { 2624 map[byteIndex++] = charIndex; 2625 } 2626 + charIndex += char.length; 2627 } 2628 2629 return map; ··· 2657 return { start, end, feature: f.features[0] }; 2658 }); 2659 } 2660 + export function renderTextWithFacets({ 2661 text, 2662 facets, 2663 navigate, 2664 }: { 2665 text: string; 2666 facets: Facet[]; 2667 + navigate: (_: any) => void; 2668 }) { 2669 const ranges = extractFacetRanges(text, facets).sort( 2670 (a: any, b: any) => a.start - b.start ··· 2679 } 2680 2681 const fragment = text.slice(start, end); 2682 + // @ts-expect-error i didnt bother with the correct types here sorry. bsky api types are cursed 2683 if (feature.$type === "app.bsky.richtext.facet#link" && feature.uri) { 2684 result.push( 2685 <a 2686 + // @ts-expect-error i didnt bother with the correct types here sorry. bsky api types are cursed 2687 href={feature.uri} 2688 key={start} 2689 className="link" ··· 2703 ); 2704 } else if ( 2705 feature.$type === "app.bsky.richtext.facet#mention" && 2706 + // @ts-expect-error i didnt bother with the correct types here sorry. bsky api types are cursed 2707 feature.did 2708 ) { 2709 result.push( ··· 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 }); 2721 }} 2722 > ··· 2812 rel="noopener noreferrer" 2813 onClick={(e) => { 2814 e.stopPropagation(); 2815 + if (onOpen) onOpen(); 2816 }} 2817 + /* @ts-expect-error css arent typed or something idk fuck you */ 2818 style={linkStyle} 2819 className="text-gray-500 dark:text-gray-400" 2820 > 2821 <div 2822 style={containerStyle as React.CSSProperties} 2823 + className="border border-gray-200 dark:border-gray-800 was7" 2824 > 2825 {thumb && ( 2826 <div ··· 2834 marginBottom: 8, 2835 //borderBottom: `1px solid ${theme.border}`, 2836 }} 2837 + className="border-b border-gray-200 dark:border-gray-800 was7" 2838 > 2839 <img 2840 src={thumb} ··· 2858 paddingTop: thumb ? 0 : 12, 2859 }} 2860 > 2861 + {/* @ts-expect-error css */} 2862 <div style={titleStyle} className="text-gray-900 dark:text-gray-100"> 2863 {title} 2864 </div> 2865 <div 2866 style={descriptionStyle as React.CSSProperties} 2867 className="text-gray-500 dark:text-gray-400" ··· 2960 borderRadius: 12, 2961 //border: `1px solid ${theme.border}`, 2962 }} 2963 + className="border border-gray-200 dark:border-gray-800 was7" 2964 onClick={async (e) => { 2965 e.stopPropagation(); 2966 setPlaying(true); ··· 3001 100 / (aspect ? aspect.width / aspect.height : 16 / 9) 3002 }%`, // 16:9 = 56.25%, 4:3 = 75% 3003 }} 3004 + className="border border-gray-200 dark:border-gray-800 was7" 3005 > 3006 <ReactPlayer 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";
+77 -12
src/main.tsx
··· 1 - import { StrictMode } from "react"; 2 import ReactDOM from "react-dom/client"; 3 - import { RouterProvider, createRouter } from "@tanstack/react-router"; 4 5 // Import the generated route tree 6 import { routeTree } from "./routeTree.gen"; 7 8 - import "~/styles/app.css"; 9 - import reportWebVitals from "./reportWebVitals.ts"; 10 - import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; 11 12 - const queryClient = new QueryClient(); 13 // Create a new router instance 14 const router = createRouter({ 15 routeTree, ··· 33 const root = ReactDOM.createRoot(rootElement); 34 root.render( 35 // double queries annoys me 36 - <StrictMode> 37 - <QueryClientProvider client={queryClient}> 38 - <RouterProvider router={router} /> 39 - </QueryClientProvider> 40 - </StrictMode> 41 ); 42 } 43 44 // If you want to start measuring performance in your app, pass a function 45 - // to log results (for example: reportWebVitals(console.log)) 46 // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 47 reportWebVitals();
··· 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"; 10 import ReactDOM from "react-dom/client"; 11 12 + import reportWebVitals from "./reportWebVitals.ts"; 13 // Import the generated route tree 14 import { routeTree } from "./routeTree.gen"; 15 + import { isAtTopAtom } from "./utils/atoms.ts"; 16 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 + }); 34 35 // Create a new router instance 36 const router = createRouter({ 37 routeTree, ··· 55 const root = ReactDOM.createRoot(rootElement); 56 root.render( 57 // double queries annoys me 58 + // <StrictMode> 59 + <QueryClientProvider client={queryClient}> 60 + <ScrollTopWatcher /> 61 + <RouterProvider router={router} /> 62 + </QueryClientProvider> 63 + // </StrictMode> 64 ); 65 } 66 67 // If you want to start measuring performance in your app, pass a function 68 + // to log results (for example: reportWebVitals(// /*mass comment*/ console.log)) 69 // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 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 import { Route as FeedsRouteImport } from './routes/feeds' 16 import { Route as PathlessLayoutRouteImport } from './routes/_pathlessLayout' 17 import { Route as IndexRouteImport } from './routes/index' 18 import { Route as PathlessLayoutNestedLayoutRouteImport } from './routes/_pathlessLayout/_nested-layout' 19 import { Route as ProfileDidIndexRouteImport } from './routes/profile.$did/index' 20 import { Route as PathlessLayoutNestedLayoutRouteBRouteImport } from './routes/_pathlessLayout/_nested-layout/route-b' 21 import { Route as PathlessLayoutNestedLayoutRouteARouteImport } from './routes/_pathlessLayout/_nested-layout/route-a' 22 import { Route as ProfileDidPostRkeyRouteImport } from './routes/profile.$did/post.$rkey' 23 24 const SettingsRoute = SettingsRouteImport.update({ 25 id: '/settings', ··· 50 path: '/', 51 getParentRoute: () => rootRouteImport, 52 } as any) 53 const PathlessLayoutNestedLayoutRoute = 54 PathlessLayoutNestedLayoutRouteImport.update({ 55 id: '/_nested-layout', ··· 77 path: '/profile/$did/post/$rkey', 78 getParentRoute: () => rootRouteImport, 79 } as any) 80 81 export interface FileRoutesByFullPath { 82 '/': typeof IndexRoute ··· 84 '/notifications': typeof NotificationsRoute 85 '/search': typeof SearchRoute 86 '/settings': typeof SettingsRoute 87 '/route-a': typeof PathlessLayoutNestedLayoutRouteARoute 88 '/route-b': typeof PathlessLayoutNestedLayoutRouteBRoute 89 '/profile/$did': typeof ProfileDidIndexRoute 90 - '/profile/$did/post/$rkey': typeof ProfileDidPostRkeyRoute 91 } 92 export interface FileRoutesByTo { 93 '/': typeof IndexRoute ··· 95 '/notifications': typeof NotificationsRoute 96 '/search': typeof SearchRoute 97 '/settings': typeof SettingsRoute 98 '/route-a': typeof PathlessLayoutNestedLayoutRouteARoute 99 '/route-b': typeof PathlessLayoutNestedLayoutRouteBRoute 100 '/profile/$did': typeof ProfileDidIndexRoute 101 - '/profile/$did/post/$rkey': typeof ProfileDidPostRkeyRoute 102 } 103 export interface FileRoutesById { 104 __root__: typeof rootRouteImport ··· 109 '/search': typeof SearchRoute 110 '/settings': typeof SettingsRoute 111 '/_pathlessLayout/_nested-layout': typeof PathlessLayoutNestedLayoutRouteWithChildren 112 '/_pathlessLayout/_nested-layout/route-a': typeof PathlessLayoutNestedLayoutRouteARoute 113 '/_pathlessLayout/_nested-layout/route-b': typeof PathlessLayoutNestedLayoutRouteBRoute 114 '/profile/$did/': typeof ProfileDidIndexRoute 115 - '/profile/$did/post/$rkey': typeof ProfileDidPostRkeyRoute 116 } 117 export interface FileRouteTypes { 118 fileRoutesByFullPath: FileRoutesByFullPath ··· 122 | '/notifications' 123 | '/search' 124 | '/settings' 125 | '/route-a' 126 | '/route-b' 127 | '/profile/$did' 128 | '/profile/$did/post/$rkey' 129 fileRoutesByTo: FileRoutesByTo 130 to: 131 | '/' ··· 133 | '/notifications' 134 | '/search' 135 | '/settings' 136 | '/route-a' 137 | '/route-b' 138 | '/profile/$did' 139 | '/profile/$did/post/$rkey' 140 id: 141 | '__root__' 142 | '/' ··· 146 | '/search' 147 | '/settings' 148 | '/_pathlessLayout/_nested-layout' 149 | '/_pathlessLayout/_nested-layout/route-a' 150 | '/_pathlessLayout/_nested-layout/route-b' 151 | '/profile/$did/' 152 | '/profile/$did/post/$rkey' 153 fileRoutesById: FileRoutesById 154 } 155 export interface RootRouteChildren { ··· 159 NotificationsRoute: typeof NotificationsRoute 160 SearchRoute: typeof SearchRoute 161 SettingsRoute: typeof SettingsRoute 162 ProfileDidIndexRoute: typeof ProfileDidIndexRoute 163 - ProfileDidPostRkeyRoute: typeof ProfileDidPostRkeyRoute 164 } 165 166 declare module '@tanstack/react-router' { ··· 207 preLoaderRoute: typeof IndexRouteImport 208 parentRoute: typeof rootRouteImport 209 } 210 '/_pathlessLayout/_nested-layout': { 211 id: '/_pathlessLayout/_nested-layout' 212 path: '' ··· 242 preLoaderRoute: typeof ProfileDidPostRkeyRouteImport 243 parentRoute: typeof rootRouteImport 244 } 245 } 246 } 247 ··· 275 PathlessLayoutRouteChildren, 276 ) 277 278 const rootRouteChildren: RootRouteChildren = { 279 IndexRoute: IndexRoute, 280 PathlessLayoutRoute: PathlessLayoutRouteWithChildren, ··· 282 NotificationsRoute: NotificationsRoute, 283 SearchRoute: SearchRoute, 284 SettingsRoute: SettingsRoute, 285 ProfileDidIndexRoute: ProfileDidIndexRoute, 286 - ProfileDidPostRkeyRoute: ProfileDidPostRkeyRoute, 287 } 288 export const routeTree = rootRouteImport 289 ._addFileChildren(rootRouteChildren)
··· 15 import { Route as FeedsRouteImport } from './routes/feeds' 16 import { Route as PathlessLayoutRouteImport } from './routes/_pathlessLayout' 17 import { Route as IndexRouteImport } from './routes/index' 18 + import { Route as CallbackIndexRouteImport } from './routes/callback/index' 19 import { Route as PathlessLayoutNestedLayoutRouteImport } from './routes/_pathlessLayout/_nested-layout' 20 import { Route as ProfileDidIndexRouteImport } from './routes/profile.$did/index' 21 import { Route as PathlessLayoutNestedLayoutRouteBRouteImport } from './routes/_pathlessLayout/_nested-layout/route-b' 22 import { Route as PathlessLayoutNestedLayoutRouteARouteImport } from './routes/_pathlessLayout/_nested-layout/route-a' 23 import { Route as ProfileDidPostRkeyRouteImport } from './routes/profile.$did/post.$rkey' 24 + import { Route as ProfileDidPostRkeyImageIRouteImport } from './routes/profile.$did/post.$rkey.image.$i' 25 26 const SettingsRoute = SettingsRouteImport.update({ 27 id: '/settings', ··· 52 path: '/', 53 getParentRoute: () => rootRouteImport, 54 } as any) 55 + const CallbackIndexRoute = CallbackIndexRouteImport.update({ 56 + id: '/callback/', 57 + path: '/callback/', 58 + getParentRoute: () => rootRouteImport, 59 + } as any) 60 const PathlessLayoutNestedLayoutRoute = 61 PathlessLayoutNestedLayoutRouteImport.update({ 62 id: '/_nested-layout', ··· 84 path: '/profile/$did/post/$rkey', 85 getParentRoute: () => rootRouteImport, 86 } as any) 87 + const ProfileDidPostRkeyImageIRoute = 88 + ProfileDidPostRkeyImageIRouteImport.update({ 89 + id: '/image/$i', 90 + path: '/image/$i', 91 + getParentRoute: () => ProfileDidPostRkeyRoute, 92 + } as any) 93 94 export interface FileRoutesByFullPath { 95 '/': typeof IndexRoute ··· 97 '/notifications': typeof NotificationsRoute 98 '/search': typeof SearchRoute 99 '/settings': typeof SettingsRoute 100 + '/callback': typeof CallbackIndexRoute 101 '/route-a': typeof PathlessLayoutNestedLayoutRouteARoute 102 '/route-b': typeof PathlessLayoutNestedLayoutRouteBRoute 103 '/profile/$did': typeof ProfileDidIndexRoute 104 + '/profile/$did/post/$rkey': typeof ProfileDidPostRkeyRouteWithChildren 105 + '/profile/$did/post/$rkey/image/$i': typeof ProfileDidPostRkeyImageIRoute 106 } 107 export interface FileRoutesByTo { 108 '/': typeof IndexRoute ··· 110 '/notifications': typeof NotificationsRoute 111 '/search': typeof SearchRoute 112 '/settings': typeof SettingsRoute 113 + '/callback': typeof CallbackIndexRoute 114 '/route-a': typeof PathlessLayoutNestedLayoutRouteARoute 115 '/route-b': typeof PathlessLayoutNestedLayoutRouteBRoute 116 '/profile/$did': typeof ProfileDidIndexRoute 117 + '/profile/$did/post/$rkey': typeof ProfileDidPostRkeyRouteWithChildren 118 + '/profile/$did/post/$rkey/image/$i': typeof ProfileDidPostRkeyImageIRoute 119 } 120 export interface FileRoutesById { 121 __root__: typeof rootRouteImport ··· 126 '/search': typeof SearchRoute 127 '/settings': typeof SettingsRoute 128 '/_pathlessLayout/_nested-layout': typeof PathlessLayoutNestedLayoutRouteWithChildren 129 + '/callback/': typeof CallbackIndexRoute 130 '/_pathlessLayout/_nested-layout/route-a': typeof PathlessLayoutNestedLayoutRouteARoute 131 '/_pathlessLayout/_nested-layout/route-b': typeof PathlessLayoutNestedLayoutRouteBRoute 132 '/profile/$did/': typeof ProfileDidIndexRoute 133 + '/profile/$did/post/$rkey': typeof ProfileDidPostRkeyRouteWithChildren 134 + '/profile/$did/post/$rkey/image/$i': typeof ProfileDidPostRkeyImageIRoute 135 } 136 export interface FileRouteTypes { 137 fileRoutesByFullPath: FileRoutesByFullPath ··· 141 | '/notifications' 142 | '/search' 143 | '/settings' 144 + | '/callback' 145 | '/route-a' 146 | '/route-b' 147 | '/profile/$did' 148 | '/profile/$did/post/$rkey' 149 + | '/profile/$did/post/$rkey/image/$i' 150 fileRoutesByTo: FileRoutesByTo 151 to: 152 | '/' ··· 154 | '/notifications' 155 | '/search' 156 | '/settings' 157 + | '/callback' 158 | '/route-a' 159 | '/route-b' 160 | '/profile/$did' 161 | '/profile/$did/post/$rkey' 162 + | '/profile/$did/post/$rkey/image/$i' 163 id: 164 | '__root__' 165 | '/' ··· 169 | '/search' 170 | '/settings' 171 | '/_pathlessLayout/_nested-layout' 172 + | '/callback/' 173 | '/_pathlessLayout/_nested-layout/route-a' 174 | '/_pathlessLayout/_nested-layout/route-b' 175 | '/profile/$did/' 176 | '/profile/$did/post/$rkey' 177 + | '/profile/$did/post/$rkey/image/$i' 178 fileRoutesById: FileRoutesById 179 } 180 export interface RootRouteChildren { ··· 184 NotificationsRoute: typeof NotificationsRoute 185 SearchRoute: typeof SearchRoute 186 SettingsRoute: typeof SettingsRoute 187 + CallbackIndexRoute: typeof CallbackIndexRoute 188 ProfileDidIndexRoute: typeof ProfileDidIndexRoute 189 + ProfileDidPostRkeyRoute: typeof ProfileDidPostRkeyRouteWithChildren 190 } 191 192 declare module '@tanstack/react-router' { ··· 233 preLoaderRoute: typeof IndexRouteImport 234 parentRoute: typeof rootRouteImport 235 } 236 + '/callback/': { 237 + id: '/callback/' 238 + path: '/callback' 239 + fullPath: '/callback' 240 + preLoaderRoute: typeof CallbackIndexRouteImport 241 + parentRoute: typeof rootRouteImport 242 + } 243 '/_pathlessLayout/_nested-layout': { 244 id: '/_pathlessLayout/_nested-layout' 245 path: '' ··· 275 preLoaderRoute: typeof ProfileDidPostRkeyRouteImport 276 parentRoute: typeof rootRouteImport 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 + } 285 } 286 } 287 ··· 315 PathlessLayoutRouteChildren, 316 ) 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 + 329 const rootRouteChildren: RootRouteChildren = { 330 IndexRoute: IndexRoute, 331 PathlessLayoutRoute: PathlessLayoutRouteWithChildren, ··· 333 NotificationsRoute: NotificationsRoute, 334 SearchRoute: SearchRoute, 335 SettingsRoute: SettingsRoute, 336 + CallbackIndexRoute: CallbackIndexRoute, 337 ProfileDidIndexRoute: ProfileDidIndexRoute, 338 + ProfileDidPostRkeyRoute: ProfileDidPostRkeyRouteWithChildren, 339 } 340 export const routeTree = rootRouteImport 341 ._addFileChildren(rootRouteChildren)
+586 -473
src/routes/__root.tsx
··· 2 3 // dont forget to run this 4 // npx @tanstack/router-cli generate 5 - 6 - import { useState, type SVGProps } from "react"; 7 import { 8 - HeadContent, 9 - Link, 10 - Outlet, 11 Scripts, 12 - createRootRoute, 13 useLocation, 14 } from "@tanstack/react-router"; 15 import { TanStackRouterDevtools } from "@tanstack/react-router-devtools"; 16 import * as React from "react"; 17 import { DefaultCatchBoundary } from "~/components/DefaultCatchBoundary"; 18 import Login from "~/components/Login"; 19 import { NotFound } from "~/components/NotFound"; 20 - import appCss from "~/styles/app.css?url"; 21 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 26 - export const Route = createRootRoute({ 27 head: () => ({ 28 meta: [ 29 { ··· 39 }), 40 ], 41 links: [ 42 - { rel: "stylesheet", href: appCss }, 43 { 44 rel: "apple-touch-icon", 45 sizes: "180x180", ··· 61 { rel: "icon", href: "/favicon.ico" }, 62 ], 63 }), 64 - errorComponent: (props) => { 65 - return ( 66 - <RootDocument> 67 - <DefaultCatchBoundary {...props} /> 68 - </RootDocument> 69 - ); 70 - }, 71 notFoundComponent: () => <NotFound />, 72 component: RootComponent, 73 }); 74 75 function RootComponent() { 76 return ( 77 - <AuthProvider> 78 - <PersistentStoreProvider> 79 - <RootDocument> 80 - <Outlet /> 81 - </RootDocument> 82 - </PersistentStoreProvider> 83 - </AuthProvider> 84 ); 85 } 86 87 function RootDocument({ children }: { children: React.ReactNode }) { 88 const location = useLocation(); 89 - const { agent, authed } = useAuth(); 90 const isHome = location.pathname === "/"; 91 const isNotifications = location.pathname.startsWith("/notifications"); 92 - const isProfile = location.pathname.startsWith("/profile/"); 93 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); 99 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 - } 126 127 return ( 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 - )} 172 173 <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"> 175 <div className="flex items-center gap-3 mb-4"> 176 - <img src="/redstar.png" alt="Red Dwarf Logo" className="w-8 h-8" /> 177 <span className="font-extrabold text-2xl tracking-tight text-gray-900 dark:text-gray-100"> 178 Red Dwarf{" "} 179 {/* <span className="text-gray-500 dark:text-gray-400 text-sm"> ··· 181 </span> */} 182 </span> 183 </div> 184 - <Link 185 to="/" 186 className={ 187 `py-2 px-4 hover:bg-gray-100 dark:hover:bg-gray-900 text-xl flex items-center gap-3 ` + 188 (isHome ? "font-bold" : "") 189 } 190 > 191 - {isHome ? ( 192 - <TablerHomeFilled width={28} height={28} /> 193 ) : ( 194 - <TablerHome width={28} height={28} /> 195 )} 196 <span>Home</span> 197 </Link> ··· 202 (isNotifications ? "font-bold" : "") 203 } 204 > 205 - {isNotifications ? ( 206 - <TablerBellFilled width={28} height={28} /> 207 ) : ( 208 - <TablerBell width={28} height={28} /> 209 )} 210 <span>Notifications</span> 211 </Link> ··· 216 }`} 217 > 218 {location.pathname.startsWith("/feeds") ? ( 219 - <TablerHashtagFilled width={28} height={28} /> 220 ) : ( 221 - <TablerHashtag width={28} height={28} /> 222 )} 223 <span>Feeds</span> 224 </Link> ··· 230 }`} 231 > 232 {location.pathname.startsWith("/search") ? ( 233 - <TablerSearchFilled width={28} height={28} /> 234 ) : ( 235 - <TablerSearch width={28} height={28} /> 236 )} 237 <span>Search</span> 238 </Link> ··· 242 }`} 243 onClick={() => { 244 if (authed && agent && agent.assertDid) { 245 - window.location.href = `/profile/${agent.assertDid}`; 246 } 247 }} 248 type="button" 249 > 250 - <TablerUserCircle width={28} height={28} /> 251 <span>Profile</span> 252 </button> 253 <Link ··· 256 location.pathname.startsWith("/settings") ? "font-bold" : "" 257 }`} 258 > 259 - {location.pathname.startsWith("/settings") ? ( 260 - <IonSettingsSharp width={28} height={28} /> 261 ) : ( 262 - <IonSettings width={28} height={28} /> 263 )} 264 <span>Settings</span> 265 - </Link> 266 - <button 267 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 onClick={() => setPostOpen(true)} 269 type="button" 270 > 271 - <TablerEdit 272 width={24} 273 height={24} 274 className="text-gray-600 dark:text-gray-400" 275 /> 276 <span>Post</span> 277 - </button> 278 <div className="flex-1"></div> 279 <a 280 href="https://tangled.sh/@whey.party/red-dwarf" ··· 305 </div> 306 </nav> 307 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" 319 /> 320 - </button> 321 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> 340 </div> 341 342 {children} 343 </main> 344 345 <aside className="hidden lg:flex h-screen w-[250px] sticky top-0 self-start flex-col"> 346 <Login /> 347 348 <div className="flex-1"></div> 349 <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. 353 </p> 354 </aside> 355 </div> 356 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}`; 413 } 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> 435 </div> 436 - </nav> 437 438 - <TanStackRouterDevtools position="bottom-right" /> 439 <Scripts /> 440 </> 441 ); 442 } 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 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} 500 > 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 - } 609 610 - export function TablerSearch(props: SVGProps<SVGSVGElement>) { 611 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} 642 > 643 - <g 644 - fill="none" 645 - stroke="currentColor" 646 - strokeLinecap="round" 647 - strokeLinejoin="round" 648 - strokeWidth={3} 649 > 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> 654 ); 655 } 656 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>) { 678 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} 685 > 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> 691 ); 692 }
··· 2 3 // dont forget to run this 4 // npx @tanstack/router-cli generate 5 + import type { QueryClient } from "@tanstack/react-query"; 6 import { 7 + createRootRouteWithContext, 8 + // Link, 9 + // Outlet, 10 Scripts, 11 useLocation, 12 + useNavigate, 13 } from "@tanstack/react-router"; 14 import { TanStackRouterDevtools } from "@tanstack/react-router-devtools"; 15 + import { useAtom } from "jotai"; 16 import * as React from "react"; 17 + import { KeepAliveOutlet, KeepAliveProvider } from "tanstack-router-keepalive"; 18 + 19 + import { Composer } from "~/components/Composer"; 20 import { DefaultCatchBoundary } from "~/components/DefaultCatchBoundary"; 21 + import { Import } from "~/components/Import"; 22 import Login from "~/components/Login"; 23 import { NotFound } from "~/components/NotFound"; 24 + import { FluentEmojiHighContrastGlowingStar } from "~/components/Star"; 25 + import { UnifiedAuthProvider, useAuth } from "~/providers/UnifiedAuthProvider"; 26 + import { composerAtom, hueAtom, useAtomCssVar } from "~/utils/atoms"; 27 import { seo } from "~/utils/seo"; 28 29 + export const Route = createRootRouteWithContext<{ 30 + queryClient: QueryClient; 31 + }>()({ 32 head: () => ({ 33 meta: [ 34 { ··· 44 }), 45 ], 46 links: [ 47 { 48 rel: "apple-touch-icon", 49 sizes: "180x180", ··· 65 { rel: "icon", href: "/favicon.ico" }, 66 ], 67 }), 68 + errorComponent: import.meta.env.DEV 69 + ? undefined 70 + : (props) => ( 71 + <RootDocument> 72 + <DefaultCatchBoundary {...props} /> 73 + </RootDocument> 74 + ), 75 notFoundComponent: () => <NotFound />, 76 component: RootComponent, 77 }); 78 79 function RootComponent() { 80 return ( 81 + <UnifiedAuthProvider> 82 + <RootDocument> 83 + <KeepAliveProvider> 84 + <KeepAliveOutlet /> 85 + </KeepAliveProvider> 86 + </RootDocument> 87 + </UnifiedAuthProvider> 88 ); 89 } 90 91 function RootDocument({ children }: { children: React.ReactNode }) { 92 + useAtomCssVar(hueAtom, "--tw-gray-hue"); 93 const location = useLocation(); 94 + const navigate = useNavigate(); 95 + const { agent } = useAuth(); 96 + const authed = !!agent?.did; 97 const isHome = location.pathname === "/"; 98 const isNotifications = location.pathname.startsWith("/notifications"); 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"); 106 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"; 124 125 + const [, setComposerPost] = useAtom(composerAtom); 126 127 return ( 128 <> 129 + <Composer /> 130 131 <div className="min-h-screen flex justify-center bg-gray-50 dark:bg-gray-950"> 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"> 133 <div className="flex items-center gap-3 mb-4"> 134 + <FluentEmojiHighContrastGlowingStar className="h-8 w-8" style={{color: "oklch(0.6616 0.2249 calc(25.88 + (var(--safe-hue) - 28))"}} /> 135 <span className="font-extrabold text-2xl tracking-tight text-gray-900 dark:text-gray-100"> 136 Red Dwarf{" "} 137 {/* <span className="text-gray-500 dark:text-gray-400 text-sm"> ··· 139 </span> */} 140 </span> 141 </div> 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 240 to="/" 241 className={ 242 `py-2 px-4 hover:bg-gray-100 dark:hover:bg-gray-900 text-xl flex items-center gap-3 ` + 243 (isHome ? "font-bold" : "") 244 } 245 > 246 + {!isHome ? ( 247 + <IconMaterialSymbolsHomeOutline width={28} height={28} /> 248 ) : ( 249 + <IconMaterialSymbolsHome width={28} height={28} /> 250 )} 251 <span>Home</span> 252 </Link> ··· 257 (isNotifications ? "font-bold" : "") 258 } 259 > 260 + {!isNotifications ? ( 261 + <IconMaterialSymbolsNotificationsOutline width={28} height={28} /> 262 ) : ( 263 + <IconMaterialSymbolsNotifications width={28} height={28} /> 264 )} 265 <span>Notifications</span> 266 </Link> ··· 271 }`} 272 > 273 {location.pathname.startsWith("/feeds") ? ( 274 + <IconMaterialSymbolsTag width={28} height={28} /> 275 ) : ( 276 + <IconMaterialSymbolsTag width={28} height={28} /> 277 )} 278 <span>Feeds</span> 279 </Link> ··· 285 }`} 286 > 287 {location.pathname.startsWith("/search") ? ( 288 + <IconMaterialSymbolsSearch width={28} height={28} /> 289 ) : ( 290 + <IconMaterialSymbolsSearch width={28} height={28} /> 291 )} 292 <span>Search</span> 293 </Link> ··· 297 }`} 298 onClick={() => { 299 if (authed && agent && agent.assertDid) { 300 + //window.location.href = `/profile/${agent.assertDid}`; 301 + navigate({ 302 + to: "/profile/$did", 303 + params: { did: agent.assertDid }, 304 + }); 305 } 306 }} 307 type="button" 308 > 309 + {!isProfile ? ( 310 + <IconMaterialSymbolsAccountCircleOutline width={28} height={28} /> 311 + ) : ( 312 + <IconMaterialSymbolsAccountCircle width={28} height={28} /> 313 + )} 314 <span>Profile</span> 315 </button> 316 <Link ··· 319 location.pathname.startsWith("/settings") ? "font-bold" : "" 320 }`} 321 > 322 + {!location.pathname.startsWith("/settings") ? ( 323 + <IconMaterialSymbolsSettingsOutline width={28} height={28} /> 324 ) : ( 325 + <IconMaterialSymbolsSettings width={28} height={28} /> 326 )} 327 <span>Settings</span> 328 + </Link> */} 329 + {/* <button 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" 331 onClick={() => setPostOpen(true)} 332 type="button" 333 > 334 + <IconMdiPencilOutline 335 width={24} 336 height={24} 337 className="text-gray-600 dark:text-gray-400" 338 /> 339 <span>Post</span> 340 + </button> */} 341 <div className="flex-1"></div> 342 <a 343 href="https://tangled.sh/@whey.party/red-dwarf" ··· 368 </div> 369 </nav> 370 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" 389 /> 390 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 + /> 478 </div> 479 + </nav> 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"> 498 {children} 499 </main> 500 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> 503 <Login /> 504 505 <div className="flex-1"></div> 506 <p className="text-xs text-gray-400 dark:text-gray-500 text-justify mx-4 mb-4"> 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) 508 </p> 509 </aside> 510 </div> 511 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 + }) 660 } 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> 694 </div> 695 + )} 696 697 + <TanStackRouterDevtools position="bottom-left" /> 698 <Scripts /> 699 </> 700 ); 701 } 702 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 + }} 729 > 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 + ); 742 743 return ( 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 + }} 753 > 754 + <div className={`mr-4 ${active ? " " : " "}`}> 755 + {active ? ActiveIcon : InactiveIcon} 756 + </div> 757 + <span 758 + className={`text-[17px] text-roboto ${active ? "font-medium" : ""}`} 759 > 760 + {text} 761 + </span> 762 + </button> 763 ); 764 } 765 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; 782 return ( 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 + }} 792 > 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> 804 ); 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 + }
+264 -96
src/routes/index.tsx
··· 1 import { createFileRoute } from "@tanstack/react-router"; 2 import { 3 - CACHE_TIMEOUT, 4 - //cachedGetRecord, 5 - //cachedResolveIdentity, 6 - UniversalPostRendererATURILoader, 7 - } from "~/components/UniversalPostRenderer"; 8 - import * as React from "react"; 9 - import { useAuth } from "~/providers/PassAuthProvider"; 10 //import { usePersistentStore } from "~/providers/PersistentStoreProvider"; 11 import { 12 useQueryIdentity, 13 - useQueryPost, 14 - useQueryFeedSkeleton, 15 useQueryPreferences, 16 - useQueryArbitrary 17 } from "~/utils/useQuery"; 18 - import { InfiniteCustomFeed } from "~/components/InfiniteCustomFeed"; 19 20 export const Route = createFileRoute("/")({ 21 component: Home, 22 }); 23 24 - function Home() { 25 const { 26 agent, 27 - loginStatus, 28 - login, 29 logout, 30 - loading: loadering, 31 - authed, 32 } = useAuth(); 33 //const { get, set } = usePersistentStore(); 34 // const [feed, setFeed] = React.useState<any[]>([]); 35 // const [loading, setLoading] = React.useState(true); ··· 48 // set, 49 // }); 50 51 - // console.log("alistoffeeds", prefs); 52 // setPrefs(prefs || {}); 53 // } catch (err) { 54 // console.error("alistoffeeds Fetch error in preferences effect:", err); ··· 67 // }, [prefs]); 68 69 // const savedFeeds = savedFeedsPref?.items || []; 70 - 71 - const identityresultmaybe = useQueryIdentity(agent?.did); 72 - const identity = identityresultmaybe?.data 73 74 - const prefsresultmaybe = useQueryPreferences({agent: agent ?? undefined, pdsUrl: identity?.pds}); 75 - const prefs = prefsresultmaybe?.data 76 - 77 const savedFeeds = React.useMemo(() => { 78 const savedFeedsPref = prefs?.preferences?.find( 79 (p: any) => p?.$type === "app.bsky.actor.defs#savedFeedsPrefV2" ··· 81 return savedFeedsPref?.items || []; 82 }, [prefs]); 83 84 85 - 86 - const [selectedFeed, setSelectedFeed] = React.useState<string | null>(null); 87 - 88 React.useEffect(() => { 89 const fallbackFeed = 90 "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot"; 91 if (authed) { 92 if (savedFeeds.length > 0) { 93 setSelectedFeed((prev) => 94 prev && savedFeeds.some((f: any) => f.value === prev) 95 ? prev 96 - : savedFeeds[0].value, 97 ); 98 } else { 99 setSelectedFeed(fallbackFeed); 100 } 101 } else { 102 setSelectedFeed(fallbackFeed); 103 } 104 - }, [savedFeeds, authed]); 105 106 // React.useEffect(() => { 107 // if (loadering || !selectedFeed) return; ··· 123 // }); 124 125 // const fetchstringcomplex = `${pdsurl.pdsUrl}/xrpc/app.bsky.feed.getFeedSkeleton?feed=${selectedFeed}`; 126 - // console.log("fetching feed authed: " + fetchstringcomplex); 127 128 // const feeddef = await cachedGetRecord({ 129 // atUri: selectedFeed, ··· 146 147 // if (!ignore) setFeed(data.feed || []); 148 // } else { 149 - // console.log("falling back"); 150 // // always use fallback feed for not logged in 151 // const fallbackFeed = 152 // "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot"; ··· 158 159 // //const feedservicedid = "did:web:discover.bsky.app" //feeddef.did; 160 // const fetchstringsimple = `https://discover.bsky.app/xrpc/app.bsky.feed.getFeedSkeleton?feed=${fallbackFeed}`; 161 - // console.log("fetching feed unauthed: " + fetchstringsimple); 162 163 // const res = await fetch(fetchstringsimple); 164 // if (!res.ok) throw new Error("Failed to fetch feed"); ··· 185 // ignore = true; 186 // }; 187 // }, [authed, agent, loadering, selectedFeed, get, set]); 188 - 189 190 - const feedGengetrecordquery = useQueryArbitrary(selectedFeed??undefined); 191 - const feedServiceDid = (feedGengetrecordquery?.data?.value as any)?.did; 192 193 // const { 194 // data: feedData, ··· 204 205 // const feed = feedData?.feed || []; 206 207 - const isReadyForAuthedFeed = authed && agent && identity?.pds && feedServiceDid; 208 - const isReadyForUnauthedFeed = !authed && selectedFeed; 209 210 return ( 211 - <div className="flex flex-col divide-y divide-gray-200 dark:divide-gray-800"> 212 - <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"> 213 - {savedFeeds.length > 0 ? ( 214 - savedFeeds.map((item: any, idx: number) => { 215 const label = item.value.split("/").pop() || item.value; 216 const isActive = selectedFeed === item.value; 217 return ( ··· 219 key={item.value || idx} 220 className={`px-3 py-1 rounded-full whitespace-nowrap font-medium transition-colors ${ 221 isActive 222 - ? "bg-gray-500 text-white" 223 - : item.pinned 224 - ? "bg-gray-200 text-gray-700 dark:bg-gray-700 dark:text-gray-200" 225 - : "bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-200" 226 }`} 227 onClick={() => setSelectedFeed(item.value)} 228 title={item.value} 229 > 230 {label} 231 {item.pinned && ( 232 - <span className="ml-1 text-xs text-gray-700 dark:text-gray-200"> 233 โ˜… 234 </span> 235 )} 236 </button> 237 ); 238 - }) 239 - ) : ( 240 - <span className="text-xl font-bold ml-2">Home</span> 241 - )} 242 - </div> 243 {/* {isFeedLoading && <div className="p-4 text-gray-500">Loading...</div>} 244 {feedError && <div className="p-4 text-red-500">{feedError.message}</div>} 245 {!isFeedLoading && !feedError && feed.length === 0 && ( ··· 252 /> 253 ))} */} 254 255 - {(authed && (!identity?.pds || !feedServiceDid)) && ( 256 - <div className="p-4 text-center text-gray-500">Preparing your feed...</div> 257 )} 258 259 - {(isReadyForAuthedFeed || isReadyForUnauthedFeed) ? ( 260 - <InfiniteCustomFeed 261 - feedUri={selectedFeed!} 262 - pdsUrl={identity?.pds} 263 - feedServiceDid={feedServiceDid} 264 - /> 265 ) : ( 266 - <div className="p-4 text-center text-gray-500">Select a feed to get started.</div> 267 )} 268 </div> 269 ); 270 } 271 272 - export async function cachedResolveDIDWEBDOC({ 273 - didweb, 274 - cacheTimeout = CACHE_TIMEOUT, 275 - get, 276 - set, 277 - }: { 278 - didweb: string; 279 - cacheTimeout?: number; 280 - get: (key: string) => any; 281 - set: (key: string, value: string) => void; 282 - }): Promise<any> { 283 - const isDidInput = didweb.startsWith("did:web:"); 284 - const cacheKey = `didwebdoc:${didweb}`; 285 - const now = Date.now(); 286 - const cached = get(cacheKey); 287 - if ( 288 - cached && 289 - cached.value && 290 - cached.time && 291 - now - cached.time < cacheTimeout 292 - ) { 293 - try { 294 - return JSON.parse(cached.value); 295 - } catch {} 296 - } 297 - const url = `https://free-fly-24.deno.dev/resolve-did-web?did=${encodeURIComponent( 298 - didweb, 299 - )}`; 300 - const res = await fetch(url); 301 - if (!res.ok) throw new Error("Failed to resolve didwebdoc"); 302 - const data = await res.json(); 303 - set(cacheKey, JSON.stringify(data)); 304 - if (!isDidInput && data.did) { 305 - set(`didwebdoc:${data.did}`, JSON.stringify(data)); 306 - } 307 - return data; 308 - } 309 310 // export async function cachedGetPrefs({ 311 // did,
··· 1 import { createFileRoute } from "@tanstack/react-router"; 2 + import { useAtom } from "jotai"; 3 + import * as React from "react"; 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"; 25 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 + // }, 86 component: Home, 87 + pendingComponent: PendingHome, // PendingHome, 88 + staticData: { keepAlive: true }, 89 }); 90 + function PendingHome() { 91 + return <div>loading... (prefetching your timeline)</div>; 92 + } 93 94 + //function Homer() { 95 + // return <div></div> 96 + //} 97 + export function Home({ hidden = false }: { hidden?: boolean }) { 98 const { 99 agent, 100 + status, 101 + authMethod, 102 + loginWithPassword, 103 + loginWithOAuth, 104 logout, 105 } = useAuth(); 106 + const authed = !!agent?.did; 107 + 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]); 125 + 126 //const { get, set } = usePersistentStore(); 127 // const [feed, setFeed] = React.useState<any[]>([]); 128 // const [loading, setLoading] = React.useState(true); ··· 141 // set, 142 // }); 143 144 + // // /*mass comment*/ console.log("alistoffeeds", prefs); 145 // setPrefs(prefs || {}); 146 // } catch (err) { 147 // console.error("alistoffeeds Fetch error in preferences effect:", err); ··· 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" ··· 180 return savedFeedsPref?.items || []; 181 }, [prefs]); 182 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; 191 192 + // /*mass comment*/ console.log("my selectedFeed is: ", selectedFeed); 193 React.useEffect(() => { 194 const fallbackFeed = 195 "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot"; 196 if (authed) { 197 + if (selectedFeed) return; 198 if (savedFeeds.length > 0) { 199 setSelectedFeed((prev) => 200 prev && savedFeeds.some((f: any) => f.value === prev) 201 ? prev 202 + : savedFeeds[0].value 203 ); 204 } else { 205 + if (selectedFeed) return; 206 setSelectedFeed(fallbackFeed); 207 } 208 } else { 209 + if (selectedFeed) return; 210 setSelectedFeed(fallbackFeed); 211 } 212 + }, [savedFeeds, authed, setSelectedFeed]); 213 214 // React.useEffect(() => { 215 // if (loadering || !selectedFeed) return; ··· 231 // }); 232 233 // const fetchstringcomplex = `${pdsurl.pdsUrl}/xrpc/app.bsky.feed.getFeedSkeleton?feed=${selectedFeed}`; 234 + // // /*mass comment*/ console.log("fetching feed authed: " + fetchstringcomplex); 235 236 // const feeddef = await cachedGetRecord({ 237 // atUri: selectedFeed, ··· 254 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"; ··· 266 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); 270 271 // const res = await fetch(fetchstringsimple); 272 // if (!res.ok) throw new Error("Failed to fetch feed"); ··· 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 }); 326 + return () => { 327 + window.removeEventListener("scroll", handleScroll); 328 + 329 + setScrollPositions(scrollPositionsRef.current); 330 + }; 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, ··· 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); 355 356 return ( 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) => { 363 const label = item.value.split("/").pop() || item.value; 364 const isActive = selectedFeed === item.value; 365 return ( ··· 367 key={item.value || idx} 368 className={`px-3 py-1 rounded-full whitespace-nowrap font-medium transition-colors ${ 369 isActive 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" 376 }`} 377 onClick={() => setSelectedFeed(item.value)} 378 title={item.value} 379 > 380 {label} 381 {item.pinned && ( 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 + > 389 โ˜… 390 </span> 391 )} 392 </button> 393 ); 394 + })} 395 + </div> 396 + ) : ( 397 + // <span className="text-xl font-bold ml-2">Home</span> 398 + <Header title="Home" /> 399 + )} 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 && ( ··· 409 /> 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 + )} */} 435 </div> 436 ); 437 } 438 + // not even used lmaooo 439 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 + // } 477 478 // export async function cachedGetPrefs({ 479 // did,
+31 -26
src/routes/notifications.tsx
··· 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"; 5 6 const HANDLE_DID_CACHE_TIMEOUT = 60 * 60 * 1000; // 1 hour 7 ··· 10 }); 11 12 function NotificationsComponent() { 13 - console.log("NotificationsComponent render"); 14 - const { agent, authed, loading: authLoading } = useAuth(); 15 - const { get, set } = usePersistentStore(); 16 const [did, setDid] = useState<string | null>(null); 17 const [resolving, setResolving] = useState(false); 18 const [error, setError] = useState<string | null>(null); ··· 28 }, [authed, agent, authLoading]); 29 30 async function handleSubmit() { 31 - console.log("handleSubmit called"); 32 setError(null); 33 setResponses([null, null, null]); 34 const value = inputRef.current?.value?.trim() || ""; ··· 41 setResolving(true); 42 const cacheKey = `handleDid:${value}`; 43 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 - } 58 try { 59 const url = `https://free-fly-24.deno.dev/?handle=${encodeURIComponent(value)}`; 60 const res = await fetch(url); 61 if (!res.ok) throw new Error("Failed to resolve handle"); 62 const data = await res.json(); 63 - set(cacheKey, JSON.stringify(data)); 64 setDid(data.did); 65 } catch (e: any) { 66 setError("Failed to resolve handle: " + (e?.message || e)); ··· 69 } 70 } 71 72 useEffect(() => { 73 if (!did) return; 74 setLoading(true); 75 setError(null); 76 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`, 80 ]; 81 let ignore = false; 82 Promise.all( ··· 94 } catch (e: any) { 95 return { error: e?.message || String(e) }; 96 } 97 - }), 98 ) 99 .then((results) => { 100 if (!ignore) setResponses(results);
··· 1 import { createFileRoute } from "@tanstack/react-router"; 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"; 7 8 const HANDLE_DID_CACHE_TIMEOUT = 60 * 60 * 1000; // 1 hour 9 ··· 12 }); 13 14 function NotificationsComponent() { 15 + // /*mass comment*/ console.log("NotificationsComponent render"); 16 + const { agent, status } = useAuth(); 17 + const authed = !!agent?.did; 18 + const authLoading = status === "loading"; 19 const [did, setDid] = useState<string | null>(null); 20 const [resolving, setResolving] = useState(false); 21 const [error, setError] = useState<string | null>(null); ··· 31 }, [authed, agent, authLoading]); 32 33 async function handleSubmit() { 34 + // /*mass comment*/ console.log("handleSubmit called"); 35 setError(null); 36 setResponses([null, null, null]); 37 const value = inputRef.current?.value?.trim() || ""; ··· 44 setResolving(true); 45 const cacheKey = `handleDid:${value}`; 46 const now = Date.now(); 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 + // } 61 try { 62 const url = `https://free-fly-24.deno.dev/?handle=${encodeURIComponent(value)}`; 63 const res = await fetch(url); 64 if (!res.ok) throw new Error("Failed to resolve handle"); 65 const data = await res.json(); 66 + //set(cacheKey, JSON.stringify(data)); 67 setDid(data.did); 68 } catch (e: any) { 69 setError("Failed to resolve handle: " + (e?.message || e)); ··· 72 } 73 } 74 75 + const [constellationURL] = useAtom(constellationURLAtom) 76 + 77 useEffect(() => { 78 if (!did) return; 79 setLoading(true); 80 setError(null); 81 const urls = [ 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`, 85 ]; 86 let ignore = false; 87 Promise.all( ··· 99 } catch (e: any) { 100 return { error: e?.message || String(e) }; 101 } 102 + }) 103 ) 104 .then((results) => { 105 if (!ignore) setResponses(results);
+203 -31
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 { useQueryClient } from "@tanstack/react-query"; 5 6 import { 7 useQueryIdentity, 8 useQueryProfile, 9 - useInfiniteQueryAuthorFeed, 10 } from "~/utils/useQuery"; 11 12 export const Route = createFileRoute("/profile/$did/")({ ··· 14 }); 15 16 function ProfileComponent() { 17 const { did } = Route.useParams(); 18 const queryClient = useQueryClient(); 19 - 20 const { 21 data: identity, 22 isLoading: isIdentityLoading, ··· 58 [postsData] 59 ); 60 61 function getAvatarUrl(p: typeof profile) { 62 const link = p?.avatar?.ref?.["$link"]; 63 if (!link || !resolvedDid) return null; 64 - return `https://cdn.bsky.app/img/avatar/plain/${resolvedDid}/${link}@jpeg`; 65 } 66 function getBannerUrl(p: typeof profile) { 67 const link = p?.banner?.ref?.["$link"]; 68 if (!link || !resolvedDid) return null; 69 - return `https://cdn.bsky.app/img/banner/plain/${resolvedDid}/${link}@jpeg`; 70 } 71 72 const displayName = ··· 96 97 return ( 98 <> 99 - <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"> 100 <Link 101 to=".." 102 className="px-3 py-1 rounded hover:bg-gray-100 dark:hover:bg-gray-900 font-bold text-lg" 103 onClick={(e) => { 104 e.preventDefault(); 105 - window.history.length > 1 106 - ? window.history.back() 107 - : window.location.assign("/"); 108 }} 109 aria-label="Go back" 110 > 111 โ† 112 </Link> 113 <span className="text-xl font-bold ml-2">Profile</span> 114 - </div> 115 116 {/* Profile Header */} 117 - <div className="w-full max-w-2xl mx-auto shadow-lg rounded-b-lg overflow-hidden relative bg-gray-200 dark:bg-gray-900"> 118 {/* Banner */} 119 <div 120 className="w-full h-40 bg-gray-300 dark:bg-gray-700" ··· 141 also delay the backfill to be on demand because it would be pretty intense 142 also save it persistently 143 */} 144 - {true ? ( 145 - <> 146 - <button className="rounded-full bg-gray-600 px-3 py-2 text-[14px]"> 147 - Follow 148 - </button> 149 - <button className="rounded-full bg-gray-600 px-3 py-2 text-[14px]"> 150 - Unfollow 151 - </button> 152 - </> 153 - ) : ( 154 - <button className="rounded-full bg-gray-600 px-3 py-2 text-[14px]"> 155 - Edit Profile 156 - </button> 157 - )} 158 - <button className="rounded-full bg-gray-600 px-3 py-2 text-[14px]"> 159 ... {/* todo: icon */} 160 - </button> 161 </div> 162 163 {/* Info Card */} 164 <div className="mt-16 pb-2 px-4 text-gray-900 dark:text-gray-100"> 165 <div className="font-bold text-2xl">{displayName}</div> 166 - <div className="text-gray-500 dark:text-gray-400 text-base mb-3"> 167 {handle} 168 </div> 169 {description && ( 170 <div className="text-base leading-relaxed text-gray-800 dark:text-gray-300 mb-5 whitespace-pre-wrap break-words text-[15px]"> 171 - {description} 172 </div> 173 )} 174 </div> ··· 211 </> 212 ); 213 }
··· 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"; 6 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"; 25 26 export const Route = createFileRoute("/profile/$did/")({ ··· 28 }); 29 30 function ProfileComponent() { 31 + // booo bad this is not always the did it might be a handle, use identity.did instead 32 const { did } = Route.useParams(); 33 + const navigate = useNavigate(); 34 const queryClient = useQueryClient(); 35 const { 36 data: identity, 37 isLoading: isIdentityLoading, ··· 73 [postsData] 74 ); 75 76 + const [imgcdn] = useAtom(imgCDNAtom); 77 + 78 function getAvatarUrl(p: typeof profile) { 79 const link = p?.avatar?.ref?.["$link"]; 80 if (!link || !resolvedDid) return null; 81 + return `https://${imgcdn}/img/avatar/plain/${resolvedDid}/${link}@jpeg`; 82 } 83 function getBannerUrl(p: typeof profile) { 84 const link = p?.banner?.ref?.["$link"]; 85 if (!link || !resolvedDid) return null; 86 + return `https://${imgcdn}/img/banner/plain/${resolvedDid}/${link}@jpeg`; 87 } 88 89 const displayName = ··· 113 114 return ( 115 <> 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"> 127 <Link 128 to=".." 129 className="px-3 py-1 rounded hover:bg-gray-100 dark:hover:bg-gray-900 font-bold text-lg" 130 onClick={(e) => { 131 e.preventDefault(); 132 + if (window.history.length > 1) { 133 + window.history.back() 134 + } else { 135 + window.location.assign("/"); 136 + } 137 }} 138 aria-label="Go back" 139 > 140 โ† 141 </Link> 142 <span className="text-xl font-bold ml-2">Profile</span> 143 + </div> */} 144 145 {/* Profile Header */} 146 + <div className="w-full max-w-2xl mx-auto overflow-hidden relative bg-gray-100 dark:bg-gray-900"> 147 {/* Banner */} 148 <div 149 className="w-full h-40 bg-gray-300 dark:bg-gray-700" ··· 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 179 {/* Info Card */} 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} /> 184 {handle} 185 </div> 186 {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} /> 190 </div> 191 )} 192 </div> ··· 229 </> 230 ); 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 + }
+241 -70
src/routes/profile.$did/post.$rkey.tsx
··· 1 - import { useQueryClient } from "@tanstack/react-query"; 2 - import { createFileRoute, Link } from "@tanstack/react-router"; 3 import React, { useLayoutEffect } from "react"; 4 - import ShrinkingBox from "~/components/shrinkpadding"; 5 import { UniversalPostRendererATURILoader } from "~/components/UniversalPostRenderer"; 6 //import { usePersistentStore } from '~/providers/PersistentStoreProvider'; 7 import { 8 useQueryIdentity, 9 useQueryPost, 10 - useQueryConstellation, 11 - constructPostQuery, 12 - useQueryArbitrary, 13 } from "~/utils/useQuery"; 14 15 //const HANDLE_DID_CACHE_TIMEOUT = 60 * 60 * 1000; // 1 hour 16 ··· 33 ); 34 } 35 36 - function ProfilePostComponent({ did, rkey }: { did: string; rkey: string }) { 37 //const { get, set } = usePersistentStore(); 38 const queryClient = useQueryClient(); 39 // const [resolvedDid, setResolvedDid] = React.useState<string | null>(null); ··· 180 () => 181 resolvedDid 182 ? `at://${decodeURIComponent(resolvedDid)}/app.bsky.feed.post/${rkey}` 183 - : "", 184 [resolvedDid, rkey] 185 ); 186 187 const { data: mainPost } = useQueryPost(atUri); 188 189 - const { data: repliesData } = useQueryConstellation({ 190 - method: "/links", 191 target: atUri, 192 - collection: "app.bsky.feed.post", 193 - path: ".reply.parent.uri", 194 }); 195 - const replies = repliesData?.linking_records.slice(0, 50) ?? []; 196 197 const [parents, setParents] = React.useState<any[]>([]); 198 const [parentsLoading, setParentsLoading] = React.useState(false); 199 200 const mainPostRef = React.useRef<HTMLDivElement>(null); 201 - const userHasScrolled = React.useRef(false); 202 203 - const scrollAnchor = React.useRef<{ top: number } | null>(null); 204 205 206 - React.useEffect(() => { 207 - const onScroll = () => { 208 209 - if (window.scrollY > 50) { 210 - userHasScrolled.current = true; 211 212 - window.removeEventListener("scroll", onScroll); 213 } 214 - }; 215 - 216 - if (!userHasScrolled.current) { 217 - window.addEventListener("scroll", onScroll, { passive: true }); 218 } 219 - return () => window.removeEventListener("scroll", onScroll); 220 - }, []); 221 222 - useLayoutEffect(() => { 223 - if (parentsLoading && mainPostRef.current && !userHasScrolled.current) { 224 - scrollAnchor.current = { 225 - top: mainPostRef.current.getBoundingClientRect().top, 226 - }; 227 } 228 - }, [parentsLoading]); 229 230 - useLayoutEffect(() => { 231 - if ( 232 - scrollAnchor.current && 233 - mainPostRef.current && 234 - !userHasScrolled.current 235 - ) { 236 - const newTop = mainPostRef.current.getBoundingClientRect().top; 237 - const topDiff = newTop - scrollAnchor.current.top; 238 - if (topDiff > 0) { 239 - window.scrollBy(0, topDiff); 240 - } 241 - scrollAnchor.current = null; 242 } 243 - }, [parents]); 244 245 React.useEffect(() => { 246 if (!mainPost?.value?.reply?.parent?.uri) { ··· 259 while (currentParentUri && safetyCounter < MAX_PARENTS) { 260 try { 261 const parentPost = await queryClient.fetchQuery( 262 - constructPostQuery(currentParentUri) 263 ); 264 if (!parentPost) break; 265 parentChain.push(parentPost); ··· 291 292 return ( 293 <> 294 - <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"> 295 - <Link 296 - to=".." 297 - className="px-3 py-1 rounded hover:bg-gray-100 dark:hover:bg-gray-900 font-bold text-lg" 298 - onClick={(e) => { 299 - e.preventDefault(); 300 - window.history.length > 1 301 - ? window.history.back() 302 - : window.location.assign("/"); 303 - }} 304 - aria-label="Go back" 305 - > 306 - โ† 307 - </Link> 308 - <span className="text-xl font-bold ml-2">Post</span> 309 - </div> 310 311 {parentsLoading && ( 312 <div className="text-center text-gray-500 dark:text-gray-400 flex flex-row"> ··· 321 )} 322 323 {/* we should use the reply lines here thats provided by UPR*/} 324 - <div style={{ maxWidth: 600, margin: "0px auto 0", padding: 0 }}> 325 {parents.map((parent, index) => ( 326 <UniversalPostRendererATURILoader 327 key={parent.uri} ··· 337 atUri={atUri} 338 detailed={true} 339 topReplyLine={parentsLoading || parents.length > 0} 340 /> 341 </div> 342 <div 343 style={{ 344 maxWidth: 600, 345 - margin: "0px auto 0", 346 padding: 0, 347 - minHeight: "100dvh", 348 }} 349 > 350 <div ··· 358 Replies 359 </div> 360 <div style={{ display: "flex", flexDirection: "column", gap: 0 }}> 361 - {replies.length > 0 && 362 - replies.map((reply) => { 363 - const replyAtUri = `at://${reply.did}/app.bsky.feed.post/${reply.rkey}`; 364 return ( 365 <UniversalPostRendererATURILoader 366 - key={replyAtUri} 367 - atUri={replyAtUri} 368 /> 369 ); 370 })} 371 </div> 372 </div> 373 </>
··· 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"; 6 + 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"; 20 + 21 + import type { LightboxProps } from "./post.$rkey.image.$i"; 22 23 //const HANDLE_DID_CACHE_TIMEOUT = 60 * 60 * 1000; // 1 hour 24 ··· 41 ); 42 } 43 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); ··· 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); 229 + 230 + React.useEffect(() => { 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", 290 + } 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); 343 + } 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; 386 } 387 + 388 + // todo idk what to do with this 389 + // eslint-disable-next-line react-hooks/set-state-in-effect 390 + setLayoutReady(true); 391 } 392 + }, [parents, layoutReady]); 393 + 394 395 + const [slingshoturl] = useAtom(slingshotURLAtom) 396 + 397 + React.useEffect(() => { 398 + if (parentsLoading) { 399 + setLayoutReady(false); 400 } 401 402 + if (!mainPost?.value?.reply?.parent?.uri && !parentsLoading) { 403 + setLayoutReady(true); 404 + hasPerformedInitialLayout.current = true; 405 } 406 + }, [parentsLoading, mainPost]); 407 408 React.useEffect(() => { 409 if (!mainPost?.value?.reply?.parent?.uri) { ··· 422 while (currentParentUri && safetyCounter < MAX_PARENTS) { 423 try { 424 const parentPost = await queryClient.fetchQuery( 425 + constructPostQuery(currentParentUri, slingshoturl) 426 ); 427 if (!parentPost) break; 428 parentChain.push(parentPost); ··· 454 455 return ( 456 <> 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 + /> 468 469 {parentsLoading && ( 470 <div className="text-center text-gray-500 dark:text-gray-400 flex flex-row"> ··· 479 )} 480 481 {/* we should use the reply lines here thats provided by UPR*/} 482 + <div style={{ maxWidth: 600, padding: 0 }}> 483 {parents.map((parent, index) => ( 484 <UniversalPostRendererATURILoader 485 key={parent.uri} ··· 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 ··· 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 ); 532 })} 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 + )} 542 </div> 543 </div> 544 </>
+50 -1
src/routes/search.tsx
··· 1 import { createFileRoute } from "@tanstack/react-router"; 2 3 export const Route = createFileRoute("/search")({ 4 component: Search, 5 }); 6 7 export function Search() { 8 - return <div className="p-6">Search page (coming soon)</div>; 9 }
··· 1 import { createFileRoute } from "@tanstack/react-router"; 2 3 + import { Header } from "~/components/Header"; 4 + import { Import } from "~/components/Import"; 5 + 6 export const Route = createFileRoute("/search")({ 7 component: Search, 8 }); 9 10 export function Search() { 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 + ); 58 }
+181 -1
src/routes/settings.tsx
··· 1 import { createFileRoute } from "@tanstack/react-router"; 2 3 export const Route = createFileRoute("/settings")({ 4 component: Settings, 5 }); 6 7 export function Settings() { 8 - return <div className="p-6">Settings page (coming soon)</div>; 9 }
··· 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"; 19 20 export const Route = createFileRoute("/settings")({ 21 component: Settings, 22 }); 23 24 export function Settings() { 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 + ); 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 "tailwindcss"; 2 3 /* @theme { ··· 14 --color-gray-950: oklch(0.129 0.050 222.000); 15 } */ 16 17 @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); 29 } 30 31 @layer base { ··· 47 } 48 } 49 50 @media (width >= 64rem /* 1024px */) { 51 - html, 52 - body { 53 scrollbar-gutter: stable both-edges !important; 54 } 55 } 56 .scroll-thin { 57 scrollbar-width: thin; 58 /*scrollbar-gutter: stable both-edges !important;*/ ··· 61 .scroll-none { 62 scrollbar-width: none; 63 }
··· 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'); 2 @import "tailwindcss"; 3 4 /* @theme { ··· 15 --color-gray-950: oklch(0.129 0.050 222.000); 16 } */ 17 18 + :root { 19 + --safe-hue: var(--tw-gray-hue, 28) 20 + } 21 + 22 @theme { 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)); 34 } 35 36 @layer base { ··· 52 } 53 } 54 55 + .gutter{ 56 + scrollbar-gutter: stable both-edges; 57 + } 58 + 59 @media (width >= 64rem /* 1024px */) { 60 + html:not(:has(.disablegutter)), 61 + body:not(:has(.disablegutter)) { 62 scrollbar-gutter: stable both-edges !important; 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; 73 } 74 + 75 .scroll-thin { 76 scrollbar-width: thin; 77 /*scrollbar-gutter: stable both-edges !important;*/ ··· 80 .scroll-none { 81 scrollbar-width: none; 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 + }
+80 -3
src/utils/atoms.ts
··· 1 - import { atom } from "jotai"; 2 3 - export const selectedFeedUriAtom = atom<string | null>(null); 4 5 - export const feedScrollPositionsAtom = atom<Record<string, number>>({});
··· 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 + });
+70 -71
src/utils/useHydrated.ts
··· 1 - import { useState, useEffect, useMemo } from "react"; 2 import { 3 AppBskyEmbedExternal, 4 AppBskyEmbedImages, 5 AppBskyEmbedRecord, 6 AppBskyEmbedRecordWithMedia, 7 AppBskyEmbedVideo, 8 - AppBskyActorDefs, 9 AppBskyFeedPost, 10 AtUri, 11 - type $Typed, 12 } from "@atproto/api"; 13 - import * as ATPAPI from "@atproto/api" 14 15 - import { useQueryPost, useQueryProfile, useQueryIdentity } from "./useQuery"; 16 17 - type QueryResultData<T extends (...args: any) => any> = ReturnType<T> extends 18 - | { data: infer D } 19 - | undefined 20 - ? D 21 - : never; 22 23 function asTyped<T extends { $type: string }>(obj: T): $Typed<T> { 24 return obj as $Typed<T>; ··· 27 export function hydrateEmbedImages( 28 embed: AppBskyEmbedImages.Main, 29 did: string, 30 ): $Typed<AppBskyEmbedImages.View> { 31 return asTyped({ 32 $type: "app.bsky.embed.images#view" as const, ··· 35 const link = img.image.ref?.["$link"]; 36 if (!link) return null; 37 return { 38 - thumb: `https://cdn.bsky.app/img/feed_thumbnail/plain/${did}/${link}@jpeg`, 39 - fullsize: `https://cdn.bsky.app/img/feed_fullsize/plain/${did}/${link}@jpeg`, 40 alt: img.alt || "", 41 aspectRatio: img.aspectRatio, 42 }; ··· 48 export function hydrateEmbedExternal( 49 embed: AppBskyEmbedExternal.Main, 50 did: string, 51 ): $Typed<AppBskyEmbedExternal.View> { 52 return asTyped({ 53 $type: "app.bsky.embed.external#view" as const, ··· 56 title: embed.external.title, 57 description: embed.external.description, 58 thumb: embed.external.thumb?.ref?.$link 59 - ? `https://cdn.bsky.app/img/feed_thumbnail/plain/${did}/${embed.external.thumb.ref.$link}@jpeg` 60 : undefined, 61 }, 62 }); ··· 65 export function hydrateEmbedVideo( 66 embed: AppBskyEmbedVideo.Main, 67 did: string, 68 ): $Typed<AppBskyEmbedVideo.View> { 69 const videoLink = embed.video.ref.$link; 70 return asTyped({ 71 $type: "app.bsky.embed.video#view" as const, 72 - playlist: `https://video.bsky.app/watch/${did}/${videoLink}/playlist.m3u8`, 73 - thumbnail: `https://video.bsky.app/watch/${did}/${videoLink}/thumbnail.jpg`, 74 aspectRatio: embed.aspectRatio, 75 cid: videoLink, 76 }); ··· 81 quotedPost: QueryResultData<typeof useQueryPost>, 82 quotedProfile: QueryResultData<typeof useQueryProfile>, 83 quotedIdentity: QueryResultData<typeof useQueryIdentity>, 84 ): $Typed<AppBskyEmbedRecord.View> | undefined { 85 if (!quotedPost || !quotedProfile || !quotedIdentity) { 86 return undefined; ··· 92 handle: quotedIdentity.handle, 93 displayName: quotedProfile.value.displayName ?? quotedIdentity.handle, 94 avatar: quotedProfile.value.avatar?.ref?.$link 95 - ? `https://cdn.bsky.app/img/avatar/plain/${quotedIdentity.did}/${quotedProfile.value.avatar.ref.$link}@jpeg` 96 : undefined, 97 viewer: {}, 98 labels: [], ··· 123 quotedPost: QueryResultData<typeof useQueryPost>, 124 quotedProfile: QueryResultData<typeof useQueryProfile>, 125 quotedIdentity: QueryResultData<typeof useQueryIdentity>, 126 ): $Typed<AppBskyEmbedRecordWithMedia.View> | undefined { 127 const hydratedRecord = hydrateEmbedRecord( 128 embed.record, 129 quotedPost, 130 quotedProfile, 131 quotedIdentity, 132 ); 133 134 if (!hydratedRecord) return undefined; ··· 149 150 export function useHydratedEmbed( 151 embed: AppBskyFeedPost.Record["embed"], 152 - postAuthorDid: string | undefined, 153 ) { 154 const recordInfo = useMemo(() => { 155 - if ( 156 - AppBskyEmbedRecordWithMedia.isMain(embed) 157 - ) { 158 const recordUri = embed.record.record.uri; 159 const quotedAuthorDid = new AtUri(recordUri).hostname; 160 return { recordUri, quotedAuthorDid, isRecordType: true }; 161 - } else 162 - if ( 163 - AppBskyEmbedRecord.isMain(embed) 164 - ) { 165 const recordUri = embed.record.uri; 166 const quotedAuthorDid = new AtUri(recordUri).hostname; 167 return { recordUri, quotedAuthorDid, isRecordType: true }; ··· 172 isRecordType: false, 173 }; 174 }, [embed]); 175 - const { isRecordType, recordUri, quotedAuthorDid } = recordInfo; 176 177 178 const usequerypostresults = useQueryPost(recordUri); 179 - // const { 180 - // data: quotedPost, 181 - // isLoading: isLoadingPost, 182 - // error: postError, 183 - // } = usequerypostresults 184 185 - const profileUri = quotedAuthorDid ? `at://${quotedAuthorDid}/app.bsky.actor.profile/self` : undefined; 186 187 const { 188 data: quotedProfile, ··· 190 error: profileError, 191 } = useQueryProfile(profileUri); 192 193 const queryidentityresult = useQueryIdentity(quotedAuthorDid); 194 - // const { 195 - // data: quotedIdentity, 196 - // isLoading: isLoadingIdentity, 197 - // error: identityError, 198 - // } = queryidentityresult 199 200 - const [hydratedEmbed, setHydratedEmbed] = useState< 201 - HydratedEmbedView | undefined 202 - >(undefined); 203 204 - useEffect(() => { 205 - if (!embed || !postAuthorDid) { 206 - setHydratedEmbed(undefined); 207 - return; 208 - } 209 - 210 - if (isRecordType && (!usequerypostresults?.data || !quotedProfile || !queryidentityresult?.data)) { 211 - setHydratedEmbed(undefined); 212 - return; 213 } 214 215 try { 216 - let result: HydratedEmbedView | undefined; 217 - 218 if (AppBskyEmbedImages.isMain(embed)) { 219 - result = hydrateEmbedImages(embed, postAuthorDid); 220 } else if (AppBskyEmbedExternal.isMain(embed)) { 221 - result = hydrateEmbedExternal(embed, postAuthorDid); 222 } else if (AppBskyEmbedVideo.isMain(embed)) { 223 - result = hydrateEmbedVideo(embed, postAuthorDid); 224 } else if (AppBskyEmbedRecord.isMain(embed)) { 225 - result = hydrateEmbedRecord( 226 embed, 227 usequerypostresults?.data, 228 quotedProfile, 229 queryidentityresult?.data, 230 ); 231 } else if (AppBskyEmbedRecordWithMedia.isMain(embed)) { 232 let hydratedMedia: ··· 236 | undefined; 237 238 if (AppBskyEmbedImages.isMain(embed.media)) { 239 - hydratedMedia = hydrateEmbedImages(embed.media, postAuthorDid); 240 } else if (AppBskyEmbedExternal.isMain(embed.media)) { 241 - hydratedMedia = hydrateEmbedExternal(embed.media, postAuthorDid); 242 } else if (AppBskyEmbedVideo.isMain(embed.media)) { 243 - hydratedMedia = hydrateEmbedVideo(embed.media, postAuthorDid); 244 } 245 246 if (hydratedMedia) { 247 - result = hydrateEmbedRecordWithMedia( 248 embed, 249 hydratedMedia, 250 usequerypostresults?.data, 251 quotedProfile, 252 queryidentityresult?.data, 253 ); 254 } 255 } 256 - setHydratedEmbed(result); 257 } catch (e) { 258 console.error("Error hydrating embed", e); 259 - setHydratedEmbed(undefined); 260 } 261 - }, [ 262 - embed, 263 - postAuthorDid, 264 - isRecordType, 265 - usequerypostresults?.data, 266 - quotedProfile, 267 - queryidentityresult?.data, 268 - ]); 269 270 const isLoading = isRecordType 271 - ? usequerypostresults?.isLoading || isLoadingProfile || queryidentityresult?.isLoading 272 : false; 273 - const error = usequerypostresults?.error || profileError || queryidentityresult?.error; 274 275 return { data: hydratedEmbed, isLoading, error }; 276 - }
··· 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>; ··· 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, ··· 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 }; ··· 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, ··· 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 }); ··· 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 }); ··· 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; ··· 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: [], ··· 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; ··· 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 }; ··· 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, ··· 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: ··· 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 + }
+172 -44
src/utils/useQuery.ts
··· 1 import { 2 queryOptions, 3 - useQuery, 4 useInfiniteQuery, 5 - type QueryFunctionContext, 6 - type UseQueryResult, 7 - type InfiniteData 8 - } from "@tanstack/react-query"; 9 - import * as ATPAPI from "@atproto/api"; 10 11 - export function constructIdentityQuery(didorhandle?: string) { 12 return queryOptions({ 13 queryKey: ["identity", didorhandle], 14 queryFn: async () => { 15 if (!didorhandle) return undefined as undefined 16 const res = await fetch( 17 - `https://slingshot.microcosm.blue/xrpc/com.bad-example.identity.resolveMiniDoc?identifier=${encodeURIComponent(didorhandle)}` 18 ); 19 if (!res.ok) throw new Error("Failed to fetch post"); 20 try { ··· 28 return undefined; 29 } 30 }, 31 }); 32 } 33 export function useQueryIdentity(didorhandle: string): UseQueryResult< ··· 54 Error 55 > 56 export function useQueryIdentity(didorhandle?: string) { 57 - return useQuery(constructIdentityQuery(didorhandle)); 58 } 59 60 - export function constructPostQuery(uri?: string) { 61 return queryOptions({ 62 queryKey: ["post", uri], 63 queryFn: async () => { 64 if (!uri) return undefined as undefined 65 const res = await fetch( 66 - `https://slingshot.microcosm.blue/xrpc/com.bad-example.repo.getUriRecord?at_uri=${encodeURIComponent(uri)}` 67 ); 68 - if (!res.ok) throw new Error("Failed to fetch post"); 69 try { 70 - return (await res.json()) as { 71 uri: string; 72 cid: string; 73 - value: ATPAPI.AppBskyFeedPost.Record; 74 }; 75 } catch (_e) { 76 return undefined; 77 } 78 }, 79 }); 80 } 81 export function useQueryPost(uri: string): UseQueryResult< ··· 100 Error 101 > 102 export function useQueryPost(uri?: string) { 103 - return useQuery(constructPostQuery(uri)); 104 } 105 106 - export function constructProfileQuery(uri?: string) { 107 return queryOptions({ 108 queryKey: ["profile", uri], 109 queryFn: async () => { 110 if (!uri) return undefined as undefined 111 const res = await fetch( 112 - `https://slingshot.microcosm.blue/xrpc/com.bad-example.repo.getUriRecord?at_uri=${encodeURIComponent(uri)}` 113 ); 114 - if (!res.ok) throw new Error("Failed to fetch post"); 115 try { 116 - return (await res.json()) as { 117 uri: string; 118 cid: string; 119 - value: ATPAPI.AppBskyActorProfile.Record; 120 }; 121 } catch (_e) { 122 return undefined; 123 } 124 }, 125 }); 126 } 127 export function useQueryProfile(uri: string): UseQueryResult< ··· 146 Error 147 > 148 export function useQueryProfile(uri?: string) { 149 - return useQuery(constructProfileQuery(uri)); 150 } 151 152 // export function constructConstellationQuery( ··· 182 // target: string 183 // ): QueryOptions<linksAllResponse, Error>; 184 export function constructConstellationQuery(query?:{ 185 method: 186 | "/links" 187 | "/links/distinct-dids" 188 | "/links/count" 189 | "/links/count/distinct-dids" 190 - | "/links/all", 191 target: string, 192 collection?: string, 193 path?: string, 194 - cursor?: string 195 } 196 ) { 197 // : QueryOptions< ··· 203 // Error 204 // > 205 return queryOptions({ 206 - queryKey: ["post", query?.method, query?.target, query?.collection, query?.path, query?.cursor] as const, 207 queryFn: async () => { 208 - if (!query) return undefined as undefined 209 const method = query.method 210 const target = query.target 211 const collection = query?.collection 212 const path = query?.path 213 const cursor = query.cursor 214 const res = await fetch( 215 - `https://constellation.microcosm.blue${method}?target=${encodeURIComponent(target)}${collection ? `&collection=${encodeURIComponent(collection)}` : ""}${path ? `&path=${encodeURIComponent(path)}` : ""}${cursor ? `&cursor=${encodeURIComponent(cursor)}` : ""}` 216 ); 217 if (!res.ok) throw new Error("Failed to fetch post"); 218 try { ··· 234 return undefined; 235 } 236 }, 237 }); 238 } 239 export function useQueryConstellation(query: { ··· 242 collection: string; 243 path: string; 244 cursor?: string; 245 }): UseQueryResult<linksRecordsResponse, Error>; 246 export function useQueryConstellation(query: { 247 method: "/links/distinct-dids"; ··· 269 target: string; 270 }): UseQueryResult<linksAllResponse, Error>; 271 export function useQueryConstellation(): undefined; 272 export function useQueryConstellation(query?: { 273 method: 274 | "/links" 275 | "/links/distinct-dids" 276 | "/links/count" 277 | "/links/count/distinct-dids" 278 - | "/links/all"; 279 target: string; 280 collection?: string; 281 path?: string; 282 cursor?: string; 283 }): 284 | UseQueryResult< 285 | linksRecordsResponse ··· 291 > 292 | undefined { 293 //if (!query) return; 294 return useQuery( 295 - constructConstellationQuery(query) 296 ); 297 } 298 ··· 301 collection: string; 302 rkey: string; 303 }; 304 - type linksRecordsResponse = { 305 total: string; 306 linking_records: linksRecord[]; 307 cursor?: string; ··· 314 type linksCountResponse = { 315 total: string; 316 }; 317 - type linksAllResponse = { 318 links: Record< 319 string, 320 Record< ··· 329 330 export function constructFeedSkeletonQuery(options?: { 331 feedUri: string; 332 - agent?: ATPAPI.AtpAgent; 333 isAuthed: boolean; 334 pdsUrl?: string; 335 feedServiceDid?: string; ··· 369 370 export function useQueryFeedSkeleton(options?: { 371 feedUri: string; 372 - agent?: ATPAPI.AtpAgent; 373 isAuthed: boolean; 374 pdsUrl?: string; 375 feedServiceDid?: string; ··· 377 return useQuery(constructFeedSkeletonQuery(options)); 378 } 379 380 - export function constructPreferencesQuery(agent?: ATPAPI.AtpAgent | undefined, pdsUrl?: string | undefined) { 381 return queryOptions({ 382 queryKey: ['preferences', agent?.did], 383 queryFn: async () => { ··· 390 }); 391 } 392 export function useQueryPreferences(options: { 393 - agent?: ATPAPI.AtpAgent | undefined, pdsUrl?: string | undefined 394 }) { 395 return useQuery(constructPreferencesQuery(options.agent, options.pdsUrl)); 396 } 397 398 399 400 - export function constructArbitraryQuery(uri?: string) { 401 return queryOptions({ 402 - queryKey: ["post", uri], 403 queryFn: async () => { 404 if (!uri) return undefined as undefined 405 const res = await fetch( 406 - `https://slingshot.microcosm.blue/xrpc/com.bad-example.repo.getUriRecord?at_uri=${encodeURIComponent(uri)}` 407 ); 408 - if (!res.ok) throw new Error("Failed to fetch post"); 409 try { 410 - return (await res.json()) as { 411 uri: string; 412 cid: string; 413 value: any; ··· 416 return undefined; 417 } 418 }, 419 }); 420 } 421 export function useQueryArbitrary(uri: string): UseQueryResult< ··· 439 Error 440 >; 441 export function useQueryArbitrary(uri?: string) { 442 - return useQuery(constructArbitraryQuery(uri)); 443 } 444 445 export function constructFallbackNothingQuery(){ ··· 495 496 export function constructInfiniteFeedSkeletonQuery(options: { 497 feedUri: string; 498 - agent?: ATPAPI.AtpAgent; 499 isAuthed: boolean; 500 pdsUrl?: string; 501 feedServiceDid?: string; ··· 534 535 export function useInfiniteQueryFeedSkeleton(options: { 536 feedUri: string; 537 - agent?: ATPAPI.AtpAgent; 538 isAuthed: boolean; 539 pdsUrl?: string; 540 feedServiceDid?: string; 541 }) { 542 const { queryKey, queryFn } = constructInfiniteFeedSkeletonQuery(options); 543 544 - return useInfiniteQuery({ 545 queryKey, 546 queryFn, 547 initialPageParam: undefined as never, ··· 549 staleTime: Infinity, 550 refetchOnWindowFocus: false, 551 enabled: !!options.feedUri && (options.isAuthed ? !!options.agent && !!options.pdsUrl && !!options.feedServiceDid : true), 552 - }); 553 }
··· 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 { ··· 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< ··· 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< ··· 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< ··· 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( ··· 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< ··· 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 { ··· 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: { ··· 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"; ··· 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 ··· 346 > 347 | undefined { 348 //if (!query) return; 349 + const [constellationurl] = useAtom(constellationURLAtom) 350 return useQuery( 351 + constructConstellationQuery(query && {constellation: constellationurl, ...query}) 352 ); 353 } 354 ··· 357 collection: string; 358 rkey: string; 359 }; 360 + export type linksRecordsResponse = { 361 total: string; 362 linking_records: linksRecord[]; 363 cursor?: string; ··· 370 type linksCountResponse = { 371 total: string; 372 }; 373 + export type linksAllResponse = { 374 links: Record< 375 string, 376 Record< ··· 385 386 export function constructFeedSkeletonQuery(options?: { 387 feedUri: string; 388 + agent?: ATPAPI.Agent; 389 isAuthed: boolean; 390 pdsUrl?: string; 391 feedServiceDid?: string; ··· 425 426 export function useQueryFeedSkeleton(options?: { 427 feedUri: string; 428 + agent?: ATPAPI.Agent; 429 isAuthed: boolean; 430 pdsUrl?: string; 431 feedServiceDid?: string; ··· 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 () => { ··· 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; ··· 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< ··· 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(){ ··· 569 570 export function constructInfiniteFeedSkeletonQuery(options: { 571 feedUri: string; 572 + agent?: ATPAPI.Agent; 573 isAuthed: boolean; 574 pdsUrl?: string; 575 feedServiceDid?: string; ··· 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, ··· 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 "jsx": "react-jsx", 6 "module": "ESNext", 7 "lib": ["ES2022", "DOM", "DOM.Iterable"], 8 - "types": ["vite/client"], 9 10 /* Bundler mode */ 11 "moduleResolution": "bundler",
··· 5 "jsx": "react-jsx", 6 "module": "ESNext", 7 "lib": ["ES2022", "DOM", "DOM.Iterable"], 8 + "types": ["vite/client", "unplugin-icons/types/react"], 9 10 /* Bundler mode */ 11 "moduleResolution": "bundler",
+49 -5
vite.config.ts
··· 1 - import { defineConfig } from "vite"; 2 import viteReact from "@vitejs/plugin-react"; 3 - import tailwindcss from "@tailwindcss/vite"; 4 5 - import { TanStackRouterVite } from "@tanstack/router-plugin/vite"; 6 - import { resolve } from "node:path"; 7 8 // https://vitejs.dev/config/ 9 export default defineConfig({ 10 plugins: [ 11 TanStackRouterVite({ autoCodeSplitting: true }), 12 - viteReact(), 13 tailwindcss(), 14 ], 15 // test: { 16 // globals: true, ··· 21 "@": resolve(__dirname, "./src"), 22 "~": resolve(__dirname, "./src"), 23 }, 24 }, 25 });
··· 1 + import { resolve } from "node:path"; 2 + 3 + import tailwindcss from "@tailwindcss/vite"; 4 + import { TanStackRouterVite } from "@tanstack/router-plugin/vite"; 5 import viteReact from "@vitejs/plugin-react"; 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" 15 16 + function shp(url: string): string { 17 + return url.replace(/^https?:\/\//, ''); 18 + } 19 20 // https://vitejs.dev/config/ 21 export default defineConfig({ 22 plugins: [ 23 + generateMetadataPlugin({ 24 + prod: PROD_URL, 25 + dev: DEV_URL, 26 + }), 27 TanStackRouterVite({ autoCodeSplitting: true }), 28 + viteReact({ 29 + babel: { 30 + plugins: ['babel-plugin-react-compiler'], 31 + }, 32 + }), 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 + }), 52 ], 53 // test: { 54 // globals: true, ··· 59 "@": resolve(__dirname, "./src"), 60 "~": resolve(__dirname, "./src"), 61 }, 62 + }, 63 + server: { 64 + allowedHosts: [shp(PROD_URL),shp(DEV_URL)], 65 + }, 66 + css: { 67 + devSourcemap: true, 68 }, 69 });