+51
-13
README.md
+51
-13
README.md
···
1
-
# Initial Red Dwarf Open Source Release
2
-
i made red dwarf in three days
1
+
# Red Dwarf
2
+
Red Dwarf is a Bluesky client that does not use any AppView servers, instead it gathers the data from [Constellation](https://constellation.microcosm.blue/) and each users' PDS.
3
3
4
-
it isnt really that well made
5
-
(go take a look at `UniversalPostRenderer.tsx`)
4
+

6
5
7
-
further development is pending
8
-
(especially around future plans for user-resolved constellation instances)
6
+
huge thanks to [Microcosm](https://microcosm.blue/) for making this possible
9
7
10
-
huge thanks to Constellation ([Microcosm](https://microcosm.blue/)) for making this possible
8
+
## running dev and build
9
+
in the `vite.config.ts` file you should change these values
10
+
```ts
11
+
const PROD_URL = "https://reddwarf.app"
12
+
const DEV_URL = "https://local3768forumtest.whey.party"
13
+
```
14
+
the PROD_URL is what will compile your oauth client metadata so it is very important to change that. same for DEV_URL if you are using a tunnel for dev work
15
+
16
+
run dev with `npm run dev` (port 3768) and build with `npm run build` (the output is the `dist` folder)
17
+
18
+
## useQuery
19
+
Red Dwarf has been upgraded from its original bespoke caching system to Tanstack Query (react query). this migration was done to achieve a more robust and maintainable approach to data fetching and caching and state synchronization. ive seen serious performance gains from this switch!
20
+
21
+
all core data fetching logic is now centralized in `src/utils/useQuery.ts` and exposed as a collection of custom react hooks. theres two basic types of custom hooks, the use-once, and the inifinite query ones (used for paginated requests like feed skeletons and listrecord)
11
22
12
23
## UniversalPostRenderer
13
24
its a mega component rooted in my Masonry "[TestFront](https://testfront-87q.pages.dev/)" project. its goal is simple: have one component render everything. it has several shims to normalize different post data formats into a single format the component can handle. unlike TestFront, it has no animations, though some weird component splits might linger from the old version.
14
25
15
26
to adapt TestFront's bsky-api-based `UniversalPostRenderer` to Red Dwarf's model of fetching records directly from each user's PDS and then querying constellation for backlinks, i wrap it in `UniversalPostRendererATURILoader`, which handles raw record and backlink fetching. to bridge the gap between bsky api shapes like `PostView` and the raw record, i use `UniversalPostRendererRawRecordShim`. this way, the core `UniversalPostRenderer` remains the same between TestFront and Red Dwarf (with the only difference being in the red dwarf version the framer motion animations are removed).
16
27
28
+
## Microcosm
29
+
### Constellation
30
+
the beating heart of Red Dwarf, the backlink index that provides contextual information not available from direct PDS queries. Every post's likes, replies, and reposts all come from constellation. Unfortunately i wasnt using tanstack query at the time (compared to its intensive use in the old version of ForumTest) so it is not using any caching
17
31
18
-
## PassAuthProvider
19
-
a really bad app-password auth provider, inherited from TestFront and used in all my projects from TestFront to ForumTest (im very good at naming things). in ForumTest, its been superseded by the [OAuthProvider](https://tangled.sh/@whey.party/forumtest/blob/main/src/providers/OAuthProvider.tsx). i havent backported it here and maybe soon, although oauth makes it slightly more annoying to do development because it requires a tunnel so maybe someday if i managed to merge the password and oauth logins to provide both options
32
+
### Slingshot
33
+
though Red Dwarf was made before Microcosm [Slingshot](https://slingshot.microcosm.blue) existed, it now uses Slingshot to reduce load from each respective PDS server. Slignshot
20
34
21
-
## Constellation
22
-
the beating heart of Red Dwarf, the backlink index that provides contextual information not available from direct PDS queries. Every post's likes, replies, and reposts all come from constellation. Unfortunately i wasnt using tanstack query at the time (compared to its intensive use in the old version of ForumTest) so it is not using any caching
35
+
## UnifiedAuthProvider
36
+
a merged auth provider with oauth and password based login. oauth makes it slightly more annoying to do development because it requires a tunnel, so so the password auth option is still here if you do prefer password login for whatever reason.
23
37
24
-
Red Dwarf was made before Microcosm [Slingshot](https://slingshot.microcosm.blue) existed, and it would be a very good idea to migrate to it in the future maybe (to reduce load from individual PDS servers)
38
+
### Pass Auth
39
+
a really bad app-password auth provider, inherited from TestFront and used in all my projects from TestFront to ForumTest (im very good at naming things).
40
+
41
+
### OAuth
42
+
taken from ForumTest [OAuthProvider](https://tangled.sh/@whey.party/forumtest/blob/main/src/providers/OAuthProvider.tsx)
25
43
26
44
## Custom Feeds
27
45
they work, but i havent implemented a simple way of viewing arbitraty feeds. currently it either loads discover (logged out) or your saved feeds (logged in) and its not a technical limitation i just havent implemented it yet
···
34
52
and for list feeds, you can just use something like graze or skyfeed to input a list of users and output a custom feed
35
53
36
54
## Tanstack Router
37
-
it does the job, nothing very specific was used here
55
+
something specific was used here
56
+
57
+
so tanstack router is used as the base, but the home route is using tanstack-router-keepalive to preserve the route for better responsiveness, and it also saves scroll position of feeds into jotai (persistent)
58
+
59
+
i previously used a tanstack router loader to ensure the tanstack query cache is ready to prevent scroll jumps but it is way too slow so i replaced it with tanstack-router-keepalive
60
+
61
+
## Icons
62
+
this project uses Material icons. do not the light variant. sometimes i use `Mdi` if the icon needed doesnt exist in `MaterialSymbols`
63
+
64
+
the project uses unplugin icon auto import, so you can just use the component and itll just work!
65
+
66
+
the format is:
67
+
```tsx
68
+
<IconMaterialSymbols{icon name here} />
69
+
// or
70
+
<IconMdi{icon name here} />
71
+
```
72
+
73
+
you can get the full list of icon names from iconify ([Material Symbols](https://icon-sets.iconify.design/material-symbols/) or [MDI](https://icon-sets.iconify.design/mdi/))
74
+
75
+
while it is nice to keep everything consistent by using material icons, if the icon you need is not provided by either material symbols nor mdi, you are allowed to just grab any icon from any pack (please do prioritize icons that fit in)
+59
eslint.config.ts
+59
eslint.config.ts
···
1
+
import eslintJs from "@eslint/js";
2
+
import eslintReact from "@eslint-react/eslint-plugin";
3
+
import { defineConfig } from "eslint/config";
4
+
import reactHooks from "eslint-plugin-react-hooks";
5
+
import simpleImportSort from "eslint-plugin-simple-import-sort";
6
+
import unusedImports from "eslint-plugin-unused-imports";
7
+
import tseslint from "typescript-eslint";
8
+
9
+
export default defineConfig([
10
+
{
11
+
files: ["**/*.ts", "**/*.tsx"],
12
+
extends: [
13
+
eslintJs.configs.recommended,
14
+
tseslint.configs.recommended,
15
+
eslintReact.configs["recommended-typescript"],
16
+
reactHooks.configs.flat["recommended-latest"],
17
+
],
18
+
plugins: {
19
+
"react-hooks": reactHooks,
20
+
"simple-import-sort": simpleImportSort,
21
+
"unused-imports": unusedImports,
22
+
},
23
+
languageOptions: {
24
+
parser: tseslint.parser,
25
+
parserOptions: {
26
+
projectService: true,
27
+
tsconfigRootDir: import.meta.dirname,
28
+
},
29
+
},
30
+
rules: {
31
+
// Unused imports
32
+
"unused-imports/no-unused-imports": "error",
33
+
"unused-imports/no-unused-vars": [
34
+
"warn",
35
+
{
36
+
vars: "all",
37
+
varsIgnorePattern: "^_",
38
+
args: "after-used",
39
+
argsIgnorePattern: "^_",
40
+
},
41
+
],
42
+
43
+
// Auto sort imports
44
+
"simple-import-sort/imports": "error",
45
+
"simple-import-sort/exports": "error",
46
+
47
+
48
+
"@typescript-eslint/no-unused-vars": [
49
+
"warn",
50
+
{
51
+
argsIgnorePattern: "^_",
52
+
varsIgnorePattern: "^_",
53
+
caughtErrorsIgnorePattern: "^_",
54
+
},
55
+
],
56
+
"@typescript-eslint/no-explicit-any": "warn",
57
+
},
58
+
},
59
+
]);
+2
-3
index.html
+2
-3
index.html
···
4
4
<meta charset="UTF-8" />
5
5
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
<link rel="icon" href="/favicon.ico" />
7
-
<meta name="theme-color" content="#000000" />
7
+
<meta name="theme-color" content="#180001" />
8
8
<meta
9
9
name="description"
10
-
content="Web site created using create-tsrouter-app"
10
+
content="an appview-less Bluesky client using Constellation and PDS Queries"
11
11
/>
12
12
<link rel="apple-touch-icon" href="/redstar.png" />
13
13
<link rel="manifest" href="/manifest.json" />
14
-
<link rel="stylesheet" href="/src/styles/app.css" />
15
14
<title>Red Dwarf</title>
16
15
</head>
17
16
<body>
+48
oauthdev.mts
+48
oauthdev.mts
···
1
+
import fs from 'fs';
2
+
import path from 'path';
3
+
//import { generateClientMetadata } from './src/helpers/oauthClient'
4
+
export const generateClientMetadata = (appOrigin: string) => {
5
+
const callbackPath = '/callback';
6
+
7
+
return {
8
+
"client_id": `${appOrigin}/client-metadata.json`,
9
+
"client_name": "ForumTest",
10
+
"client_uri": appOrigin,
11
+
"logo_uri": `${appOrigin}/logo192.png`,
12
+
"tos_uri": `${appOrigin}/terms-of-service`,
13
+
"policy_uri": `${appOrigin}/privacy-policy`,
14
+
"redirect_uris": [`${appOrigin}${callbackPath}`] as [string, ...string[]],
15
+
"scope": "atproto transition:generic",
16
+
"grant_types": ["authorization_code", "refresh_token"] as ["authorization_code", "refresh_token"],
17
+
"response_types": ["code"] as ["code"],
18
+
"token_endpoint_auth_method": "none" as "none",
19
+
"application_type": "web" as "web",
20
+
"dpop_bound_access_tokens": true
21
+
};
22
+
}
23
+
24
+
25
+
export function generateMetadataPlugin({prod, dev}:{prod: string, dev: string}) {
26
+
return {
27
+
name: 'vite-plugin-generate-metadata',
28
+
config(_config: any, { mode }: any) {
29
+
let appOrigin;
30
+
if (mode === 'production') {
31
+
appOrigin = prod
32
+
if (!appOrigin || !appOrigin.startsWith('https://')) {
33
+
throw new Error('VITE_APP_ORIGIN environment variable must be set to a valid HTTPS URL for production build.');
34
+
}
35
+
} else {
36
+
appOrigin = dev;
37
+
}
38
+
39
+
40
+
const metadata = generateClientMetadata(appOrigin);
41
+
const outputPath = path.resolve(process.cwd(), 'public', 'client-metadata.json');
42
+
43
+
fs.writeFileSync(outputPath, JSON.stringify(metadata, null, 2));
44
+
45
+
// /*mass comment*/ console.log(`โ
Generated client-metadata.json for ${appOrigin}`);
46
+
},
47
+
};
48
+
}
+9090
-32
package-lock.json
+9090
-32
package-lock.json
···
7
7
"name": "red-dwarf-tanstack",
8
8
"dependencies": {
9
9
"@atproto/api": "^0.16.6",
10
+
"@atproto/oauth-client-browser": "^0.3.33",
11
+
"@radix-ui/react-dialog": "^1.1.15",
12
+
"@radix-ui/react-dropdown-menu": "^2.1.16",
13
+
"@radix-ui/react-hover-card": "^1.1.15",
14
+
"@radix-ui/react-slider": "^1.3.6",
10
15
"@tailwindcss/vite": "^4.0.6",
16
+
"@tanstack/query-sync-storage-persister": "^5.85.6",
11
17
"@tanstack/react-devtools": "^0.2.2",
18
+
"@tanstack/react-query": "^5.85.6",
19
+
"@tanstack/react-query-persist-client": "^5.85.6",
12
20
"@tanstack/react-router": "^1.130.2",
13
21
"@tanstack/react-router-devtools": "^1.131.5",
14
22
"@tanstack/router-plugin": "^1.121.2",
23
+
"dompurify": "^3.3.0",
24
+
"i": "^0.3.7",
15
25
"idb-keyval": "^6.2.2",
26
+
"jotai": "^2.13.1",
27
+
"npm": "^11.6.2",
28
+
"radix-ui": "^1.4.3",
16
29
"react": "^19.0.0",
17
30
"react-dom": "^19.0.0",
18
31
"react-player": "^3.3.2",
19
-
"tailwindcss": "^4.0.6"
32
+
"tailwindcss": "^4.0.6",
33
+
"tanstack-router-keepalive": "^1.0.0"
20
34
},
21
35
"devDependencies": {
36
+
"@eslint-react/eslint-plugin": "^2.2.1",
37
+
"@iconify-icon/react": "^3.0.1",
38
+
"@iconify-json/material-symbols": "^1.2.42",
39
+
"@iconify-json/mdi": "^1.2.3",
40
+
"@iconify/json": "^2.2.396",
41
+
"@svgr/core": "^8.1.0",
42
+
"@svgr/plugin-jsx": "^8.1.0",
22
43
"@testing-library/dom": "^10.4.0",
23
44
"@testing-library/react": "^16.2.0",
24
45
"@types/node": "^24.3.0",
25
46
"@types/react": "^19.0.8",
26
47
"@types/react-dom": "^19.0.3",
48
+
"@typescript-eslint/eslint-plugin": "^8.46.1",
49
+
"@typescript-eslint/parser": "^8.46.1",
27
50
"@vitejs/plugin-react": "^4.3.4",
51
+
"babel-plugin-react-compiler": "^1.0.0",
52
+
"eslint-plugin-react": "^7.37.5",
53
+
"eslint-plugin-react-hooks": "^7.0.0",
54
+
"eslint-plugin-simple-import-sort": "^12.1.1",
55
+
"eslint-plugin-unused-imports": "^4.2.0",
28
56
"jsdom": "^26.0.0",
29
57
"prettier": "^3.6.2",
30
58
"typescript": "^5.7.2",
59
+
"typescript-eslint": "^8.46.1",
60
+
"unplugin-auto-import": "^20.2.0",
61
+
"unplugin-icons": "^22.4.2",
31
62
"vite": "^6.3.5",
32
63
"vitest": "^3.0.5",
33
64
"web-vitals": "^4.2.4"
···
46
77
"node": ">=6.0.0"
47
78
}
48
79
},
80
+
"node_modules/@antfu/install-pkg": {
81
+
"version": "1.1.0",
82
+
"resolved": "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-1.1.0.tgz",
83
+
"integrity": "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==",
84
+
"dev": true,
85
+
"license": "MIT",
86
+
"dependencies": {
87
+
"package-manager-detector": "^1.3.0",
88
+
"tinyexec": "^1.0.1"
89
+
},
90
+
"funding": {
91
+
"url": "https://github.com/sponsors/antfu"
92
+
}
93
+
},
94
+
"node_modules/@antfu/install-pkg/node_modules/tinyexec": {
95
+
"version": "1.0.1",
96
+
"resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz",
97
+
"integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==",
98
+
"dev": true,
99
+
"license": "MIT"
100
+
},
101
+
"node_modules/@antfu/utils": {
102
+
"version": "9.3.0",
103
+
"resolved": "https://registry.npmjs.org/@antfu/utils/-/utils-9.3.0.tgz",
104
+
"integrity": "sha512-9hFT4RauhcUzqOE4f1+frMKLZrgNog5b06I7VmZQV1BkvwvqrbC8EBZf3L1eEL2AKb6rNKjER0sEvJiSP1FXEA==",
105
+
"dev": true,
106
+
"license": "MIT",
107
+
"funding": {
108
+
"url": "https://github.com/sponsors/antfu"
109
+
}
110
+
},
49
111
"node_modules/@asamuzakjp/css-color": {
50
112
"version": "3.2.0",
51
113
"resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.2.0.tgz",
···
67
129
"dev": true,
68
130
"license": "ISC"
69
131
},
132
+
"node_modules/@atproto-labs/did-resolver": {
133
+
"version": "0.2.2",
134
+
"resolved": "https://registry.npmjs.org/@atproto-labs/did-resolver/-/did-resolver-0.2.2.tgz",
135
+
"integrity": "sha512-ca2B7xR43tVoQ8XxBvha58DXwIH8cIyKQl6lpOKGkPUrJuFoO4iCLlDiSDi2Ueh+yE1rMDPP/qveHdajgDX3WQ==",
136
+
"license": "MIT",
137
+
"dependencies": {
138
+
"@atproto-labs/fetch": "0.2.3",
139
+
"@atproto-labs/pipe": "0.1.1",
140
+
"@atproto-labs/simple-store": "0.3.0",
141
+
"@atproto-labs/simple-store-memory": "0.1.4",
142
+
"@atproto/did": "0.2.1",
143
+
"zod": "^3.23.8"
144
+
}
145
+
},
146
+
"node_modules/@atproto-labs/fetch": {
147
+
"version": "0.2.3",
148
+
"resolved": "https://registry.npmjs.org/@atproto-labs/fetch/-/fetch-0.2.3.tgz",
149
+
"integrity": "sha512-NZtbJOCbxKUFRFKMpamT38PUQMY0hX0p7TG5AEYOPhZKZEP7dHZ1K2s1aB8MdVH0qxmqX7nQleNrrvLf09Zfdw==",
150
+
"license": "MIT",
151
+
"dependencies": {
152
+
"@atproto-labs/pipe": "0.1.1"
153
+
}
154
+
},
155
+
"node_modules/@atproto-labs/handle-resolver": {
156
+
"version": "0.3.2",
157
+
"resolved": "https://registry.npmjs.org/@atproto-labs/handle-resolver/-/handle-resolver-0.3.2.tgz",
158
+
"integrity": "sha512-KIerCzh3qb+zZoqWbIvTlvBY0XPq0r56kwViaJY/LTe/3oPO2JaqlYKS/F4dByWBhHK6YoUOJ0sWrh6PMJl40A==",
159
+
"license": "MIT",
160
+
"dependencies": {
161
+
"@atproto-labs/simple-store": "0.3.0",
162
+
"@atproto-labs/simple-store-memory": "0.1.4",
163
+
"@atproto/did": "0.2.1",
164
+
"zod": "^3.23.8"
165
+
}
166
+
},
167
+
"node_modules/@atproto-labs/identity-resolver": {
168
+
"version": "0.3.2",
169
+
"resolved": "https://registry.npmjs.org/@atproto-labs/identity-resolver/-/identity-resolver-0.3.2.tgz",
170
+
"integrity": "sha512-MYxO9pe0WsFyi5HFdKAwqIqHfiF2kBPoVhAIuH/4PYHzGr799ED47xLhNMxR3ZUYrJm5+TQzWXypGZ0Btw1Ffw==",
171
+
"license": "MIT",
172
+
"dependencies": {
173
+
"@atproto-labs/did-resolver": "0.2.2",
174
+
"@atproto-labs/handle-resolver": "0.3.2"
175
+
}
176
+
},
177
+
"node_modules/@atproto-labs/pipe": {
178
+
"version": "0.1.1",
179
+
"resolved": "https://registry.npmjs.org/@atproto-labs/pipe/-/pipe-0.1.1.tgz",
180
+
"integrity": "sha512-hdNw2oUs2B6BN1lp+32pF7cp8EMKuIN5Qok2Vvv/aOpG/3tNSJ9YkvfI0k6Zd188LeDDYRUpYpxcoFIcGH/FNg==",
181
+
"license": "MIT"
182
+
},
183
+
"node_modules/@atproto-labs/simple-store": {
184
+
"version": "0.3.0",
185
+
"resolved": "https://registry.npmjs.org/@atproto-labs/simple-store/-/simple-store-0.3.0.tgz",
186
+
"integrity": "sha512-nOb6ONKBRJHRlukW1sVawUkBqReLlLx6hT35VS3imaNPwiXDxLnTK7lxw3Lrl9k5yugSBDQAkZAq3MPTEFSUBQ==",
187
+
"license": "MIT"
188
+
},
189
+
"node_modules/@atproto-labs/simple-store-memory": {
190
+
"version": "0.1.4",
191
+
"resolved": "https://registry.npmjs.org/@atproto-labs/simple-store-memory/-/simple-store-memory-0.1.4.tgz",
192
+
"integrity": "sha512-3mKY4dP8I7yKPFj9VKpYyCRzGJOi5CEpOLPlRhoJyLmgs3J4RzDrjn323Oakjz2Aj2JzRU/AIvWRAZVhpYNJHw==",
193
+
"license": "MIT",
194
+
"dependencies": {
195
+
"@atproto-labs/simple-store": "0.3.0",
196
+
"lru-cache": "^10.2.0"
197
+
}
198
+
},
199
+
"node_modules/@atproto-labs/simple-store-memory/node_modules/lru-cache": {
200
+
"version": "10.4.3",
201
+
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
202
+
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
203
+
"license": "ISC"
204
+
},
70
205
"node_modules/@atproto/api": {
71
206
"version": "0.16.6",
72
207
"resolved": "https://registry.npmjs.org/@atproto/api/-/api-0.16.6.tgz",
···
84
219
}
85
220
},
86
221
"node_modules/@atproto/common-web": {
87
-
"version": "0.4.2",
88
-
"resolved": "https://registry.npmjs.org/@atproto/common-web/-/common-web-0.4.2.tgz",
89
-
"integrity": "sha512-vrXwGNoFGogodjQvJDxAeP3QbGtawgZute2ed1XdRO0wMixLk3qewtikZm06H259QDJVu6voKC5mubml+WgQUw==",
222
+
"version": "0.4.3",
223
+
"resolved": "https://registry.npmjs.org/@atproto/common-web/-/common-web-0.4.3.tgz",
224
+
"integrity": "sha512-nRDINmSe4VycJzPo6fP/hEltBcULFxt9Kw7fQk6405FyAWZiTluYHlXOnU7GkQfeUK44OENG1qFTBcmCJ7e8pg==",
90
225
"license": "MIT",
91
226
"dependencies": {
92
227
"graphemer": "^1.4.0",
···
95
230
"zod": "^3.23.8"
96
231
}
97
232
},
233
+
"node_modules/@atproto/did": {
234
+
"version": "0.2.1",
235
+
"resolved": "https://registry.npmjs.org/@atproto/did/-/did-0.2.1.tgz",
236
+
"integrity": "sha512-1i5BTU2GnBaaeYWhxUOnuEKFVq9euT5+dQPFabHpa927BlJ54PmLGyBBaOI7/NbLmN5HWwBa18SBkMpg3jGZRA==",
237
+
"license": "MIT",
238
+
"dependencies": {
239
+
"zod": "^3.23.8"
240
+
}
241
+
},
242
+
"node_modules/@atproto/jwk": {
243
+
"version": "0.6.0",
244
+
"resolved": "https://registry.npmjs.org/@atproto/jwk/-/jwk-0.6.0.tgz",
245
+
"integrity": "sha512-bDoJPvt7TrQVi/rBfBrSSpGykhtIriKxeYCYQTiPRKFfyRhbgpElF0wPXADjIswnbzZdOwbY63az4E/CFVT3Tw==",
246
+
"license": "MIT",
247
+
"dependencies": {
248
+
"multiformats": "^9.9.0",
249
+
"zod": "^3.23.8"
250
+
}
251
+
},
252
+
"node_modules/@atproto/jwk-jose": {
253
+
"version": "0.1.11",
254
+
"resolved": "https://registry.npmjs.org/@atproto/jwk-jose/-/jwk-jose-0.1.11.tgz",
255
+
"integrity": "sha512-i4Fnr2sTBYmMmHXl7NJh8GrCH+tDQEVWrcDMDnV5DjJfkgT17wIqvojIw9SNbSL4Uf0OtfEv6AgG0A+mgh8b5Q==",
256
+
"license": "MIT",
257
+
"dependencies": {
258
+
"@atproto/jwk": "0.6.0",
259
+
"jose": "^5.2.0"
260
+
}
261
+
},
262
+
"node_modules/@atproto/jwk-webcrypto": {
263
+
"version": "0.2.0",
264
+
"resolved": "https://registry.npmjs.org/@atproto/jwk-webcrypto/-/jwk-webcrypto-0.2.0.tgz",
265
+
"integrity": "sha512-UmgRrrEAkWvxwhlwe30UmDOdTEFidlIzBC7C3cCbeJMcBN1x8B3KH+crXrsTqfWQBG58mXgt8wgSK3Kxs2LhFg==",
266
+
"license": "MIT",
267
+
"dependencies": {
268
+
"@atproto/jwk": "0.6.0",
269
+
"@atproto/jwk-jose": "0.1.11",
270
+
"zod": "^3.23.8"
271
+
}
272
+
},
98
273
"node_modules/@atproto/lexicon": {
99
-
"version": "0.5.0",
100
-
"resolved": "https://registry.npmjs.org/@atproto/lexicon/-/lexicon-0.5.0.tgz",
101
-
"integrity": "sha512-3aAzEAy9EAPs3CxznzMhEcqDd7m3vz1eze/ya9/ThbB7yleqJIhz5GY2q76tCCwHPhn5qDDMhlA9kKV6fG23gA==",
274
+
"version": "0.5.1",
275
+
"resolved": "https://registry.npmjs.org/@atproto/lexicon/-/lexicon-0.5.1.tgz",
276
+
"integrity": "sha512-y8AEtYmfgVl4fqFxqXAeGvhesiGkxiy3CWoJIfsFDDdTlZUC8DFnZrYhcqkIop3OlCkkljvpSJi1hbeC1tbi8A==",
102
277
"license": "MIT",
103
278
"dependencies": {
104
-
"@atproto/common-web": "^0.4.2",
279
+
"@atproto/common-web": "^0.4.3",
105
280
"@atproto/syntax": "^0.4.1",
106
281
"iso-datestring-validator": "^2.2.2",
107
282
"multiformats": "^9.9.0",
108
283
"zod": "^3.23.8"
109
284
}
110
285
},
286
+
"node_modules/@atproto/oauth-client": {
287
+
"version": "0.5.7",
288
+
"resolved": "https://registry.npmjs.org/@atproto/oauth-client/-/oauth-client-0.5.7.tgz",
289
+
"integrity": "sha512-pDvbvy9DCxrAJv7bAbBUzWrHZKhFy091HvEMZhr+EyZA6gSCGYmmQJG/coDj0oICSVQeafAZd+IxR0YUCWwmEg==",
290
+
"license": "MIT",
291
+
"dependencies": {
292
+
"@atproto-labs/did-resolver": "0.2.2",
293
+
"@atproto-labs/fetch": "0.2.3",
294
+
"@atproto-labs/handle-resolver": "0.3.2",
295
+
"@atproto-labs/identity-resolver": "0.3.2",
296
+
"@atproto-labs/simple-store": "0.3.0",
297
+
"@atproto-labs/simple-store-memory": "0.1.4",
298
+
"@atproto/did": "0.2.1",
299
+
"@atproto/jwk": "0.6.0",
300
+
"@atproto/oauth-types": "0.4.2",
301
+
"@atproto/xrpc": "0.7.5",
302
+
"core-js": "^3",
303
+
"multiformats": "^9.9.0",
304
+
"zod": "^3.23.8"
305
+
}
306
+
},
307
+
"node_modules/@atproto/oauth-client-browser": {
308
+
"version": "0.3.33",
309
+
"resolved": "https://registry.npmjs.org/@atproto/oauth-client-browser/-/oauth-client-browser-0.3.33.tgz",
310
+
"integrity": "sha512-IvHn/5W3e9GXFUGXQ4MV19E4HXY4zJFgu+eZRWexIXnZl4GwgTH7op8J1SosczdOK1Ngu+LnHE6npcNhUGGd6Q==",
311
+
"license": "MIT",
312
+
"dependencies": {
313
+
"@atproto-labs/did-resolver": "0.2.2",
314
+
"@atproto-labs/handle-resolver": "0.3.2",
315
+
"@atproto-labs/simple-store": "0.3.0",
316
+
"@atproto/did": "0.2.1",
317
+
"@atproto/jwk": "0.6.0",
318
+
"@atproto/jwk-webcrypto": "0.2.0",
319
+
"@atproto/oauth-client": "0.5.7",
320
+
"@atproto/oauth-types": "0.4.2",
321
+
"core-js": "^3"
322
+
}
323
+
},
324
+
"node_modules/@atproto/oauth-types": {
325
+
"version": "0.4.2",
326
+
"resolved": "https://registry.npmjs.org/@atproto/oauth-types/-/oauth-types-0.4.2.tgz",
327
+
"integrity": "sha512-gcfNTyFsPJcYDf79M0iKHykWqzxloscioKoerdIN3MTS3htiNOSgZjm2p8ho7pdrElLzea3qktuhTQI39j1XFQ==",
328
+
"license": "MIT",
329
+
"dependencies": {
330
+
"@atproto/did": "0.2.1",
331
+
"@atproto/jwk": "0.6.0",
332
+
"zod": "^3.23.8"
333
+
}
334
+
},
111
335
"node_modules/@atproto/syntax": {
112
336
"version": "0.4.1",
113
337
"resolved": "https://registry.npmjs.org/@atproto/syntax/-/syntax-0.4.1.tgz",
···
115
339
"license": "MIT"
116
340
},
117
341
"node_modules/@atproto/xrpc": {
118
-
"version": "0.7.4",
119
-
"resolved": "https://registry.npmjs.org/@atproto/xrpc/-/xrpc-0.7.4.tgz",
120
-
"integrity": "sha512-sDi68+QE1XHegTaNAndlX41Gp827pouSzSs8CyAwhrqZdsJUxE3P7TMtrA0z+zAjvxVyvzscRc0TsN/fGUGrhw==",
342
+
"version": "0.7.5",
343
+
"resolved": "https://registry.npmjs.org/@atproto/xrpc/-/xrpc-0.7.5.tgz",
344
+
"integrity": "sha512-MUYNn5d2hv8yVegRL0ccHvTHAVj5JSnW07bkbiaz96UH45lvYNRVwt44z+yYVnb0/mvBzyD3/ZQ55TRGt7fHkA==",
121
345
"license": "MIT",
122
346
"dependencies": {
123
-
"@atproto/lexicon": "^0.5.0",
347
+
"@atproto/lexicon": "^0.5.1",
124
348
"zod": "^3.23.8"
125
349
}
126
350
},
···
1102
1326
"node": ">=18"
1103
1327
}
1104
1328
},
1329
+
"node_modules/@eslint-community/eslint-utils": {
1330
+
"version": "4.9.0",
1331
+
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz",
1332
+
"integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==",
1333
+
"dev": true,
1334
+
"license": "MIT",
1335
+
"dependencies": {
1336
+
"eslint-visitor-keys": "^3.4.3"
1337
+
},
1338
+
"engines": {
1339
+
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
1340
+
},
1341
+
"funding": {
1342
+
"url": "https://opencollective.com/eslint"
1343
+
},
1344
+
"peerDependencies": {
1345
+
"eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
1346
+
}
1347
+
},
1348
+
"node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": {
1349
+
"version": "3.4.3",
1350
+
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
1351
+
"integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
1352
+
"dev": true,
1353
+
"license": "Apache-2.0",
1354
+
"engines": {
1355
+
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
1356
+
},
1357
+
"funding": {
1358
+
"url": "https://opencollective.com/eslint"
1359
+
}
1360
+
},
1361
+
"node_modules/@eslint-community/regexpp": {
1362
+
"version": "4.12.1",
1363
+
"resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz",
1364
+
"integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==",
1365
+
"dev": true,
1366
+
"license": "MIT",
1367
+
"engines": {
1368
+
"node": "^12.0.0 || ^14.0.0 || >=16.0.0"
1369
+
}
1370
+
},
1371
+
"node_modules/@eslint-react/ast": {
1372
+
"version": "2.2.1",
1373
+
"resolved": "https://registry.npmjs.org/@eslint-react/ast/-/ast-2.2.1.tgz",
1374
+
"integrity": "sha512-bjzSAdtTT/gIU0/olh8Kki57Mnadl5BIjJxcA3wqxcAvNwYAt3yl0CM4LRqVqW4kJneslCNqB5UriRJJPSKhuA==",
1375
+
"dev": true,
1376
+
"license": "MIT",
1377
+
"dependencies": {
1378
+
"@eslint-react/eff": "2.2.1",
1379
+
"@typescript-eslint/types": "^8.46.0",
1380
+
"@typescript-eslint/typescript-estree": "^8.46.0",
1381
+
"@typescript-eslint/utils": "^8.46.0",
1382
+
"string-ts": "^2.2.1"
1383
+
},
1384
+
"engines": {
1385
+
"node": ">=20.19.0"
1386
+
}
1387
+
},
1388
+
"node_modules/@eslint-react/core": {
1389
+
"version": "2.2.1",
1390
+
"resolved": "https://registry.npmjs.org/@eslint-react/core/-/core-2.2.1.tgz",
1391
+
"integrity": "sha512-slP1G7sReKgijlDx56SDhgkpS6OjoNCEqItuY6Ayo4viIIYMyQ5LkPJ2BJ5xbBxSklyszQ/yP+8UFDK6uzYChQ==",
1392
+
"dev": true,
1393
+
"license": "MIT",
1394
+
"dependencies": {
1395
+
"@eslint-react/ast": "2.2.1",
1396
+
"@eslint-react/eff": "2.2.1",
1397
+
"@eslint-react/shared": "2.2.1",
1398
+
"@eslint-react/var": "2.2.1",
1399
+
"@typescript-eslint/scope-manager": "^8.46.0",
1400
+
"@typescript-eslint/types": "^8.46.0",
1401
+
"@typescript-eslint/utils": "^8.46.0",
1402
+
"birecord": "^0.1.1",
1403
+
"ts-pattern": "^5.8.0"
1404
+
},
1405
+
"engines": {
1406
+
"node": ">=20.19.0"
1407
+
}
1408
+
},
1409
+
"node_modules/@eslint-react/eff": {
1410
+
"version": "2.2.1",
1411
+
"resolved": "https://registry.npmjs.org/@eslint-react/eff/-/eff-2.2.1.tgz",
1412
+
"integrity": "sha512-u9IJB9O8Jwo4b40CLIoF1HePsOvFLdbRKdCVUBEv2TPihae/ltYRD45mCI0bHLroYUxevC1nvD/cQRfwJPH0zg==",
1413
+
"dev": true,
1414
+
"license": "MIT",
1415
+
"engines": {
1416
+
"node": ">=20.19.0"
1417
+
}
1418
+
},
1419
+
"node_modules/@eslint-react/eslint-plugin": {
1420
+
"version": "2.2.1",
1421
+
"resolved": "https://registry.npmjs.org/@eslint-react/eslint-plugin/-/eslint-plugin-2.2.1.tgz",
1422
+
"integrity": "sha512-BjIwFBvgo2b8d5KaTm3qkqKHMFT0HJmAYUZ6TT5j+C/2lWQK3mANxoPwD9Kq4tuI/zw5dINyKxQp6Kr8yGybHQ==",
1423
+
"dev": true,
1424
+
"license": "MIT",
1425
+
"dependencies": {
1426
+
"@eslint-react/eff": "2.2.1",
1427
+
"@eslint-react/shared": "2.2.1",
1428
+
"@typescript-eslint/scope-manager": "^8.46.0",
1429
+
"@typescript-eslint/type-utils": "^8.46.0",
1430
+
"@typescript-eslint/types": "^8.46.0",
1431
+
"@typescript-eslint/utils": "^8.46.0",
1432
+
"eslint-plugin-react-dom": "2.2.1",
1433
+
"eslint-plugin-react-hooks-extra": "2.2.1",
1434
+
"eslint-plugin-react-naming-convention": "2.2.1",
1435
+
"eslint-plugin-react-web-api": "2.2.1",
1436
+
"eslint-plugin-react-x": "2.2.1",
1437
+
"ts-api-utils": "^2.1.0"
1438
+
},
1439
+
"engines": {
1440
+
"node": ">=20.19.0"
1441
+
},
1442
+
"peerDependencies": {
1443
+
"eslint": "^9.37.0",
1444
+
"typescript": "^5.9.3"
1445
+
}
1446
+
},
1447
+
"node_modules/@eslint-react/shared": {
1448
+
"version": "2.2.1",
1449
+
"resolved": "https://registry.npmjs.org/@eslint-react/shared/-/shared-2.2.1.tgz",
1450
+
"integrity": "sha512-YxYo4Svw2OzV0XDj4HLJKcmB4vtAyQghSE1ZFKN5i90CIbfp/RYBNK6VVrIbxtXu6tAsJ0lSBZiepHfn3i/l8w==",
1451
+
"dev": true,
1452
+
"license": "MIT",
1453
+
"dependencies": {
1454
+
"@eslint-react/eff": "2.2.1",
1455
+
"@typescript-eslint/utils": "^8.46.0",
1456
+
"ts-pattern": "^5.8.0",
1457
+
"zod": "^4.1.12"
1458
+
},
1459
+
"engines": {
1460
+
"node": ">=20.19.0"
1461
+
}
1462
+
},
1463
+
"node_modules/@eslint-react/shared/node_modules/zod": {
1464
+
"version": "4.1.12",
1465
+
"resolved": "https://registry.npmjs.org/zod/-/zod-4.1.12.tgz",
1466
+
"integrity": "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==",
1467
+
"dev": true,
1468
+
"license": "MIT",
1469
+
"funding": {
1470
+
"url": "https://github.com/sponsors/colinhacks"
1471
+
}
1472
+
},
1473
+
"node_modules/@eslint-react/var": {
1474
+
"version": "2.2.1",
1475
+
"resolved": "https://registry.npmjs.org/@eslint-react/var/-/var-2.2.1.tgz",
1476
+
"integrity": "sha512-u5o1z01mNE0F+6DG1sDPnIGDbTaI3s0IOJnGCU4FfcsH7DOf96F4aB1szdJfznJBgVCrcBbyhO9oKKlYZoW0hQ==",
1477
+
"dev": true,
1478
+
"license": "MIT",
1479
+
"dependencies": {
1480
+
"@eslint-react/ast": "2.2.1",
1481
+
"@eslint-react/eff": "2.2.1",
1482
+
"@typescript-eslint/scope-manager": "^8.46.0",
1483
+
"@typescript-eslint/types": "^8.46.0",
1484
+
"@typescript-eslint/utils": "^8.46.0",
1485
+
"ts-pattern": "^5.8.0"
1486
+
},
1487
+
"engines": {
1488
+
"node": ">=20.19.0"
1489
+
}
1490
+
},
1491
+
"node_modules/@eslint/config-array": {
1492
+
"version": "0.21.0",
1493
+
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz",
1494
+
"integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==",
1495
+
"dev": true,
1496
+
"license": "Apache-2.0",
1497
+
"peer": true,
1498
+
"dependencies": {
1499
+
"@eslint/object-schema": "^2.1.6",
1500
+
"debug": "^4.3.1",
1501
+
"minimatch": "^3.1.2"
1502
+
},
1503
+
"engines": {
1504
+
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
1505
+
}
1506
+
},
1507
+
"node_modules/@eslint/config-helpers": {
1508
+
"version": "0.4.0",
1509
+
"resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.0.tgz",
1510
+
"integrity": "sha512-WUFvV4WoIwW8Bv0KeKCIIEgdSiFOsulyN0xrMu+7z43q/hkOLXjvb5u7UC9jDxvRzcrbEmuZBX5yJZz1741jog==",
1511
+
"dev": true,
1512
+
"license": "Apache-2.0",
1513
+
"peer": true,
1514
+
"dependencies": {
1515
+
"@eslint/core": "^0.16.0"
1516
+
},
1517
+
"engines": {
1518
+
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
1519
+
}
1520
+
},
1521
+
"node_modules/@eslint/core": {
1522
+
"version": "0.16.0",
1523
+
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.16.0.tgz",
1524
+
"integrity": "sha512-nmC8/totwobIiFcGkDza3GIKfAw1+hLiYVrh3I1nIomQ8PEr5cxg34jnkmGawul/ep52wGRAcyeDCNtWKSOj4Q==",
1525
+
"dev": true,
1526
+
"license": "Apache-2.0",
1527
+
"peer": true,
1528
+
"dependencies": {
1529
+
"@types/json-schema": "^7.0.15"
1530
+
},
1531
+
"engines": {
1532
+
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
1533
+
}
1534
+
},
1535
+
"node_modules/@eslint/eslintrc": {
1536
+
"version": "3.3.1",
1537
+
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz",
1538
+
"integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==",
1539
+
"dev": true,
1540
+
"license": "MIT",
1541
+
"peer": true,
1542
+
"dependencies": {
1543
+
"ajv": "^6.12.4",
1544
+
"debug": "^4.3.2",
1545
+
"espree": "^10.0.1",
1546
+
"globals": "^14.0.0",
1547
+
"ignore": "^5.2.0",
1548
+
"import-fresh": "^3.2.1",
1549
+
"js-yaml": "^4.1.0",
1550
+
"minimatch": "^3.1.2",
1551
+
"strip-json-comments": "^3.1.1"
1552
+
},
1553
+
"engines": {
1554
+
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
1555
+
},
1556
+
"funding": {
1557
+
"url": "https://opencollective.com/eslint"
1558
+
}
1559
+
},
1560
+
"node_modules/@eslint/js": {
1561
+
"version": "9.37.0",
1562
+
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.37.0.tgz",
1563
+
"integrity": "sha512-jaS+NJ+hximswBG6pjNX0uEJZkrT0zwpVi3BA3vX22aFGjJjmgSTSmPpZCRKmoBL5VY/M6p0xsSJx7rk7sy5gg==",
1564
+
"dev": true,
1565
+
"license": "MIT",
1566
+
"peer": true,
1567
+
"engines": {
1568
+
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
1569
+
},
1570
+
"funding": {
1571
+
"url": "https://eslint.org/donate"
1572
+
}
1573
+
},
1574
+
"node_modules/@eslint/object-schema": {
1575
+
"version": "2.1.6",
1576
+
"resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz",
1577
+
"integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==",
1578
+
"dev": true,
1579
+
"license": "Apache-2.0",
1580
+
"peer": true,
1581
+
"engines": {
1582
+
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
1583
+
}
1584
+
},
1585
+
"node_modules/@eslint/plugin-kit": {
1586
+
"version": "0.4.0",
1587
+
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.0.tgz",
1588
+
"integrity": "sha512-sB5uyeq+dwCWyPi31B2gQlVlo+j5brPlWx4yZBrEaRo/nhdDE8Xke1gsGgtiBdaBTxuTkceLVuVt/pclrasb0A==",
1589
+
"dev": true,
1590
+
"license": "Apache-2.0",
1591
+
"peer": true,
1592
+
"dependencies": {
1593
+
"@eslint/core": "^0.16.0",
1594
+
"levn": "^0.4.1"
1595
+
},
1596
+
"engines": {
1597
+
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
1598
+
}
1599
+
},
1600
+
"node_modules/@floating-ui/core": {
1601
+
"version": "1.7.3",
1602
+
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz",
1603
+
"integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==",
1604
+
"dependencies": {
1605
+
"@floating-ui/utils": "^0.2.10"
1606
+
}
1607
+
},
1608
+
"node_modules/@floating-ui/dom": {
1609
+
"version": "1.7.4",
1610
+
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz",
1611
+
"integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==",
1612
+
"dependencies": {
1613
+
"@floating-ui/core": "^1.7.3",
1614
+
"@floating-ui/utils": "^0.2.10"
1615
+
}
1616
+
},
1617
+
"node_modules/@floating-ui/react-dom": {
1618
+
"version": "2.1.6",
1619
+
"resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.6.tgz",
1620
+
"integrity": "sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==",
1621
+
"dependencies": {
1622
+
"@floating-ui/dom": "^1.7.4"
1623
+
},
1624
+
"peerDependencies": {
1625
+
"react": ">=16.8.0",
1626
+
"react-dom": ">=16.8.0"
1627
+
}
1628
+
},
1629
+
"node_modules/@floating-ui/utils": {
1630
+
"version": "0.2.10",
1631
+
"resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz",
1632
+
"integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ=="
1633
+
},
1634
+
"node_modules/@humanfs/core": {
1635
+
"version": "0.19.1",
1636
+
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
1637
+
"integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==",
1638
+
"dev": true,
1639
+
"license": "Apache-2.0",
1640
+
"peer": true,
1641
+
"engines": {
1642
+
"node": ">=18.18.0"
1643
+
}
1644
+
},
1645
+
"node_modules/@humanfs/node": {
1646
+
"version": "0.16.7",
1647
+
"resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz",
1648
+
"integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==",
1649
+
"dev": true,
1650
+
"license": "Apache-2.0",
1651
+
"peer": true,
1652
+
"dependencies": {
1653
+
"@humanfs/core": "^0.19.1",
1654
+
"@humanwhocodes/retry": "^0.4.0"
1655
+
},
1656
+
"engines": {
1657
+
"node": ">=18.18.0"
1658
+
}
1659
+
},
1660
+
"node_modules/@humanwhocodes/module-importer": {
1661
+
"version": "1.0.1",
1662
+
"resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
1663
+
"integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
1664
+
"dev": true,
1665
+
"license": "Apache-2.0",
1666
+
"peer": true,
1667
+
"engines": {
1668
+
"node": ">=12.22"
1669
+
},
1670
+
"funding": {
1671
+
"type": "github",
1672
+
"url": "https://github.com/sponsors/nzakas"
1673
+
}
1674
+
},
1675
+
"node_modules/@humanwhocodes/retry": {
1676
+
"version": "0.4.3",
1677
+
"resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz",
1678
+
"integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==",
1679
+
"dev": true,
1680
+
"license": "Apache-2.0",
1681
+
"peer": true,
1682
+
"engines": {
1683
+
"node": ">=18.18"
1684
+
},
1685
+
"funding": {
1686
+
"type": "github",
1687
+
"url": "https://github.com/sponsors/nzakas"
1688
+
}
1689
+
},
1690
+
"node_modules/@iconify-icon/react": {
1691
+
"version": "3.0.1",
1692
+
"resolved": "https://registry.npmjs.org/@iconify-icon/react/-/react-3.0.1.tgz",
1693
+
"integrity": "sha512-/4CAVpk8HDyKS78r1G0rZhML7hI6jLxb8kAmjEXsCtuVUDwdGqicGCRg0T14mqeHNImrQPR49MhbuSSS++JlUA==",
1694
+
"dev": true,
1695
+
"license": "MIT",
1696
+
"dependencies": {
1697
+
"iconify-icon": "^3.0.1"
1698
+
},
1699
+
"funding": {
1700
+
"url": "https://github.com/sponsors/cyberalien"
1701
+
},
1702
+
"peerDependencies": {
1703
+
"react": ">=16"
1704
+
}
1705
+
},
1706
+
"node_modules/@iconify-json/material-symbols": {
1707
+
"version": "1.2.42",
1708
+
"resolved": "https://registry.npmjs.org/@iconify-json/material-symbols/-/material-symbols-1.2.42.tgz",
1709
+
"integrity": "sha512-FDRfnQqy8iXaq/swVPFWaHftqP9tk3qDCRhC30s3UZL2j4mvGZk5gVECRXCkZv5jnsAiTpZxGQM8HrMiwE7GtA==",
1710
+
"dev": true,
1711
+
"license": "Apache-2.0",
1712
+
"dependencies": {
1713
+
"@iconify/types": "*"
1714
+
}
1715
+
},
1716
+
"node_modules/@iconify-json/mdi": {
1717
+
"version": "1.2.3",
1718
+
"resolved": "https://registry.npmjs.org/@iconify-json/mdi/-/mdi-1.2.3.tgz",
1719
+
"integrity": "sha512-O3cLwbDOK7NNDf2ihaQOH5F9JglnulNDFV7WprU2dSoZu3h3cWH//h74uQAB87brHmvFVxIOkuBX2sZSzYhScg==",
1720
+
"dev": true,
1721
+
"license": "Apache-2.0",
1722
+
"dependencies": {
1723
+
"@iconify/types": "*"
1724
+
}
1725
+
},
1726
+
"node_modules/@iconify/json": {
1727
+
"version": "2.2.396",
1728
+
"resolved": "https://registry.npmjs.org/@iconify/json/-/json-2.2.396.tgz",
1729
+
"integrity": "sha512-tijg77JFuYIt32S9N8p7La8C0zp9zKZsX6UP8ip5GVB1F6Mp3pZA5Vc5eAquTY50NoDJX58U6z4Qn3d6Wyossg==",
1730
+
"dev": true,
1731
+
"license": "MIT",
1732
+
"dependencies": {
1733
+
"@iconify/types": "*",
1734
+
"pathe": "^2.0.0"
1735
+
}
1736
+
},
1737
+
"node_modules/@iconify/types": {
1738
+
"version": "2.0.0",
1739
+
"resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz",
1740
+
"integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==",
1741
+
"dev": true,
1742
+
"license": "MIT"
1743
+
},
1744
+
"node_modules/@iconify/utils": {
1745
+
"version": "3.0.2",
1746
+
"resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-3.0.2.tgz",
1747
+
"integrity": "sha512-EfJS0rLfVuRuJRn4psJHtK2A9TqVnkxPpHY6lYHiB9+8eSuudsxbwMiavocG45ujOo6FJ+CIRlRnlOGinzkaGQ==",
1748
+
"dev": true,
1749
+
"license": "MIT",
1750
+
"dependencies": {
1751
+
"@antfu/install-pkg": "^1.1.0",
1752
+
"@antfu/utils": "^9.2.0",
1753
+
"@iconify/types": "^2.0.0",
1754
+
"debug": "^4.4.1",
1755
+
"globals": "^15.15.0",
1756
+
"kolorist": "^1.8.0",
1757
+
"local-pkg": "^1.1.1",
1758
+
"mlly": "^1.7.4"
1759
+
}
1760
+
},
1761
+
"node_modules/@iconify/utils/node_modules/globals": {
1762
+
"version": "15.15.0",
1763
+
"resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz",
1764
+
"integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==",
1765
+
"dev": true,
1766
+
"license": "MIT",
1767
+
"engines": {
1768
+
"node": ">=18"
1769
+
},
1770
+
"funding": {
1771
+
"url": "https://github.com/sponsors/sindresorhus"
1772
+
}
1773
+
},
1105
1774
"node_modules/@isaacs/fs-minipass": {
1106
1775
"version": "4.0.1",
1107
1776
"resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
···
1227
1896
"mux-embed": "^5.8.3"
1228
1897
}
1229
1898
},
1899
+
"node_modules/@nodelib/fs.scandir": {
1900
+
"version": "2.1.5",
1901
+
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
1902
+
"integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
1903
+
"dev": true,
1904
+
"license": "MIT",
1905
+
"dependencies": {
1906
+
"@nodelib/fs.stat": "2.0.5",
1907
+
"run-parallel": "^1.1.9"
1908
+
},
1909
+
"engines": {
1910
+
"node": ">= 8"
1911
+
}
1912
+
},
1913
+
"node_modules/@nodelib/fs.stat": {
1914
+
"version": "2.0.5",
1915
+
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
1916
+
"integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
1917
+
"dev": true,
1918
+
"license": "MIT",
1919
+
"engines": {
1920
+
"node": ">= 8"
1921
+
}
1922
+
},
1923
+
"node_modules/@nodelib/fs.walk": {
1924
+
"version": "1.2.8",
1925
+
"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
1926
+
"integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
1927
+
"dev": true,
1928
+
"license": "MIT",
1929
+
"dependencies": {
1930
+
"@nodelib/fs.scandir": "2.1.5",
1931
+
"fastq": "^1.6.0"
1932
+
},
1933
+
"engines": {
1934
+
"node": ">= 8"
1935
+
}
1936
+
},
1937
+
"node_modules/@radix-ui/number": {
1938
+
"version": "1.1.1",
1939
+
"resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz",
1940
+
"integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g=="
1941
+
},
1942
+
"node_modules/@radix-ui/primitive": {
1943
+
"version": "1.1.3",
1944
+
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz",
1945
+
"integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="
1946
+
},
1947
+
"node_modules/@radix-ui/react-accessible-icon": {
1948
+
"version": "1.1.7",
1949
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-accessible-icon/-/react-accessible-icon-1.1.7.tgz",
1950
+
"integrity": "sha512-XM+E4WXl0OqUJFovy6GjmxxFyx9opfCAIUku4dlKRd5YEPqt4kALOkQOp0Of6reHuUkJuiPBEc5k0o4z4lTC8A==",
1951
+
"dependencies": {
1952
+
"@radix-ui/react-visually-hidden": "1.2.3"
1953
+
},
1954
+
"peerDependencies": {
1955
+
"@types/react": "*",
1956
+
"@types/react-dom": "*",
1957
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
1958
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1959
+
},
1960
+
"peerDependenciesMeta": {
1961
+
"@types/react": {
1962
+
"optional": true
1963
+
},
1964
+
"@types/react-dom": {
1965
+
"optional": true
1966
+
}
1967
+
}
1968
+
},
1969
+
"node_modules/@radix-ui/react-accordion": {
1970
+
"version": "1.2.12",
1971
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.12.tgz",
1972
+
"integrity": "sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA==",
1973
+
"dependencies": {
1974
+
"@radix-ui/primitive": "1.1.3",
1975
+
"@radix-ui/react-collapsible": "1.1.12",
1976
+
"@radix-ui/react-collection": "1.1.7",
1977
+
"@radix-ui/react-compose-refs": "1.1.2",
1978
+
"@radix-ui/react-context": "1.1.2",
1979
+
"@radix-ui/react-direction": "1.1.1",
1980
+
"@radix-ui/react-id": "1.1.1",
1981
+
"@radix-ui/react-primitive": "2.1.3",
1982
+
"@radix-ui/react-use-controllable-state": "1.2.2"
1983
+
},
1984
+
"peerDependencies": {
1985
+
"@types/react": "*",
1986
+
"@types/react-dom": "*",
1987
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
1988
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1989
+
},
1990
+
"peerDependenciesMeta": {
1991
+
"@types/react": {
1992
+
"optional": true
1993
+
},
1994
+
"@types/react-dom": {
1995
+
"optional": true
1996
+
}
1997
+
}
1998
+
},
1999
+
"node_modules/@radix-ui/react-alert-dialog": {
2000
+
"version": "1.1.15",
2001
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.1.15.tgz",
2002
+
"integrity": "sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw==",
2003
+
"dependencies": {
2004
+
"@radix-ui/primitive": "1.1.3",
2005
+
"@radix-ui/react-compose-refs": "1.1.2",
2006
+
"@radix-ui/react-context": "1.1.2",
2007
+
"@radix-ui/react-dialog": "1.1.15",
2008
+
"@radix-ui/react-primitive": "2.1.3",
2009
+
"@radix-ui/react-slot": "1.2.3"
2010
+
},
2011
+
"peerDependencies": {
2012
+
"@types/react": "*",
2013
+
"@types/react-dom": "*",
2014
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
2015
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
2016
+
},
2017
+
"peerDependenciesMeta": {
2018
+
"@types/react": {
2019
+
"optional": true
2020
+
},
2021
+
"@types/react-dom": {
2022
+
"optional": true
2023
+
}
2024
+
}
2025
+
},
2026
+
"node_modules/@radix-ui/react-arrow": {
2027
+
"version": "1.1.7",
2028
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz",
2029
+
"integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==",
2030
+
"dependencies": {
2031
+
"@radix-ui/react-primitive": "2.1.3"
2032
+
},
2033
+
"peerDependencies": {
2034
+
"@types/react": "*",
2035
+
"@types/react-dom": "*",
2036
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
2037
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
2038
+
},
2039
+
"peerDependenciesMeta": {
2040
+
"@types/react": {
2041
+
"optional": true
2042
+
},
2043
+
"@types/react-dom": {
2044
+
"optional": true
2045
+
}
2046
+
}
2047
+
},
2048
+
"node_modules/@radix-ui/react-aspect-ratio": {
2049
+
"version": "1.1.7",
2050
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-aspect-ratio/-/react-aspect-ratio-1.1.7.tgz",
2051
+
"integrity": "sha512-Yq6lvO9HQyPwev1onK1daHCHqXVLzPhSVjmsNjCa2Zcxy2f7uJD2itDtxknv6FzAKCwD1qQkeVDmX/cev13n/g==",
2052
+
"dependencies": {
2053
+
"@radix-ui/react-primitive": "2.1.3"
2054
+
},
2055
+
"peerDependencies": {
2056
+
"@types/react": "*",
2057
+
"@types/react-dom": "*",
2058
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
2059
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
2060
+
},
2061
+
"peerDependenciesMeta": {
2062
+
"@types/react": {
2063
+
"optional": true
2064
+
},
2065
+
"@types/react-dom": {
2066
+
"optional": true
2067
+
}
2068
+
}
2069
+
},
2070
+
"node_modules/@radix-ui/react-avatar": {
2071
+
"version": "1.1.10",
2072
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.1.10.tgz",
2073
+
"integrity": "sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog==",
2074
+
"dependencies": {
2075
+
"@radix-ui/react-context": "1.1.2",
2076
+
"@radix-ui/react-primitive": "2.1.3",
2077
+
"@radix-ui/react-use-callback-ref": "1.1.1",
2078
+
"@radix-ui/react-use-is-hydrated": "0.1.0",
2079
+
"@radix-ui/react-use-layout-effect": "1.1.1"
2080
+
},
2081
+
"peerDependencies": {
2082
+
"@types/react": "*",
2083
+
"@types/react-dom": "*",
2084
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
2085
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
2086
+
},
2087
+
"peerDependenciesMeta": {
2088
+
"@types/react": {
2089
+
"optional": true
2090
+
},
2091
+
"@types/react-dom": {
2092
+
"optional": true
2093
+
}
2094
+
}
2095
+
},
2096
+
"node_modules/@radix-ui/react-checkbox": {
2097
+
"version": "1.3.3",
2098
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.3.3.tgz",
2099
+
"integrity": "sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==",
2100
+
"dependencies": {
2101
+
"@radix-ui/primitive": "1.1.3",
2102
+
"@radix-ui/react-compose-refs": "1.1.2",
2103
+
"@radix-ui/react-context": "1.1.2",
2104
+
"@radix-ui/react-presence": "1.1.5",
2105
+
"@radix-ui/react-primitive": "2.1.3",
2106
+
"@radix-ui/react-use-controllable-state": "1.2.2",
2107
+
"@radix-ui/react-use-previous": "1.1.1",
2108
+
"@radix-ui/react-use-size": "1.1.1"
2109
+
},
2110
+
"peerDependencies": {
2111
+
"@types/react": "*",
2112
+
"@types/react-dom": "*",
2113
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
2114
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
2115
+
},
2116
+
"peerDependenciesMeta": {
2117
+
"@types/react": {
2118
+
"optional": true
2119
+
},
2120
+
"@types/react-dom": {
2121
+
"optional": true
2122
+
}
2123
+
}
2124
+
},
2125
+
"node_modules/@radix-ui/react-collapsible": {
2126
+
"version": "1.1.12",
2127
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.12.tgz",
2128
+
"integrity": "sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA==",
2129
+
"dependencies": {
2130
+
"@radix-ui/primitive": "1.1.3",
2131
+
"@radix-ui/react-compose-refs": "1.1.2",
2132
+
"@radix-ui/react-context": "1.1.2",
2133
+
"@radix-ui/react-id": "1.1.1",
2134
+
"@radix-ui/react-presence": "1.1.5",
2135
+
"@radix-ui/react-primitive": "2.1.3",
2136
+
"@radix-ui/react-use-controllable-state": "1.2.2",
2137
+
"@radix-ui/react-use-layout-effect": "1.1.1"
2138
+
},
2139
+
"peerDependencies": {
2140
+
"@types/react": "*",
2141
+
"@types/react-dom": "*",
2142
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
2143
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
2144
+
},
2145
+
"peerDependenciesMeta": {
2146
+
"@types/react": {
2147
+
"optional": true
2148
+
},
2149
+
"@types/react-dom": {
2150
+
"optional": true
2151
+
}
2152
+
}
2153
+
},
2154
+
"node_modules/@radix-ui/react-collection": {
2155
+
"version": "1.1.7",
2156
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz",
2157
+
"integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==",
2158
+
"dependencies": {
2159
+
"@radix-ui/react-compose-refs": "1.1.2",
2160
+
"@radix-ui/react-context": "1.1.2",
2161
+
"@radix-ui/react-primitive": "2.1.3",
2162
+
"@radix-ui/react-slot": "1.2.3"
2163
+
},
2164
+
"peerDependencies": {
2165
+
"@types/react": "*",
2166
+
"@types/react-dom": "*",
2167
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
2168
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
2169
+
},
2170
+
"peerDependenciesMeta": {
2171
+
"@types/react": {
2172
+
"optional": true
2173
+
},
2174
+
"@types/react-dom": {
2175
+
"optional": true
2176
+
}
2177
+
}
2178
+
},
2179
+
"node_modules/@radix-ui/react-compose-refs": {
2180
+
"version": "1.1.2",
2181
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
2182
+
"integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==",
2183
+
"peerDependencies": {
2184
+
"@types/react": "*",
2185
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
2186
+
},
2187
+
"peerDependenciesMeta": {
2188
+
"@types/react": {
2189
+
"optional": true
2190
+
}
2191
+
}
2192
+
},
2193
+
"node_modules/@radix-ui/react-context": {
2194
+
"version": "1.1.2",
2195
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz",
2196
+
"integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==",
2197
+
"peerDependencies": {
2198
+
"@types/react": "*",
2199
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
2200
+
},
2201
+
"peerDependenciesMeta": {
2202
+
"@types/react": {
2203
+
"optional": true
2204
+
}
2205
+
}
2206
+
},
2207
+
"node_modules/@radix-ui/react-context-menu": {
2208
+
"version": "2.2.16",
2209
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-context-menu/-/react-context-menu-2.2.16.tgz",
2210
+
"integrity": "sha512-O8morBEW+HsVG28gYDZPTrT9UUovQUlJue5YO836tiTJhuIWBm/zQHc7j388sHWtdH/xUZurK9olD2+pcqx5ww==",
2211
+
"dependencies": {
2212
+
"@radix-ui/primitive": "1.1.3",
2213
+
"@radix-ui/react-context": "1.1.2",
2214
+
"@radix-ui/react-menu": "2.1.16",
2215
+
"@radix-ui/react-primitive": "2.1.3",
2216
+
"@radix-ui/react-use-callback-ref": "1.1.1",
2217
+
"@radix-ui/react-use-controllable-state": "1.2.2"
2218
+
},
2219
+
"peerDependencies": {
2220
+
"@types/react": "*",
2221
+
"@types/react-dom": "*",
2222
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
2223
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
2224
+
},
2225
+
"peerDependenciesMeta": {
2226
+
"@types/react": {
2227
+
"optional": true
2228
+
},
2229
+
"@types/react-dom": {
2230
+
"optional": true
2231
+
}
2232
+
}
2233
+
},
2234
+
"node_modules/@radix-ui/react-dialog": {
2235
+
"version": "1.1.15",
2236
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz",
2237
+
"integrity": "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==",
2238
+
"dependencies": {
2239
+
"@radix-ui/primitive": "1.1.3",
2240
+
"@radix-ui/react-compose-refs": "1.1.2",
2241
+
"@radix-ui/react-context": "1.1.2",
2242
+
"@radix-ui/react-dismissable-layer": "1.1.11",
2243
+
"@radix-ui/react-focus-guards": "1.1.3",
2244
+
"@radix-ui/react-focus-scope": "1.1.7",
2245
+
"@radix-ui/react-id": "1.1.1",
2246
+
"@radix-ui/react-portal": "1.1.9",
2247
+
"@radix-ui/react-presence": "1.1.5",
2248
+
"@radix-ui/react-primitive": "2.1.3",
2249
+
"@radix-ui/react-slot": "1.2.3",
2250
+
"@radix-ui/react-use-controllable-state": "1.2.2",
2251
+
"aria-hidden": "^1.2.4",
2252
+
"react-remove-scroll": "^2.6.3"
2253
+
},
2254
+
"peerDependencies": {
2255
+
"@types/react": "*",
2256
+
"@types/react-dom": "*",
2257
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
2258
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
2259
+
},
2260
+
"peerDependenciesMeta": {
2261
+
"@types/react": {
2262
+
"optional": true
2263
+
},
2264
+
"@types/react-dom": {
2265
+
"optional": true
2266
+
}
2267
+
}
2268
+
},
2269
+
"node_modules/@radix-ui/react-direction": {
2270
+
"version": "1.1.1",
2271
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz",
2272
+
"integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==",
2273
+
"peerDependencies": {
2274
+
"@types/react": "*",
2275
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
2276
+
},
2277
+
"peerDependenciesMeta": {
2278
+
"@types/react": {
2279
+
"optional": true
2280
+
}
2281
+
}
2282
+
},
2283
+
"node_modules/@radix-ui/react-dismissable-layer": {
2284
+
"version": "1.1.11",
2285
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz",
2286
+
"integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==",
2287
+
"dependencies": {
2288
+
"@radix-ui/primitive": "1.1.3",
2289
+
"@radix-ui/react-compose-refs": "1.1.2",
2290
+
"@radix-ui/react-primitive": "2.1.3",
2291
+
"@radix-ui/react-use-callback-ref": "1.1.1",
2292
+
"@radix-ui/react-use-escape-keydown": "1.1.1"
2293
+
},
2294
+
"peerDependencies": {
2295
+
"@types/react": "*",
2296
+
"@types/react-dom": "*",
2297
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
2298
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
2299
+
},
2300
+
"peerDependenciesMeta": {
2301
+
"@types/react": {
2302
+
"optional": true
2303
+
},
2304
+
"@types/react-dom": {
2305
+
"optional": true
2306
+
}
2307
+
}
2308
+
},
2309
+
"node_modules/@radix-ui/react-dropdown-menu": {
2310
+
"version": "2.1.16",
2311
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.16.tgz",
2312
+
"integrity": "sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==",
2313
+
"dependencies": {
2314
+
"@radix-ui/primitive": "1.1.3",
2315
+
"@radix-ui/react-compose-refs": "1.1.2",
2316
+
"@radix-ui/react-context": "1.1.2",
2317
+
"@radix-ui/react-id": "1.1.1",
2318
+
"@radix-ui/react-menu": "2.1.16",
2319
+
"@radix-ui/react-primitive": "2.1.3",
2320
+
"@radix-ui/react-use-controllable-state": "1.2.2"
2321
+
},
2322
+
"peerDependencies": {
2323
+
"@types/react": "*",
2324
+
"@types/react-dom": "*",
2325
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
2326
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
2327
+
},
2328
+
"peerDependenciesMeta": {
2329
+
"@types/react": {
2330
+
"optional": true
2331
+
},
2332
+
"@types/react-dom": {
2333
+
"optional": true
2334
+
}
2335
+
}
2336
+
},
2337
+
"node_modules/@radix-ui/react-focus-guards": {
2338
+
"version": "1.1.3",
2339
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz",
2340
+
"integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==",
2341
+
"peerDependencies": {
2342
+
"@types/react": "*",
2343
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
2344
+
},
2345
+
"peerDependenciesMeta": {
2346
+
"@types/react": {
2347
+
"optional": true
2348
+
}
2349
+
}
2350
+
},
2351
+
"node_modules/@radix-ui/react-focus-scope": {
2352
+
"version": "1.1.7",
2353
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz",
2354
+
"integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==",
2355
+
"dependencies": {
2356
+
"@radix-ui/react-compose-refs": "1.1.2",
2357
+
"@radix-ui/react-primitive": "2.1.3",
2358
+
"@radix-ui/react-use-callback-ref": "1.1.1"
2359
+
},
2360
+
"peerDependencies": {
2361
+
"@types/react": "*",
2362
+
"@types/react-dom": "*",
2363
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
2364
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
2365
+
},
2366
+
"peerDependenciesMeta": {
2367
+
"@types/react": {
2368
+
"optional": true
2369
+
},
2370
+
"@types/react-dom": {
2371
+
"optional": true
2372
+
}
2373
+
}
2374
+
},
2375
+
"node_modules/@radix-ui/react-form": {
2376
+
"version": "0.1.8",
2377
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-form/-/react-form-0.1.8.tgz",
2378
+
"integrity": "sha512-QM70k4Zwjttifr5a4sZFts9fn8FzHYvQ5PiB19O2HsYibaHSVt9fH9rzB0XZo/YcM+b7t/p7lYCT/F5eOeF5yQ==",
2379
+
"dependencies": {
2380
+
"@radix-ui/primitive": "1.1.3",
2381
+
"@radix-ui/react-compose-refs": "1.1.2",
2382
+
"@radix-ui/react-context": "1.1.2",
2383
+
"@radix-ui/react-id": "1.1.1",
2384
+
"@radix-ui/react-label": "2.1.7",
2385
+
"@radix-ui/react-primitive": "2.1.3"
2386
+
},
2387
+
"peerDependencies": {
2388
+
"@types/react": "*",
2389
+
"@types/react-dom": "*",
2390
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
2391
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
2392
+
},
2393
+
"peerDependenciesMeta": {
2394
+
"@types/react": {
2395
+
"optional": true
2396
+
},
2397
+
"@types/react-dom": {
2398
+
"optional": true
2399
+
}
2400
+
}
2401
+
},
2402
+
"node_modules/@radix-ui/react-hover-card": {
2403
+
"version": "1.1.15",
2404
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-hover-card/-/react-hover-card-1.1.15.tgz",
2405
+
"integrity": "sha512-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg==",
2406
+
"license": "MIT",
2407
+
"dependencies": {
2408
+
"@radix-ui/primitive": "1.1.3",
2409
+
"@radix-ui/react-compose-refs": "1.1.2",
2410
+
"@radix-ui/react-context": "1.1.2",
2411
+
"@radix-ui/react-dismissable-layer": "1.1.11",
2412
+
"@radix-ui/react-popper": "1.2.8",
2413
+
"@radix-ui/react-portal": "1.1.9",
2414
+
"@radix-ui/react-presence": "1.1.5",
2415
+
"@radix-ui/react-primitive": "2.1.3",
2416
+
"@radix-ui/react-use-controllable-state": "1.2.2"
2417
+
},
2418
+
"peerDependencies": {
2419
+
"@types/react": "*",
2420
+
"@types/react-dom": "*",
2421
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
2422
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
2423
+
},
2424
+
"peerDependenciesMeta": {
2425
+
"@types/react": {
2426
+
"optional": true
2427
+
},
2428
+
"@types/react-dom": {
2429
+
"optional": true
2430
+
}
2431
+
}
2432
+
},
2433
+
"node_modules/@radix-ui/react-id": {
2434
+
"version": "1.1.1",
2435
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz",
2436
+
"integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==",
2437
+
"dependencies": {
2438
+
"@radix-ui/react-use-layout-effect": "1.1.1"
2439
+
},
2440
+
"peerDependencies": {
2441
+
"@types/react": "*",
2442
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
2443
+
},
2444
+
"peerDependenciesMeta": {
2445
+
"@types/react": {
2446
+
"optional": true
2447
+
}
2448
+
}
2449
+
},
2450
+
"node_modules/@radix-ui/react-label": {
2451
+
"version": "2.1.7",
2452
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.7.tgz",
2453
+
"integrity": "sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ==",
2454
+
"dependencies": {
2455
+
"@radix-ui/react-primitive": "2.1.3"
2456
+
},
2457
+
"peerDependencies": {
2458
+
"@types/react": "*",
2459
+
"@types/react-dom": "*",
2460
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
2461
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
2462
+
},
2463
+
"peerDependenciesMeta": {
2464
+
"@types/react": {
2465
+
"optional": true
2466
+
},
2467
+
"@types/react-dom": {
2468
+
"optional": true
2469
+
}
2470
+
}
2471
+
},
2472
+
"node_modules/@radix-ui/react-menu": {
2473
+
"version": "2.1.16",
2474
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.16.tgz",
2475
+
"integrity": "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==",
2476
+
"dependencies": {
2477
+
"@radix-ui/primitive": "1.1.3",
2478
+
"@radix-ui/react-collection": "1.1.7",
2479
+
"@radix-ui/react-compose-refs": "1.1.2",
2480
+
"@radix-ui/react-context": "1.1.2",
2481
+
"@radix-ui/react-direction": "1.1.1",
2482
+
"@radix-ui/react-dismissable-layer": "1.1.11",
2483
+
"@radix-ui/react-focus-guards": "1.1.3",
2484
+
"@radix-ui/react-focus-scope": "1.1.7",
2485
+
"@radix-ui/react-id": "1.1.1",
2486
+
"@radix-ui/react-popper": "1.2.8",
2487
+
"@radix-ui/react-portal": "1.1.9",
2488
+
"@radix-ui/react-presence": "1.1.5",
2489
+
"@radix-ui/react-primitive": "2.1.3",
2490
+
"@radix-ui/react-roving-focus": "1.1.11",
2491
+
"@radix-ui/react-slot": "1.2.3",
2492
+
"@radix-ui/react-use-callback-ref": "1.1.1",
2493
+
"aria-hidden": "^1.2.4",
2494
+
"react-remove-scroll": "^2.6.3"
2495
+
},
2496
+
"peerDependencies": {
2497
+
"@types/react": "*",
2498
+
"@types/react-dom": "*",
2499
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
2500
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
2501
+
},
2502
+
"peerDependenciesMeta": {
2503
+
"@types/react": {
2504
+
"optional": true
2505
+
},
2506
+
"@types/react-dom": {
2507
+
"optional": true
2508
+
}
2509
+
}
2510
+
},
2511
+
"node_modules/@radix-ui/react-menubar": {
2512
+
"version": "1.1.16",
2513
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-menubar/-/react-menubar-1.1.16.tgz",
2514
+
"integrity": "sha512-EB1FktTz5xRRi2Er974AUQZWg2yVBb1yjip38/lgwtCVRd3a+maUoGHN/xs9Yv8SY8QwbSEb+YrxGadVWbEutA==",
2515
+
"dependencies": {
2516
+
"@radix-ui/primitive": "1.1.3",
2517
+
"@radix-ui/react-collection": "1.1.7",
2518
+
"@radix-ui/react-compose-refs": "1.1.2",
2519
+
"@radix-ui/react-context": "1.1.2",
2520
+
"@radix-ui/react-direction": "1.1.1",
2521
+
"@radix-ui/react-id": "1.1.1",
2522
+
"@radix-ui/react-menu": "2.1.16",
2523
+
"@radix-ui/react-primitive": "2.1.3",
2524
+
"@radix-ui/react-roving-focus": "1.1.11",
2525
+
"@radix-ui/react-use-controllable-state": "1.2.2"
2526
+
},
2527
+
"peerDependencies": {
2528
+
"@types/react": "*",
2529
+
"@types/react-dom": "*",
2530
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
2531
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
2532
+
},
2533
+
"peerDependenciesMeta": {
2534
+
"@types/react": {
2535
+
"optional": true
2536
+
},
2537
+
"@types/react-dom": {
2538
+
"optional": true
2539
+
}
2540
+
}
2541
+
},
2542
+
"node_modules/@radix-ui/react-navigation-menu": {
2543
+
"version": "1.2.14",
2544
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-navigation-menu/-/react-navigation-menu-1.2.14.tgz",
2545
+
"integrity": "sha512-YB9mTFQvCOAQMHU+C/jVl96WmuWeltyUEpRJJky51huhds5W2FQr1J8D/16sQlf0ozxkPK8uF3niQMdUwZPv5w==",
2546
+
"dependencies": {
2547
+
"@radix-ui/primitive": "1.1.3",
2548
+
"@radix-ui/react-collection": "1.1.7",
2549
+
"@radix-ui/react-compose-refs": "1.1.2",
2550
+
"@radix-ui/react-context": "1.1.2",
2551
+
"@radix-ui/react-direction": "1.1.1",
2552
+
"@radix-ui/react-dismissable-layer": "1.1.11",
2553
+
"@radix-ui/react-id": "1.1.1",
2554
+
"@radix-ui/react-presence": "1.1.5",
2555
+
"@radix-ui/react-primitive": "2.1.3",
2556
+
"@radix-ui/react-use-callback-ref": "1.1.1",
2557
+
"@radix-ui/react-use-controllable-state": "1.2.2",
2558
+
"@radix-ui/react-use-layout-effect": "1.1.1",
2559
+
"@radix-ui/react-use-previous": "1.1.1",
2560
+
"@radix-ui/react-visually-hidden": "1.2.3"
2561
+
},
2562
+
"peerDependencies": {
2563
+
"@types/react": "*",
2564
+
"@types/react-dom": "*",
2565
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
2566
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
2567
+
},
2568
+
"peerDependenciesMeta": {
2569
+
"@types/react": {
2570
+
"optional": true
2571
+
},
2572
+
"@types/react-dom": {
2573
+
"optional": true
2574
+
}
2575
+
}
2576
+
},
2577
+
"node_modules/@radix-ui/react-one-time-password-field": {
2578
+
"version": "0.1.8",
2579
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-one-time-password-field/-/react-one-time-password-field-0.1.8.tgz",
2580
+
"integrity": "sha512-ycS4rbwURavDPVjCb5iS3aG4lURFDILi6sKI/WITUMZ13gMmn/xGjpLoqBAalhJaDk8I3UbCM5GzKHrnzwHbvg==",
2581
+
"dependencies": {
2582
+
"@radix-ui/number": "1.1.1",
2583
+
"@radix-ui/primitive": "1.1.3",
2584
+
"@radix-ui/react-collection": "1.1.7",
2585
+
"@radix-ui/react-compose-refs": "1.1.2",
2586
+
"@radix-ui/react-context": "1.1.2",
2587
+
"@radix-ui/react-direction": "1.1.1",
2588
+
"@radix-ui/react-primitive": "2.1.3",
2589
+
"@radix-ui/react-roving-focus": "1.1.11",
2590
+
"@radix-ui/react-use-controllable-state": "1.2.2",
2591
+
"@radix-ui/react-use-effect-event": "0.0.2",
2592
+
"@radix-ui/react-use-is-hydrated": "0.1.0",
2593
+
"@radix-ui/react-use-layout-effect": "1.1.1"
2594
+
},
2595
+
"peerDependencies": {
2596
+
"@types/react": "*",
2597
+
"@types/react-dom": "*",
2598
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
2599
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
2600
+
},
2601
+
"peerDependenciesMeta": {
2602
+
"@types/react": {
2603
+
"optional": true
2604
+
},
2605
+
"@types/react-dom": {
2606
+
"optional": true
2607
+
}
2608
+
}
2609
+
},
2610
+
"node_modules/@radix-ui/react-password-toggle-field": {
2611
+
"version": "0.1.3",
2612
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-password-toggle-field/-/react-password-toggle-field-0.1.3.tgz",
2613
+
"integrity": "sha512-/UuCrDBWravcaMix4TdT+qlNdVwOM1Nck9kWx/vafXsdfj1ChfhOdfi3cy9SGBpWgTXwYCuboT/oYpJy3clqfw==",
2614
+
"dependencies": {
2615
+
"@radix-ui/primitive": "1.1.3",
2616
+
"@radix-ui/react-compose-refs": "1.1.2",
2617
+
"@radix-ui/react-context": "1.1.2",
2618
+
"@radix-ui/react-id": "1.1.1",
2619
+
"@radix-ui/react-primitive": "2.1.3",
2620
+
"@radix-ui/react-use-controllable-state": "1.2.2",
2621
+
"@radix-ui/react-use-effect-event": "0.0.2",
2622
+
"@radix-ui/react-use-is-hydrated": "0.1.0"
2623
+
},
2624
+
"peerDependencies": {
2625
+
"@types/react": "*",
2626
+
"@types/react-dom": "*",
2627
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
2628
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
2629
+
},
2630
+
"peerDependenciesMeta": {
2631
+
"@types/react": {
2632
+
"optional": true
2633
+
},
2634
+
"@types/react-dom": {
2635
+
"optional": true
2636
+
}
2637
+
}
2638
+
},
2639
+
"node_modules/@radix-ui/react-popover": {
2640
+
"version": "1.1.15",
2641
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.15.tgz",
2642
+
"integrity": "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==",
2643
+
"dependencies": {
2644
+
"@radix-ui/primitive": "1.1.3",
2645
+
"@radix-ui/react-compose-refs": "1.1.2",
2646
+
"@radix-ui/react-context": "1.1.2",
2647
+
"@radix-ui/react-dismissable-layer": "1.1.11",
2648
+
"@radix-ui/react-focus-guards": "1.1.3",
2649
+
"@radix-ui/react-focus-scope": "1.1.7",
2650
+
"@radix-ui/react-id": "1.1.1",
2651
+
"@radix-ui/react-popper": "1.2.8",
2652
+
"@radix-ui/react-portal": "1.1.9",
2653
+
"@radix-ui/react-presence": "1.1.5",
2654
+
"@radix-ui/react-primitive": "2.1.3",
2655
+
"@radix-ui/react-slot": "1.2.3",
2656
+
"@radix-ui/react-use-controllable-state": "1.2.2",
2657
+
"aria-hidden": "^1.2.4",
2658
+
"react-remove-scroll": "^2.6.3"
2659
+
},
2660
+
"peerDependencies": {
2661
+
"@types/react": "*",
2662
+
"@types/react-dom": "*",
2663
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
2664
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
2665
+
},
2666
+
"peerDependenciesMeta": {
2667
+
"@types/react": {
2668
+
"optional": true
2669
+
},
2670
+
"@types/react-dom": {
2671
+
"optional": true
2672
+
}
2673
+
}
2674
+
},
2675
+
"node_modules/@radix-ui/react-popper": {
2676
+
"version": "1.2.8",
2677
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz",
2678
+
"integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==",
2679
+
"dependencies": {
2680
+
"@floating-ui/react-dom": "^2.0.0",
2681
+
"@radix-ui/react-arrow": "1.1.7",
2682
+
"@radix-ui/react-compose-refs": "1.1.2",
2683
+
"@radix-ui/react-context": "1.1.2",
2684
+
"@radix-ui/react-primitive": "2.1.3",
2685
+
"@radix-ui/react-use-callback-ref": "1.1.1",
2686
+
"@radix-ui/react-use-layout-effect": "1.1.1",
2687
+
"@radix-ui/react-use-rect": "1.1.1",
2688
+
"@radix-ui/react-use-size": "1.1.1",
2689
+
"@radix-ui/rect": "1.1.1"
2690
+
},
2691
+
"peerDependencies": {
2692
+
"@types/react": "*",
2693
+
"@types/react-dom": "*",
2694
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
2695
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
2696
+
},
2697
+
"peerDependenciesMeta": {
2698
+
"@types/react": {
2699
+
"optional": true
2700
+
},
2701
+
"@types/react-dom": {
2702
+
"optional": true
2703
+
}
2704
+
}
2705
+
},
2706
+
"node_modules/@radix-ui/react-portal": {
2707
+
"version": "1.1.9",
2708
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz",
2709
+
"integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==",
2710
+
"dependencies": {
2711
+
"@radix-ui/react-primitive": "2.1.3",
2712
+
"@radix-ui/react-use-layout-effect": "1.1.1"
2713
+
},
2714
+
"peerDependencies": {
2715
+
"@types/react": "*",
2716
+
"@types/react-dom": "*",
2717
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
2718
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
2719
+
},
2720
+
"peerDependenciesMeta": {
2721
+
"@types/react": {
2722
+
"optional": true
2723
+
},
2724
+
"@types/react-dom": {
2725
+
"optional": true
2726
+
}
2727
+
}
2728
+
},
2729
+
"node_modules/@radix-ui/react-presence": {
2730
+
"version": "1.1.5",
2731
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz",
2732
+
"integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==",
2733
+
"dependencies": {
2734
+
"@radix-ui/react-compose-refs": "1.1.2",
2735
+
"@radix-ui/react-use-layout-effect": "1.1.1"
2736
+
},
2737
+
"peerDependencies": {
2738
+
"@types/react": "*",
2739
+
"@types/react-dom": "*",
2740
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
2741
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
2742
+
},
2743
+
"peerDependenciesMeta": {
2744
+
"@types/react": {
2745
+
"optional": true
2746
+
},
2747
+
"@types/react-dom": {
2748
+
"optional": true
2749
+
}
2750
+
}
2751
+
},
2752
+
"node_modules/@radix-ui/react-primitive": {
2753
+
"version": "2.1.3",
2754
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz",
2755
+
"integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==",
2756
+
"dependencies": {
2757
+
"@radix-ui/react-slot": "1.2.3"
2758
+
},
2759
+
"peerDependencies": {
2760
+
"@types/react": "*",
2761
+
"@types/react-dom": "*",
2762
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
2763
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
2764
+
},
2765
+
"peerDependenciesMeta": {
2766
+
"@types/react": {
2767
+
"optional": true
2768
+
},
2769
+
"@types/react-dom": {
2770
+
"optional": true
2771
+
}
2772
+
}
2773
+
},
2774
+
"node_modules/@radix-ui/react-progress": {
2775
+
"version": "1.1.7",
2776
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.7.tgz",
2777
+
"integrity": "sha512-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg==",
2778
+
"dependencies": {
2779
+
"@radix-ui/react-context": "1.1.2",
2780
+
"@radix-ui/react-primitive": "2.1.3"
2781
+
},
2782
+
"peerDependencies": {
2783
+
"@types/react": "*",
2784
+
"@types/react-dom": "*",
2785
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
2786
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
2787
+
},
2788
+
"peerDependenciesMeta": {
2789
+
"@types/react": {
2790
+
"optional": true
2791
+
},
2792
+
"@types/react-dom": {
2793
+
"optional": true
2794
+
}
2795
+
}
2796
+
},
2797
+
"node_modules/@radix-ui/react-radio-group": {
2798
+
"version": "1.3.8",
2799
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-radio-group/-/react-radio-group-1.3.8.tgz",
2800
+
"integrity": "sha512-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ==",
2801
+
"dependencies": {
2802
+
"@radix-ui/primitive": "1.1.3",
2803
+
"@radix-ui/react-compose-refs": "1.1.2",
2804
+
"@radix-ui/react-context": "1.1.2",
2805
+
"@radix-ui/react-direction": "1.1.1",
2806
+
"@radix-ui/react-presence": "1.1.5",
2807
+
"@radix-ui/react-primitive": "2.1.3",
2808
+
"@radix-ui/react-roving-focus": "1.1.11",
2809
+
"@radix-ui/react-use-controllable-state": "1.2.2",
2810
+
"@radix-ui/react-use-previous": "1.1.1",
2811
+
"@radix-ui/react-use-size": "1.1.1"
2812
+
},
2813
+
"peerDependencies": {
2814
+
"@types/react": "*",
2815
+
"@types/react-dom": "*",
2816
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
2817
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
2818
+
},
2819
+
"peerDependenciesMeta": {
2820
+
"@types/react": {
2821
+
"optional": true
2822
+
},
2823
+
"@types/react-dom": {
2824
+
"optional": true
2825
+
}
2826
+
}
2827
+
},
2828
+
"node_modules/@radix-ui/react-roving-focus": {
2829
+
"version": "1.1.11",
2830
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz",
2831
+
"integrity": "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==",
2832
+
"dependencies": {
2833
+
"@radix-ui/primitive": "1.1.3",
2834
+
"@radix-ui/react-collection": "1.1.7",
2835
+
"@radix-ui/react-compose-refs": "1.1.2",
2836
+
"@radix-ui/react-context": "1.1.2",
2837
+
"@radix-ui/react-direction": "1.1.1",
2838
+
"@radix-ui/react-id": "1.1.1",
2839
+
"@radix-ui/react-primitive": "2.1.3",
2840
+
"@radix-ui/react-use-callback-ref": "1.1.1",
2841
+
"@radix-ui/react-use-controllable-state": "1.2.2"
2842
+
},
2843
+
"peerDependencies": {
2844
+
"@types/react": "*",
2845
+
"@types/react-dom": "*",
2846
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
2847
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
2848
+
},
2849
+
"peerDependenciesMeta": {
2850
+
"@types/react": {
2851
+
"optional": true
2852
+
},
2853
+
"@types/react-dom": {
2854
+
"optional": true
2855
+
}
2856
+
}
2857
+
},
2858
+
"node_modules/@radix-ui/react-scroll-area": {
2859
+
"version": "1.2.10",
2860
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.10.tgz",
2861
+
"integrity": "sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A==",
2862
+
"dependencies": {
2863
+
"@radix-ui/number": "1.1.1",
2864
+
"@radix-ui/primitive": "1.1.3",
2865
+
"@radix-ui/react-compose-refs": "1.1.2",
2866
+
"@radix-ui/react-context": "1.1.2",
2867
+
"@radix-ui/react-direction": "1.1.1",
2868
+
"@radix-ui/react-presence": "1.1.5",
2869
+
"@radix-ui/react-primitive": "2.1.3",
2870
+
"@radix-ui/react-use-callback-ref": "1.1.1",
2871
+
"@radix-ui/react-use-layout-effect": "1.1.1"
2872
+
},
2873
+
"peerDependencies": {
2874
+
"@types/react": "*",
2875
+
"@types/react-dom": "*",
2876
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
2877
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
2878
+
},
2879
+
"peerDependenciesMeta": {
2880
+
"@types/react": {
2881
+
"optional": true
2882
+
},
2883
+
"@types/react-dom": {
2884
+
"optional": true
2885
+
}
2886
+
}
2887
+
},
2888
+
"node_modules/@radix-ui/react-select": {
2889
+
"version": "2.2.6",
2890
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.6.tgz",
2891
+
"integrity": "sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==",
2892
+
"dependencies": {
2893
+
"@radix-ui/number": "1.1.1",
2894
+
"@radix-ui/primitive": "1.1.3",
2895
+
"@radix-ui/react-collection": "1.1.7",
2896
+
"@radix-ui/react-compose-refs": "1.1.2",
2897
+
"@radix-ui/react-context": "1.1.2",
2898
+
"@radix-ui/react-direction": "1.1.1",
2899
+
"@radix-ui/react-dismissable-layer": "1.1.11",
2900
+
"@radix-ui/react-focus-guards": "1.1.3",
2901
+
"@radix-ui/react-focus-scope": "1.1.7",
2902
+
"@radix-ui/react-id": "1.1.1",
2903
+
"@radix-ui/react-popper": "1.2.8",
2904
+
"@radix-ui/react-portal": "1.1.9",
2905
+
"@radix-ui/react-primitive": "2.1.3",
2906
+
"@radix-ui/react-slot": "1.2.3",
2907
+
"@radix-ui/react-use-callback-ref": "1.1.1",
2908
+
"@radix-ui/react-use-controllable-state": "1.2.2",
2909
+
"@radix-ui/react-use-layout-effect": "1.1.1",
2910
+
"@radix-ui/react-use-previous": "1.1.1",
2911
+
"@radix-ui/react-visually-hidden": "1.2.3",
2912
+
"aria-hidden": "^1.2.4",
2913
+
"react-remove-scroll": "^2.6.3"
2914
+
},
2915
+
"peerDependencies": {
2916
+
"@types/react": "*",
2917
+
"@types/react-dom": "*",
2918
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
2919
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
2920
+
},
2921
+
"peerDependenciesMeta": {
2922
+
"@types/react": {
2923
+
"optional": true
2924
+
},
2925
+
"@types/react-dom": {
2926
+
"optional": true
2927
+
}
2928
+
}
2929
+
},
2930
+
"node_modules/@radix-ui/react-separator": {
2931
+
"version": "1.1.7",
2932
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.7.tgz",
2933
+
"integrity": "sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA==",
2934
+
"dependencies": {
2935
+
"@radix-ui/react-primitive": "2.1.3"
2936
+
},
2937
+
"peerDependencies": {
2938
+
"@types/react": "*",
2939
+
"@types/react-dom": "*",
2940
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
2941
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
2942
+
},
2943
+
"peerDependenciesMeta": {
2944
+
"@types/react": {
2945
+
"optional": true
2946
+
},
2947
+
"@types/react-dom": {
2948
+
"optional": true
2949
+
}
2950
+
}
2951
+
},
2952
+
"node_modules/@radix-ui/react-slider": {
2953
+
"version": "1.3.6",
2954
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-slider/-/react-slider-1.3.6.tgz",
2955
+
"integrity": "sha512-JPYb1GuM1bxfjMRlNLE+BcmBC8onfCi60Blk7OBqi2MLTFdS+8401U4uFjnwkOr49BLmXxLC6JHkvAsx5OJvHw==",
2956
+
"dependencies": {
2957
+
"@radix-ui/number": "1.1.1",
2958
+
"@radix-ui/primitive": "1.1.3",
2959
+
"@radix-ui/react-collection": "1.1.7",
2960
+
"@radix-ui/react-compose-refs": "1.1.2",
2961
+
"@radix-ui/react-context": "1.1.2",
2962
+
"@radix-ui/react-direction": "1.1.1",
2963
+
"@radix-ui/react-primitive": "2.1.3",
2964
+
"@radix-ui/react-use-controllable-state": "1.2.2",
2965
+
"@radix-ui/react-use-layout-effect": "1.1.1",
2966
+
"@radix-ui/react-use-previous": "1.1.1",
2967
+
"@radix-ui/react-use-size": "1.1.1"
2968
+
},
2969
+
"peerDependencies": {
2970
+
"@types/react": "*",
2971
+
"@types/react-dom": "*",
2972
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
2973
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
2974
+
},
2975
+
"peerDependenciesMeta": {
2976
+
"@types/react": {
2977
+
"optional": true
2978
+
},
2979
+
"@types/react-dom": {
2980
+
"optional": true
2981
+
}
2982
+
}
2983
+
},
2984
+
"node_modules/@radix-ui/react-slot": {
2985
+
"version": "1.2.3",
2986
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
2987
+
"integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==",
2988
+
"dependencies": {
2989
+
"@radix-ui/react-compose-refs": "1.1.2"
2990
+
},
2991
+
"peerDependencies": {
2992
+
"@types/react": "*",
2993
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
2994
+
},
2995
+
"peerDependenciesMeta": {
2996
+
"@types/react": {
2997
+
"optional": true
2998
+
}
2999
+
}
3000
+
},
3001
+
"node_modules/@radix-ui/react-switch": {
3002
+
"version": "1.2.6",
3003
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.2.6.tgz",
3004
+
"integrity": "sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==",
3005
+
"dependencies": {
3006
+
"@radix-ui/primitive": "1.1.3",
3007
+
"@radix-ui/react-compose-refs": "1.1.2",
3008
+
"@radix-ui/react-context": "1.1.2",
3009
+
"@radix-ui/react-primitive": "2.1.3",
3010
+
"@radix-ui/react-use-controllable-state": "1.2.2",
3011
+
"@radix-ui/react-use-previous": "1.1.1",
3012
+
"@radix-ui/react-use-size": "1.1.1"
3013
+
},
3014
+
"peerDependencies": {
3015
+
"@types/react": "*",
3016
+
"@types/react-dom": "*",
3017
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
3018
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
3019
+
},
3020
+
"peerDependenciesMeta": {
3021
+
"@types/react": {
3022
+
"optional": true
3023
+
},
3024
+
"@types/react-dom": {
3025
+
"optional": true
3026
+
}
3027
+
}
3028
+
},
3029
+
"node_modules/@radix-ui/react-tabs": {
3030
+
"version": "1.1.13",
3031
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.13.tgz",
3032
+
"integrity": "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==",
3033
+
"dependencies": {
3034
+
"@radix-ui/primitive": "1.1.3",
3035
+
"@radix-ui/react-context": "1.1.2",
3036
+
"@radix-ui/react-direction": "1.1.1",
3037
+
"@radix-ui/react-id": "1.1.1",
3038
+
"@radix-ui/react-presence": "1.1.5",
3039
+
"@radix-ui/react-primitive": "2.1.3",
3040
+
"@radix-ui/react-roving-focus": "1.1.11",
3041
+
"@radix-ui/react-use-controllable-state": "1.2.2"
3042
+
},
3043
+
"peerDependencies": {
3044
+
"@types/react": "*",
3045
+
"@types/react-dom": "*",
3046
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
3047
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
3048
+
},
3049
+
"peerDependenciesMeta": {
3050
+
"@types/react": {
3051
+
"optional": true
3052
+
},
3053
+
"@types/react-dom": {
3054
+
"optional": true
3055
+
}
3056
+
}
3057
+
},
3058
+
"node_modules/@radix-ui/react-toast": {
3059
+
"version": "1.2.15",
3060
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.2.15.tgz",
3061
+
"integrity": "sha512-3OSz3TacUWy4WtOXV38DggwxoqJK4+eDkNMl5Z/MJZaoUPaP4/9lf81xXMe1I2ReTAptverZUpbPY4wWwWyL5g==",
3062
+
"dependencies": {
3063
+
"@radix-ui/primitive": "1.1.3",
3064
+
"@radix-ui/react-collection": "1.1.7",
3065
+
"@radix-ui/react-compose-refs": "1.1.2",
3066
+
"@radix-ui/react-context": "1.1.2",
3067
+
"@radix-ui/react-dismissable-layer": "1.1.11",
3068
+
"@radix-ui/react-portal": "1.1.9",
3069
+
"@radix-ui/react-presence": "1.1.5",
3070
+
"@radix-ui/react-primitive": "2.1.3",
3071
+
"@radix-ui/react-use-callback-ref": "1.1.1",
3072
+
"@radix-ui/react-use-controllable-state": "1.2.2",
3073
+
"@radix-ui/react-use-layout-effect": "1.1.1",
3074
+
"@radix-ui/react-visually-hidden": "1.2.3"
3075
+
},
3076
+
"peerDependencies": {
3077
+
"@types/react": "*",
3078
+
"@types/react-dom": "*",
3079
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
3080
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
3081
+
},
3082
+
"peerDependenciesMeta": {
3083
+
"@types/react": {
3084
+
"optional": true
3085
+
},
3086
+
"@types/react-dom": {
3087
+
"optional": true
3088
+
}
3089
+
}
3090
+
},
3091
+
"node_modules/@radix-ui/react-toggle": {
3092
+
"version": "1.1.10",
3093
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.1.10.tgz",
3094
+
"integrity": "sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ==",
3095
+
"dependencies": {
3096
+
"@radix-ui/primitive": "1.1.3",
3097
+
"@radix-ui/react-primitive": "2.1.3",
3098
+
"@radix-ui/react-use-controllable-state": "1.2.2"
3099
+
},
3100
+
"peerDependencies": {
3101
+
"@types/react": "*",
3102
+
"@types/react-dom": "*",
3103
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
3104
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
3105
+
},
3106
+
"peerDependenciesMeta": {
3107
+
"@types/react": {
3108
+
"optional": true
3109
+
},
3110
+
"@types/react-dom": {
3111
+
"optional": true
3112
+
}
3113
+
}
3114
+
},
3115
+
"node_modules/@radix-ui/react-toggle-group": {
3116
+
"version": "1.1.11",
3117
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-toggle-group/-/react-toggle-group-1.1.11.tgz",
3118
+
"integrity": "sha512-5umnS0T8JQzQT6HbPyO7Hh9dgd82NmS36DQr+X/YJ9ctFNCiiQd6IJAYYZ33LUwm8M+taCz5t2ui29fHZc4Y6Q==",
3119
+
"dependencies": {
3120
+
"@radix-ui/primitive": "1.1.3",
3121
+
"@radix-ui/react-context": "1.1.2",
3122
+
"@radix-ui/react-direction": "1.1.1",
3123
+
"@radix-ui/react-primitive": "2.1.3",
3124
+
"@radix-ui/react-roving-focus": "1.1.11",
3125
+
"@radix-ui/react-toggle": "1.1.10",
3126
+
"@radix-ui/react-use-controllable-state": "1.2.2"
3127
+
},
3128
+
"peerDependencies": {
3129
+
"@types/react": "*",
3130
+
"@types/react-dom": "*",
3131
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
3132
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
3133
+
},
3134
+
"peerDependenciesMeta": {
3135
+
"@types/react": {
3136
+
"optional": true
3137
+
},
3138
+
"@types/react-dom": {
3139
+
"optional": true
3140
+
}
3141
+
}
3142
+
},
3143
+
"node_modules/@radix-ui/react-toolbar": {
3144
+
"version": "1.1.11",
3145
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-toolbar/-/react-toolbar-1.1.11.tgz",
3146
+
"integrity": "sha512-4ol06/1bLoFu1nwUqzdD4Y5RZ9oDdKeiHIsntug54Hcr1pgaHiPqHFEaXI1IFP/EsOfROQZ8Mig9VTIRza6Tjg==",
3147
+
"dependencies": {
3148
+
"@radix-ui/primitive": "1.1.3",
3149
+
"@radix-ui/react-context": "1.1.2",
3150
+
"@radix-ui/react-direction": "1.1.1",
3151
+
"@radix-ui/react-primitive": "2.1.3",
3152
+
"@radix-ui/react-roving-focus": "1.1.11",
3153
+
"@radix-ui/react-separator": "1.1.7",
3154
+
"@radix-ui/react-toggle-group": "1.1.11"
3155
+
},
3156
+
"peerDependencies": {
3157
+
"@types/react": "*",
3158
+
"@types/react-dom": "*",
3159
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
3160
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
3161
+
},
3162
+
"peerDependenciesMeta": {
3163
+
"@types/react": {
3164
+
"optional": true
3165
+
},
3166
+
"@types/react-dom": {
3167
+
"optional": true
3168
+
}
3169
+
}
3170
+
},
3171
+
"node_modules/@radix-ui/react-tooltip": {
3172
+
"version": "1.2.8",
3173
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.8.tgz",
3174
+
"integrity": "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==",
3175
+
"dependencies": {
3176
+
"@radix-ui/primitive": "1.1.3",
3177
+
"@radix-ui/react-compose-refs": "1.1.2",
3178
+
"@radix-ui/react-context": "1.1.2",
3179
+
"@radix-ui/react-dismissable-layer": "1.1.11",
3180
+
"@radix-ui/react-id": "1.1.1",
3181
+
"@radix-ui/react-popper": "1.2.8",
3182
+
"@radix-ui/react-portal": "1.1.9",
3183
+
"@radix-ui/react-presence": "1.1.5",
3184
+
"@radix-ui/react-primitive": "2.1.3",
3185
+
"@radix-ui/react-slot": "1.2.3",
3186
+
"@radix-ui/react-use-controllable-state": "1.2.2",
3187
+
"@radix-ui/react-visually-hidden": "1.2.3"
3188
+
},
3189
+
"peerDependencies": {
3190
+
"@types/react": "*",
3191
+
"@types/react-dom": "*",
3192
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
3193
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
3194
+
},
3195
+
"peerDependenciesMeta": {
3196
+
"@types/react": {
3197
+
"optional": true
3198
+
},
3199
+
"@types/react-dom": {
3200
+
"optional": true
3201
+
}
3202
+
}
3203
+
},
3204
+
"node_modules/@radix-ui/react-use-callback-ref": {
3205
+
"version": "1.1.1",
3206
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz",
3207
+
"integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==",
3208
+
"peerDependencies": {
3209
+
"@types/react": "*",
3210
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
3211
+
},
3212
+
"peerDependenciesMeta": {
3213
+
"@types/react": {
3214
+
"optional": true
3215
+
}
3216
+
}
3217
+
},
3218
+
"node_modules/@radix-ui/react-use-controllable-state": {
3219
+
"version": "1.2.2",
3220
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz",
3221
+
"integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==",
3222
+
"dependencies": {
3223
+
"@radix-ui/react-use-effect-event": "0.0.2",
3224
+
"@radix-ui/react-use-layout-effect": "1.1.1"
3225
+
},
3226
+
"peerDependencies": {
3227
+
"@types/react": "*",
3228
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
3229
+
},
3230
+
"peerDependenciesMeta": {
3231
+
"@types/react": {
3232
+
"optional": true
3233
+
}
3234
+
}
3235
+
},
3236
+
"node_modules/@radix-ui/react-use-effect-event": {
3237
+
"version": "0.0.2",
3238
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz",
3239
+
"integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==",
3240
+
"dependencies": {
3241
+
"@radix-ui/react-use-layout-effect": "1.1.1"
3242
+
},
3243
+
"peerDependencies": {
3244
+
"@types/react": "*",
3245
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
3246
+
},
3247
+
"peerDependenciesMeta": {
3248
+
"@types/react": {
3249
+
"optional": true
3250
+
}
3251
+
}
3252
+
},
3253
+
"node_modules/@radix-ui/react-use-escape-keydown": {
3254
+
"version": "1.1.1",
3255
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz",
3256
+
"integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==",
3257
+
"dependencies": {
3258
+
"@radix-ui/react-use-callback-ref": "1.1.1"
3259
+
},
3260
+
"peerDependencies": {
3261
+
"@types/react": "*",
3262
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
3263
+
},
3264
+
"peerDependenciesMeta": {
3265
+
"@types/react": {
3266
+
"optional": true
3267
+
}
3268
+
}
3269
+
},
3270
+
"node_modules/@radix-ui/react-use-is-hydrated": {
3271
+
"version": "0.1.0",
3272
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.0.tgz",
3273
+
"integrity": "sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==",
3274
+
"dependencies": {
3275
+
"use-sync-external-store": "^1.5.0"
3276
+
},
3277
+
"peerDependencies": {
3278
+
"@types/react": "*",
3279
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
3280
+
},
3281
+
"peerDependenciesMeta": {
3282
+
"@types/react": {
3283
+
"optional": true
3284
+
}
3285
+
}
3286
+
},
3287
+
"node_modules/@radix-ui/react-use-layout-effect": {
3288
+
"version": "1.1.1",
3289
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz",
3290
+
"integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==",
3291
+
"peerDependencies": {
3292
+
"@types/react": "*",
3293
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
3294
+
},
3295
+
"peerDependenciesMeta": {
3296
+
"@types/react": {
3297
+
"optional": true
3298
+
}
3299
+
}
3300
+
},
3301
+
"node_modules/@radix-ui/react-use-previous": {
3302
+
"version": "1.1.1",
3303
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz",
3304
+
"integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==",
3305
+
"peerDependencies": {
3306
+
"@types/react": "*",
3307
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
3308
+
},
3309
+
"peerDependenciesMeta": {
3310
+
"@types/react": {
3311
+
"optional": true
3312
+
}
3313
+
}
3314
+
},
3315
+
"node_modules/@radix-ui/react-use-rect": {
3316
+
"version": "1.1.1",
3317
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz",
3318
+
"integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==",
3319
+
"dependencies": {
3320
+
"@radix-ui/rect": "1.1.1"
3321
+
},
3322
+
"peerDependencies": {
3323
+
"@types/react": "*",
3324
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
3325
+
},
3326
+
"peerDependenciesMeta": {
3327
+
"@types/react": {
3328
+
"optional": true
3329
+
}
3330
+
}
3331
+
},
3332
+
"node_modules/@radix-ui/react-use-size": {
3333
+
"version": "1.1.1",
3334
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz",
3335
+
"integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==",
3336
+
"dependencies": {
3337
+
"@radix-ui/react-use-layout-effect": "1.1.1"
3338
+
},
3339
+
"peerDependencies": {
3340
+
"@types/react": "*",
3341
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
3342
+
},
3343
+
"peerDependenciesMeta": {
3344
+
"@types/react": {
3345
+
"optional": true
3346
+
}
3347
+
}
3348
+
},
3349
+
"node_modules/@radix-ui/react-visually-hidden": {
3350
+
"version": "1.2.3",
3351
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz",
3352
+
"integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==",
3353
+
"dependencies": {
3354
+
"@radix-ui/react-primitive": "2.1.3"
3355
+
},
3356
+
"peerDependencies": {
3357
+
"@types/react": "*",
3358
+
"@types/react-dom": "*",
3359
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
3360
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
3361
+
},
3362
+
"peerDependenciesMeta": {
3363
+
"@types/react": {
3364
+
"optional": true
3365
+
},
3366
+
"@types/react-dom": {
3367
+
"optional": true
3368
+
}
3369
+
}
3370
+
},
3371
+
"node_modules/@radix-ui/rect": {
3372
+
"version": "1.1.1",
3373
+
"resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz",
3374
+
"integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw=="
3375
+
},
1230
3376
"node_modules/@rolldown/pluginutils": {
1231
3377
"version": "1.0.0-beta.27",
1232
3378
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz",
···
1541
3687
"solid-js": "^1.6.12"
1542
3688
}
1543
3689
},
3690
+
"node_modules/@svgr/babel-plugin-add-jsx-attribute": {
3691
+
"version": "8.0.0",
3692
+
"resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz",
3693
+
"integrity": "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==",
3694
+
"dev": true,
3695
+
"license": "MIT",
3696
+
"engines": {
3697
+
"node": ">=14"
3698
+
},
3699
+
"funding": {
3700
+
"type": "github",
3701
+
"url": "https://github.com/sponsors/gregberge"
3702
+
},
3703
+
"peerDependencies": {
3704
+
"@babel/core": "^7.0.0-0"
3705
+
}
3706
+
},
3707
+
"node_modules/@svgr/babel-plugin-remove-jsx-attribute": {
3708
+
"version": "8.0.0",
3709
+
"resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz",
3710
+
"integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==",
3711
+
"dev": true,
3712
+
"license": "MIT",
3713
+
"engines": {
3714
+
"node": ">=14"
3715
+
},
3716
+
"funding": {
3717
+
"type": "github",
3718
+
"url": "https://github.com/sponsors/gregberge"
3719
+
},
3720
+
"peerDependencies": {
3721
+
"@babel/core": "^7.0.0-0"
3722
+
}
3723
+
},
3724
+
"node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": {
3725
+
"version": "8.0.0",
3726
+
"resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz",
3727
+
"integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==",
3728
+
"dev": true,
3729
+
"license": "MIT",
3730
+
"engines": {
3731
+
"node": ">=14"
3732
+
},
3733
+
"funding": {
3734
+
"type": "github",
3735
+
"url": "https://github.com/sponsors/gregberge"
3736
+
},
3737
+
"peerDependencies": {
3738
+
"@babel/core": "^7.0.0-0"
3739
+
}
3740
+
},
3741
+
"node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": {
3742
+
"version": "8.0.0",
3743
+
"resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz",
3744
+
"integrity": "sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==",
3745
+
"dev": true,
3746
+
"license": "MIT",
3747
+
"engines": {
3748
+
"node": ">=14"
3749
+
},
3750
+
"funding": {
3751
+
"type": "github",
3752
+
"url": "https://github.com/sponsors/gregberge"
3753
+
},
3754
+
"peerDependencies": {
3755
+
"@babel/core": "^7.0.0-0"
3756
+
}
3757
+
},
3758
+
"node_modules/@svgr/babel-plugin-svg-dynamic-title": {
3759
+
"version": "8.0.0",
3760
+
"resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz",
3761
+
"integrity": "sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==",
3762
+
"dev": true,
3763
+
"license": "MIT",
3764
+
"engines": {
3765
+
"node": ">=14"
3766
+
},
3767
+
"funding": {
3768
+
"type": "github",
3769
+
"url": "https://github.com/sponsors/gregberge"
3770
+
},
3771
+
"peerDependencies": {
3772
+
"@babel/core": "^7.0.0-0"
3773
+
}
3774
+
},
3775
+
"node_modules/@svgr/babel-plugin-svg-em-dimensions": {
3776
+
"version": "8.0.0",
3777
+
"resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz",
3778
+
"integrity": "sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==",
3779
+
"dev": true,
3780
+
"license": "MIT",
3781
+
"engines": {
3782
+
"node": ">=14"
3783
+
},
3784
+
"funding": {
3785
+
"type": "github",
3786
+
"url": "https://github.com/sponsors/gregberge"
3787
+
},
3788
+
"peerDependencies": {
3789
+
"@babel/core": "^7.0.0-0"
3790
+
}
3791
+
},
3792
+
"node_modules/@svgr/babel-plugin-transform-react-native-svg": {
3793
+
"version": "8.1.0",
3794
+
"resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.1.0.tgz",
3795
+
"integrity": "sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==",
3796
+
"dev": true,
3797
+
"license": "MIT",
3798
+
"engines": {
3799
+
"node": ">=14"
3800
+
},
3801
+
"funding": {
3802
+
"type": "github",
3803
+
"url": "https://github.com/sponsors/gregberge"
3804
+
},
3805
+
"peerDependencies": {
3806
+
"@babel/core": "^7.0.0-0"
3807
+
}
3808
+
},
3809
+
"node_modules/@svgr/babel-plugin-transform-svg-component": {
3810
+
"version": "8.0.0",
3811
+
"resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz",
3812
+
"integrity": "sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==",
3813
+
"dev": true,
3814
+
"license": "MIT",
3815
+
"engines": {
3816
+
"node": ">=12"
3817
+
},
3818
+
"funding": {
3819
+
"type": "github",
3820
+
"url": "https://github.com/sponsors/gregberge"
3821
+
},
3822
+
"peerDependencies": {
3823
+
"@babel/core": "^7.0.0-0"
3824
+
}
3825
+
},
3826
+
"node_modules/@svgr/babel-preset": {
3827
+
"version": "8.1.0",
3828
+
"resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-8.1.0.tgz",
3829
+
"integrity": "sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==",
3830
+
"dev": true,
3831
+
"license": "MIT",
3832
+
"dependencies": {
3833
+
"@svgr/babel-plugin-add-jsx-attribute": "8.0.0",
3834
+
"@svgr/babel-plugin-remove-jsx-attribute": "8.0.0",
3835
+
"@svgr/babel-plugin-remove-jsx-empty-expression": "8.0.0",
3836
+
"@svgr/babel-plugin-replace-jsx-attribute-value": "8.0.0",
3837
+
"@svgr/babel-plugin-svg-dynamic-title": "8.0.0",
3838
+
"@svgr/babel-plugin-svg-em-dimensions": "8.0.0",
3839
+
"@svgr/babel-plugin-transform-react-native-svg": "8.1.0",
3840
+
"@svgr/babel-plugin-transform-svg-component": "8.0.0"
3841
+
},
3842
+
"engines": {
3843
+
"node": ">=14"
3844
+
},
3845
+
"funding": {
3846
+
"type": "github",
3847
+
"url": "https://github.com/sponsors/gregberge"
3848
+
},
3849
+
"peerDependencies": {
3850
+
"@babel/core": "^7.0.0-0"
3851
+
}
3852
+
},
3853
+
"node_modules/@svgr/core": {
3854
+
"version": "8.1.0",
3855
+
"resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz",
3856
+
"integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==",
3857
+
"dev": true,
3858
+
"license": "MIT",
3859
+
"dependencies": {
3860
+
"@babel/core": "^7.21.3",
3861
+
"@svgr/babel-preset": "8.1.0",
3862
+
"camelcase": "^6.2.0",
3863
+
"cosmiconfig": "^8.1.3",
3864
+
"snake-case": "^3.0.4"
3865
+
},
3866
+
"engines": {
3867
+
"node": ">=14"
3868
+
},
3869
+
"funding": {
3870
+
"type": "github",
3871
+
"url": "https://github.com/sponsors/gregberge"
3872
+
}
3873
+
},
3874
+
"node_modules/@svgr/hast-util-to-babel-ast": {
3875
+
"version": "8.0.0",
3876
+
"resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz",
3877
+
"integrity": "sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==",
3878
+
"dev": true,
3879
+
"license": "MIT",
3880
+
"dependencies": {
3881
+
"@babel/types": "^7.21.3",
3882
+
"entities": "^4.4.0"
3883
+
},
3884
+
"engines": {
3885
+
"node": ">=14"
3886
+
},
3887
+
"funding": {
3888
+
"type": "github",
3889
+
"url": "https://github.com/sponsors/gregberge"
3890
+
}
3891
+
},
3892
+
"node_modules/@svgr/hast-util-to-babel-ast/node_modules/entities": {
3893
+
"version": "4.5.0",
3894
+
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
3895
+
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
3896
+
"dev": true,
3897
+
"license": "BSD-2-Clause",
3898
+
"engines": {
3899
+
"node": ">=0.12"
3900
+
},
3901
+
"funding": {
3902
+
"url": "https://github.com/fb55/entities?sponsor=1"
3903
+
}
3904
+
},
3905
+
"node_modules/@svgr/plugin-jsx": {
3906
+
"version": "8.1.0",
3907
+
"resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz",
3908
+
"integrity": "sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==",
3909
+
"dev": true,
3910
+
"license": "MIT",
3911
+
"dependencies": {
3912
+
"@babel/core": "^7.21.3",
3913
+
"@svgr/babel-preset": "8.1.0",
3914
+
"@svgr/hast-util-to-babel-ast": "8.0.0",
3915
+
"svg-parser": "^2.0.4"
3916
+
},
3917
+
"engines": {
3918
+
"node": ">=14"
3919
+
},
3920
+
"funding": {
3921
+
"type": "github",
3922
+
"url": "https://github.com/sponsors/gregberge"
3923
+
},
3924
+
"peerDependencies": {
3925
+
"@svgr/core": "*"
3926
+
}
3927
+
},
1544
3928
"node_modules/@svta/common-media-library": {
1545
3929
"version": "0.12.4",
1546
3930
"resolved": "https://registry.npmjs.org/@svta/common-media-library/-/common-media-library-0.12.4.tgz",
···
1882
4266
"url": "https://github.com/sponsors/tannerlinsley"
1883
4267
}
1884
4268
},
4269
+
"node_modules/@tanstack/query-core": {
4270
+
"version": "5.85.6",
4271
+
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.85.6.tgz",
4272
+
"integrity": "sha512-hCj0TktzdCv2bCepIdfwqVwUVWb+GSHm1Jnn8w+40lfhQ3m7lCO7ADRUJy+2unxQ/nzjh2ipC6ye69NDW3l73g==",
4273
+
"license": "MIT",
4274
+
"funding": {
4275
+
"type": "github",
4276
+
"url": "https://github.com/sponsors/tannerlinsley"
4277
+
}
4278
+
},
4279
+
"node_modules/@tanstack/query-persist-client-core": {
4280
+
"version": "5.85.6",
4281
+
"resolved": "https://registry.npmjs.org/@tanstack/query-persist-client-core/-/query-persist-client-core-5.85.6.tgz",
4282
+
"integrity": "sha512-wUdoEurIC0YCNZzR020Xcg3OsJeF4SXmEPqlNwZ6EaGKgWeNjU17hVdK+X4ZeirUm+h0muiEQx+aIQU1lk7roQ==",
4283
+
"license": "MIT",
4284
+
"dependencies": {
4285
+
"@tanstack/query-core": "5.85.6"
4286
+
},
4287
+
"funding": {
4288
+
"type": "github",
4289
+
"url": "https://github.com/sponsors/tannerlinsley"
4290
+
}
4291
+
},
4292
+
"node_modules/@tanstack/query-sync-storage-persister": {
4293
+
"version": "5.85.6",
4294
+
"resolved": "https://registry.npmjs.org/@tanstack/query-sync-storage-persister/-/query-sync-storage-persister-5.85.6.tgz",
4295
+
"integrity": "sha512-Gj/p0paYsdzj3IbRn6SjMMNdjZ0nVQWszn17qbHLiu3Mt6H0b/YbLL3g9uRWcoyYcaB004RawgM0MuA+xJt5iw==",
4296
+
"license": "MIT",
4297
+
"dependencies": {
4298
+
"@tanstack/query-core": "5.85.6",
4299
+
"@tanstack/query-persist-client-core": "5.85.6"
4300
+
},
4301
+
"funding": {
4302
+
"type": "github",
4303
+
"url": "https://github.com/sponsors/tannerlinsley"
4304
+
}
4305
+
},
1885
4306
"node_modules/@tanstack/react-devtools": {
1886
4307
"version": "0.2.2",
1887
4308
"resolved": "https://registry.npmjs.org/@tanstack/react-devtools/-/react-devtools-0.2.2.tgz",
···
1902
4323
"@types/react-dom": ">=16.8",
1903
4324
"react": ">=16.8",
1904
4325
"react-dom": ">=16.8"
4326
+
}
4327
+
},
4328
+
"node_modules/@tanstack/react-query": {
4329
+
"version": "5.85.6",
4330
+
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.85.6.tgz",
4331
+
"integrity": "sha512-VUAag4ERjh+qlmg0wNivQIVCZUrYndqYu3/wPCVZd4r0E+1IqotbeyGTc+ICroL/PqbpSaGZg02zSWYfcvxbdA==",
4332
+
"license": "MIT",
4333
+
"dependencies": {
4334
+
"@tanstack/query-core": "5.85.6"
4335
+
},
4336
+
"funding": {
4337
+
"type": "github",
4338
+
"url": "https://github.com/sponsors/tannerlinsley"
4339
+
},
4340
+
"peerDependencies": {
4341
+
"react": "^18 || ^19"
4342
+
}
4343
+
},
4344
+
"node_modules/@tanstack/react-query-persist-client": {
4345
+
"version": "5.85.6",
4346
+
"resolved": "https://registry.npmjs.org/@tanstack/react-query-persist-client/-/react-query-persist-client-5.85.6.tgz",
4347
+
"integrity": "sha512-zLUfm8JlI6/s0AqvX5l5CcazdHwj5gwcv0mWYOaJJvADyFzl2wwQKqB/H4nYSeygUtrepBgPwVQKNqH9ZwlZpQ==",
4348
+
"license": "MIT",
4349
+
"dependencies": {
4350
+
"@tanstack/query-persist-client-core": "5.85.6"
4351
+
},
4352
+
"funding": {
4353
+
"type": "github",
4354
+
"url": "https://github.com/sponsors/tannerlinsley"
4355
+
},
4356
+
"peerDependencies": {
4357
+
"@tanstack/react-query": "^5.85.6",
4358
+
"react": "^18 || ^19"
1905
4359
}
1906
4360
},
1907
4361
"node_modules/@tanstack/react-router": {
···
2262
4716
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
2263
4717
"license": "MIT"
2264
4718
},
4719
+
"node_modules/@types/json-schema": {
4720
+
"version": "7.0.15",
4721
+
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
4722
+
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
4723
+
"dev": true,
4724
+
"license": "MIT",
4725
+
"peer": true
4726
+
},
2265
4727
"node_modules/@types/node": {
2266
4728
"version": "24.3.0",
2267
4729
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.0.tgz",
···
2290
4752
"@types/react": "^19.0.0"
2291
4753
}
2292
4754
},
4755
+
"node_modules/@types/trusted-types": {
4756
+
"version": "2.0.7",
4757
+
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
4758
+
"integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
4759
+
"license": "MIT",
4760
+
"optional": true
4761
+
},
4762
+
"node_modules/@typescript-eslint/eslint-plugin": {
4763
+
"version": "8.46.1",
4764
+
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.1.tgz",
4765
+
"integrity": "sha512-rUsLh8PXmBjdiPY+Emjz9NX2yHvhS11v0SR6xNJkm5GM1MO9ea/1GoDKlHHZGrOJclL/cZ2i/vRUYVtjRhrHVQ==",
4766
+
"dev": true,
4767
+
"license": "MIT",
4768
+
"dependencies": {
4769
+
"@eslint-community/regexpp": "^4.10.0",
4770
+
"@typescript-eslint/scope-manager": "8.46.1",
4771
+
"@typescript-eslint/type-utils": "8.46.1",
4772
+
"@typescript-eslint/utils": "8.46.1",
4773
+
"@typescript-eslint/visitor-keys": "8.46.1",
4774
+
"graphemer": "^1.4.0",
4775
+
"ignore": "^7.0.0",
4776
+
"natural-compare": "^1.4.0",
4777
+
"ts-api-utils": "^2.1.0"
4778
+
},
4779
+
"engines": {
4780
+
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
4781
+
},
4782
+
"funding": {
4783
+
"type": "opencollective",
4784
+
"url": "https://opencollective.com/typescript-eslint"
4785
+
},
4786
+
"peerDependencies": {
4787
+
"@typescript-eslint/parser": "^8.46.1",
4788
+
"eslint": "^8.57.0 || ^9.0.0",
4789
+
"typescript": ">=4.8.4 <6.0.0"
4790
+
}
4791
+
},
4792
+
"node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": {
4793
+
"version": "7.0.5",
4794
+
"resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz",
4795
+
"integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==",
4796
+
"dev": true,
4797
+
"license": "MIT",
4798
+
"engines": {
4799
+
"node": ">= 4"
4800
+
}
4801
+
},
4802
+
"node_modules/@typescript-eslint/parser": {
4803
+
"version": "8.46.1",
4804
+
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.46.1.tgz",
4805
+
"integrity": "sha512-6JSSaBZmsKvEkbRUkf7Zj7dru/8ZCrJxAqArcLaVMee5907JdtEbKGsZ7zNiIm/UAkpGUkaSMZEXShnN2D1HZA==",
4806
+
"dev": true,
4807
+
"license": "MIT",
4808
+
"dependencies": {
4809
+
"@typescript-eslint/scope-manager": "8.46.1",
4810
+
"@typescript-eslint/types": "8.46.1",
4811
+
"@typescript-eslint/typescript-estree": "8.46.1",
4812
+
"@typescript-eslint/visitor-keys": "8.46.1",
4813
+
"debug": "^4.3.4"
4814
+
},
4815
+
"engines": {
4816
+
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
4817
+
},
4818
+
"funding": {
4819
+
"type": "opencollective",
4820
+
"url": "https://opencollective.com/typescript-eslint"
4821
+
},
4822
+
"peerDependencies": {
4823
+
"eslint": "^8.57.0 || ^9.0.0",
4824
+
"typescript": ">=4.8.4 <6.0.0"
4825
+
}
4826
+
},
4827
+
"node_modules/@typescript-eslint/project-service": {
4828
+
"version": "8.46.1",
4829
+
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.46.1.tgz",
4830
+
"integrity": "sha512-FOIaFVMHzRskXr5J4Jp8lFVV0gz5ngv3RHmn+E4HYxSJ3DgDzU7fVI1/M7Ijh1zf6S7HIoaIOtln1H5y8V+9Zg==",
4831
+
"dev": true,
4832
+
"license": "MIT",
4833
+
"dependencies": {
4834
+
"@typescript-eslint/tsconfig-utils": "^8.46.1",
4835
+
"@typescript-eslint/types": "^8.46.1",
4836
+
"debug": "^4.3.4"
4837
+
},
4838
+
"engines": {
4839
+
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
4840
+
},
4841
+
"funding": {
4842
+
"type": "opencollective",
4843
+
"url": "https://opencollective.com/typescript-eslint"
4844
+
},
4845
+
"peerDependencies": {
4846
+
"typescript": ">=4.8.4 <6.0.0"
4847
+
}
4848
+
},
4849
+
"node_modules/@typescript-eslint/scope-manager": {
4850
+
"version": "8.46.1",
4851
+
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.46.1.tgz",
4852
+
"integrity": "sha512-weL9Gg3/5F0pVQKiF8eOXFZp8emqWzZsOJuWRUNtHT+UNV2xSJegmpCNQHy37aEQIbToTq7RHKhWvOsmbM680A==",
4853
+
"dev": true,
4854
+
"license": "MIT",
4855
+
"dependencies": {
4856
+
"@typescript-eslint/types": "8.46.1",
4857
+
"@typescript-eslint/visitor-keys": "8.46.1"
4858
+
},
4859
+
"engines": {
4860
+
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
4861
+
},
4862
+
"funding": {
4863
+
"type": "opencollective",
4864
+
"url": "https://opencollective.com/typescript-eslint"
4865
+
}
4866
+
},
4867
+
"node_modules/@typescript-eslint/tsconfig-utils": {
4868
+
"version": "8.46.1",
4869
+
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.46.1.tgz",
4870
+
"integrity": "sha512-X88+J/CwFvlJB+mK09VFqx5FE4H5cXD+H/Bdza2aEWkSb8hnWIQorNcscRl4IEo1Cz9VI/+/r/jnGWkbWPx54g==",
4871
+
"dev": true,
4872
+
"license": "MIT",
4873
+
"engines": {
4874
+
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
4875
+
},
4876
+
"funding": {
4877
+
"type": "opencollective",
4878
+
"url": "https://opencollective.com/typescript-eslint"
4879
+
},
4880
+
"peerDependencies": {
4881
+
"typescript": ">=4.8.4 <6.0.0"
4882
+
}
4883
+
},
4884
+
"node_modules/@typescript-eslint/type-utils": {
4885
+
"version": "8.46.1",
4886
+
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.46.1.tgz",
4887
+
"integrity": "sha512-+BlmiHIiqufBxkVnOtFwjah/vrkF4MtKKvpXrKSPLCkCtAp8H01/VV43sfqA98Od7nJpDcFnkwgyfQbOG0AMvw==",
4888
+
"dev": true,
4889
+
"license": "MIT",
4890
+
"dependencies": {
4891
+
"@typescript-eslint/types": "8.46.1",
4892
+
"@typescript-eslint/typescript-estree": "8.46.1",
4893
+
"@typescript-eslint/utils": "8.46.1",
4894
+
"debug": "^4.3.4",
4895
+
"ts-api-utils": "^2.1.0"
4896
+
},
4897
+
"engines": {
4898
+
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
4899
+
},
4900
+
"funding": {
4901
+
"type": "opencollective",
4902
+
"url": "https://opencollective.com/typescript-eslint"
4903
+
},
4904
+
"peerDependencies": {
4905
+
"eslint": "^8.57.0 || ^9.0.0",
4906
+
"typescript": ">=4.8.4 <6.0.0"
4907
+
}
4908
+
},
4909
+
"node_modules/@typescript-eslint/types": {
4910
+
"version": "8.46.1",
4911
+
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.46.1.tgz",
4912
+
"integrity": "sha512-C+soprGBHwWBdkDpbaRC4paGBrkIXxVlNohadL5o0kfhsXqOC6GYH2S/Obmig+I0HTDl8wMaRySwrfrXVP8/pQ==",
4913
+
"dev": true,
4914
+
"license": "MIT",
4915
+
"engines": {
4916
+
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
4917
+
},
4918
+
"funding": {
4919
+
"type": "opencollective",
4920
+
"url": "https://opencollective.com/typescript-eslint"
4921
+
}
4922
+
},
4923
+
"node_modules/@typescript-eslint/typescript-estree": {
4924
+
"version": "8.46.1",
4925
+
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.46.1.tgz",
4926
+
"integrity": "sha512-uIifjT4s8cQKFQ8ZBXXyoUODtRoAd7F7+G8MKmtzj17+1UbdzFl52AzRyZRyKqPHhgzvXunnSckVu36flGy8cg==",
4927
+
"dev": true,
4928
+
"license": "MIT",
4929
+
"dependencies": {
4930
+
"@typescript-eslint/project-service": "8.46.1",
4931
+
"@typescript-eslint/tsconfig-utils": "8.46.1",
4932
+
"@typescript-eslint/types": "8.46.1",
4933
+
"@typescript-eslint/visitor-keys": "8.46.1",
4934
+
"debug": "^4.3.4",
4935
+
"fast-glob": "^3.3.2",
4936
+
"is-glob": "^4.0.3",
4937
+
"minimatch": "^9.0.4",
4938
+
"semver": "^7.6.0",
4939
+
"ts-api-utils": "^2.1.0"
4940
+
},
4941
+
"engines": {
4942
+
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
4943
+
},
4944
+
"funding": {
4945
+
"type": "opencollective",
4946
+
"url": "https://opencollective.com/typescript-eslint"
4947
+
},
4948
+
"peerDependencies": {
4949
+
"typescript": ">=4.8.4 <6.0.0"
4950
+
}
4951
+
},
4952
+
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
4953
+
"version": "2.0.2",
4954
+
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
4955
+
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
4956
+
"dev": true,
4957
+
"license": "MIT",
4958
+
"dependencies": {
4959
+
"balanced-match": "^1.0.0"
4960
+
}
4961
+
},
4962
+
"node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
4963
+
"version": "9.0.5",
4964
+
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
4965
+
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
4966
+
"dev": true,
4967
+
"license": "ISC",
4968
+
"dependencies": {
4969
+
"brace-expansion": "^2.0.1"
4970
+
},
4971
+
"engines": {
4972
+
"node": ">=16 || 14 >=14.17"
4973
+
},
4974
+
"funding": {
4975
+
"url": "https://github.com/sponsors/isaacs"
4976
+
}
4977
+
},
4978
+
"node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
4979
+
"version": "7.7.3",
4980
+
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
4981
+
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
4982
+
"dev": true,
4983
+
"license": "ISC",
4984
+
"bin": {
4985
+
"semver": "bin/semver.js"
4986
+
},
4987
+
"engines": {
4988
+
"node": ">=10"
4989
+
}
4990
+
},
4991
+
"node_modules/@typescript-eslint/utils": {
4992
+
"version": "8.46.1",
4993
+
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.46.1.tgz",
4994
+
"integrity": "sha512-vkYUy6LdZS7q1v/Gxb2Zs7zziuXN0wxqsetJdeZdRe/f5dwJFglmuvZBfTUivCtjH725C1jWCDfpadadD95EDQ==",
4995
+
"dev": true,
4996
+
"license": "MIT",
4997
+
"dependencies": {
4998
+
"@eslint-community/eslint-utils": "^4.7.0",
4999
+
"@typescript-eslint/scope-manager": "8.46.1",
5000
+
"@typescript-eslint/types": "8.46.1",
5001
+
"@typescript-eslint/typescript-estree": "8.46.1"
5002
+
},
5003
+
"engines": {
5004
+
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
5005
+
},
5006
+
"funding": {
5007
+
"type": "opencollective",
5008
+
"url": "https://opencollective.com/typescript-eslint"
5009
+
},
5010
+
"peerDependencies": {
5011
+
"eslint": "^8.57.0 || ^9.0.0",
5012
+
"typescript": ">=4.8.4 <6.0.0"
5013
+
}
5014
+
},
5015
+
"node_modules/@typescript-eslint/visitor-keys": {
5016
+
"version": "8.46.1",
5017
+
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.46.1.tgz",
5018
+
"integrity": "sha512-ptkmIf2iDkNUjdeu2bQqhFPV1m6qTnFFjg7PPDjxKWaMaP0Z6I9l30Jr3g5QqbZGdw8YdYvLp+XnqnWWZOg/NA==",
5019
+
"dev": true,
5020
+
"license": "MIT",
5021
+
"dependencies": {
5022
+
"@typescript-eslint/types": "8.46.1",
5023
+
"eslint-visitor-keys": "^4.2.1"
5024
+
},
5025
+
"engines": {
5026
+
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
5027
+
},
5028
+
"funding": {
5029
+
"type": "opencollective",
5030
+
"url": "https://opencollective.com/typescript-eslint"
5031
+
}
5032
+
},
2293
5033
"node_modules/@vercel/edge": {
2294
5034
"version": "1.2.2",
2295
5035
"resolved": "https://registry.npmjs.org/@vercel/edge/-/edge-1.2.2.tgz",
···
2454
5194
"node": ">=0.4.0"
2455
5195
}
2456
5196
},
5197
+
"node_modules/acorn-jsx": {
5198
+
"version": "5.3.2",
5199
+
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
5200
+
"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
5201
+
"dev": true,
5202
+
"license": "MIT",
5203
+
"peer": true,
5204
+
"peerDependencies": {
5205
+
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
5206
+
}
5207
+
},
2457
5208
"node_modules/agent-base": {
2458
5209
"version": "7.1.4",
2459
5210
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
···
2464
5215
"node": ">= 14"
2465
5216
}
2466
5217
},
5218
+
"node_modules/ajv": {
5219
+
"version": "6.12.6",
5220
+
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
5221
+
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
5222
+
"dev": true,
5223
+
"license": "MIT",
5224
+
"peer": true,
5225
+
"dependencies": {
5226
+
"fast-deep-equal": "^3.1.1",
5227
+
"fast-json-stable-stringify": "^2.0.0",
5228
+
"json-schema-traverse": "^0.4.1",
5229
+
"uri-js": "^4.2.2"
5230
+
},
5231
+
"funding": {
5232
+
"type": "github",
5233
+
"url": "https://github.com/sponsors/epoberezkin"
5234
+
}
5235
+
},
2467
5236
"node_modules/ansi-regex": {
2468
5237
"version": "5.0.1",
2469
5238
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
···
2509
5278
"node": ">= 8"
2510
5279
}
2511
5280
},
5281
+
"node_modules/argparse": {
5282
+
"version": "2.0.1",
5283
+
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
5284
+
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
5285
+
"dev": true,
5286
+
"license": "Python-2.0"
5287
+
},
5288
+
"node_modules/aria-hidden": {
5289
+
"version": "1.2.6",
5290
+
"resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz",
5291
+
"integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==",
5292
+
"dependencies": {
5293
+
"tslib": "^2.0.0"
5294
+
},
5295
+
"engines": {
5296
+
"node": ">=10"
5297
+
}
5298
+
},
2512
5299
"node_modules/aria-query": {
2513
5300
"version": "5.3.0",
2514
5301
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
···
2519
5306
"dequal": "^2.0.3"
2520
5307
}
2521
5308
},
5309
+
"node_modules/array-buffer-byte-length": {
5310
+
"version": "1.0.2",
5311
+
"resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz",
5312
+
"integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==",
5313
+
"dev": true,
5314
+
"license": "MIT",
5315
+
"dependencies": {
5316
+
"call-bound": "^1.0.3",
5317
+
"is-array-buffer": "^3.0.5"
5318
+
},
5319
+
"engines": {
5320
+
"node": ">= 0.4"
5321
+
},
5322
+
"funding": {
5323
+
"url": "https://github.com/sponsors/ljharb"
5324
+
}
5325
+
},
5326
+
"node_modules/array-includes": {
5327
+
"version": "3.1.9",
5328
+
"resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz",
5329
+
"integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==",
5330
+
"dev": true,
5331
+
"license": "MIT",
5332
+
"dependencies": {
5333
+
"call-bind": "^1.0.8",
5334
+
"call-bound": "^1.0.4",
5335
+
"define-properties": "^1.2.1",
5336
+
"es-abstract": "^1.24.0",
5337
+
"es-object-atoms": "^1.1.1",
5338
+
"get-intrinsic": "^1.3.0",
5339
+
"is-string": "^1.1.1",
5340
+
"math-intrinsics": "^1.1.0"
5341
+
},
5342
+
"engines": {
5343
+
"node": ">= 0.4"
5344
+
},
5345
+
"funding": {
5346
+
"url": "https://github.com/sponsors/ljharb"
5347
+
}
5348
+
},
5349
+
"node_modules/array.prototype.findlast": {
5350
+
"version": "1.2.5",
5351
+
"resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz",
5352
+
"integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==",
5353
+
"dev": true,
5354
+
"license": "MIT",
5355
+
"dependencies": {
5356
+
"call-bind": "^1.0.7",
5357
+
"define-properties": "^1.2.1",
5358
+
"es-abstract": "^1.23.2",
5359
+
"es-errors": "^1.3.0",
5360
+
"es-object-atoms": "^1.0.0",
5361
+
"es-shim-unscopables": "^1.0.2"
5362
+
},
5363
+
"engines": {
5364
+
"node": ">= 0.4"
5365
+
},
5366
+
"funding": {
5367
+
"url": "https://github.com/sponsors/ljharb"
5368
+
}
5369
+
},
5370
+
"node_modules/array.prototype.flat": {
5371
+
"version": "1.3.3",
5372
+
"resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz",
5373
+
"integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==",
5374
+
"dev": true,
5375
+
"license": "MIT",
5376
+
"dependencies": {
5377
+
"call-bind": "^1.0.8",
5378
+
"define-properties": "^1.2.1",
5379
+
"es-abstract": "^1.23.5",
5380
+
"es-shim-unscopables": "^1.0.2"
5381
+
},
5382
+
"engines": {
5383
+
"node": ">= 0.4"
5384
+
},
5385
+
"funding": {
5386
+
"url": "https://github.com/sponsors/ljharb"
5387
+
}
5388
+
},
5389
+
"node_modules/array.prototype.flatmap": {
5390
+
"version": "1.3.3",
5391
+
"resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz",
5392
+
"integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==",
5393
+
"dev": true,
5394
+
"license": "MIT",
5395
+
"dependencies": {
5396
+
"call-bind": "^1.0.8",
5397
+
"define-properties": "^1.2.1",
5398
+
"es-abstract": "^1.23.5",
5399
+
"es-shim-unscopables": "^1.0.2"
5400
+
},
5401
+
"engines": {
5402
+
"node": ">= 0.4"
5403
+
},
5404
+
"funding": {
5405
+
"url": "https://github.com/sponsors/ljharb"
5406
+
}
5407
+
},
5408
+
"node_modules/array.prototype.tosorted": {
5409
+
"version": "1.1.4",
5410
+
"resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz",
5411
+
"integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==",
5412
+
"dev": true,
5413
+
"license": "MIT",
5414
+
"dependencies": {
5415
+
"call-bind": "^1.0.7",
5416
+
"define-properties": "^1.2.1",
5417
+
"es-abstract": "^1.23.3",
5418
+
"es-errors": "^1.3.0",
5419
+
"es-shim-unscopables": "^1.0.2"
5420
+
},
5421
+
"engines": {
5422
+
"node": ">= 0.4"
5423
+
}
5424
+
},
5425
+
"node_modules/arraybuffer.prototype.slice": {
5426
+
"version": "1.0.4",
5427
+
"resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz",
5428
+
"integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==",
5429
+
"dev": true,
5430
+
"license": "MIT",
5431
+
"dependencies": {
5432
+
"array-buffer-byte-length": "^1.0.1",
5433
+
"call-bind": "^1.0.8",
5434
+
"define-properties": "^1.2.1",
5435
+
"es-abstract": "^1.23.5",
5436
+
"es-errors": "^1.3.0",
5437
+
"get-intrinsic": "^1.2.6",
5438
+
"is-array-buffer": "^3.0.4"
5439
+
},
5440
+
"engines": {
5441
+
"node": ">= 0.4"
5442
+
},
5443
+
"funding": {
5444
+
"url": "https://github.com/sponsors/ljharb"
5445
+
}
5446
+
},
2522
5447
"node_modules/assertion-error": {
2523
5448
"version": "2.0.1",
2524
5449
"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz",
···
2541
5466
"node": ">=4"
2542
5467
}
2543
5468
},
5469
+
"node_modules/async-function": {
5470
+
"version": "1.0.0",
5471
+
"resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz",
5472
+
"integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==",
5473
+
"dev": true,
5474
+
"license": "MIT",
5475
+
"engines": {
5476
+
"node": ">= 0.4"
5477
+
}
5478
+
},
5479
+
"node_modules/available-typed-arrays": {
5480
+
"version": "1.0.7",
5481
+
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
5482
+
"integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
5483
+
"dev": true,
5484
+
"license": "MIT",
5485
+
"dependencies": {
5486
+
"possible-typed-array-names": "^1.0.0"
5487
+
},
5488
+
"engines": {
5489
+
"node": ">= 0.4"
5490
+
},
5491
+
"funding": {
5492
+
"url": "https://github.com/sponsors/ljharb"
5493
+
}
5494
+
},
2544
5495
"node_modules/await-lock": {
2545
5496
"version": "2.2.2",
2546
5497
"resolved": "https://registry.npmjs.org/await-lock/-/await-lock-2.2.2.tgz",
···
2558
5509
"@babel/traverse": "^7.23.7",
2559
5510
"@babel/types": "^7.23.6"
2560
5511
}
5512
+
},
5513
+
"node_modules/babel-plugin-react-compiler": {
5514
+
"version": "1.0.0",
5515
+
"resolved": "https://registry.npmjs.org/babel-plugin-react-compiler/-/babel-plugin-react-compiler-1.0.0.tgz",
5516
+
"integrity": "sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==",
5517
+
"dev": true,
5518
+
"license": "MIT",
5519
+
"dependencies": {
5520
+
"@babel/types": "^7.26.0"
5521
+
}
5522
+
},
5523
+
"node_modules/balanced-match": {
5524
+
"version": "1.0.2",
5525
+
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
5526
+
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
5527
+
"dev": true,
5528
+
"license": "MIT"
2561
5529
},
2562
5530
"node_modules/bcp-47": {
2563
5531
"version": "2.1.0",
···
2610
5578
"url": "https://github.com/sponsors/sindresorhus"
2611
5579
}
2612
5580
},
5581
+
"node_modules/birecord": {
5582
+
"version": "0.1.1",
5583
+
"resolved": "https://registry.npmjs.org/birecord/-/birecord-0.1.1.tgz",
5584
+
"integrity": "sha512-VUpsf/qykW0heRlC8LooCq28Kxn3mAqKohhDG/49rrsQ1dT1CXyj/pgXS+5BSRzFTR/3DyIBOqQOrGyZOh71Aw==",
5585
+
"dev": true,
5586
+
"license": "(MIT OR Apache-2.0)"
5587
+
},
5588
+
"node_modules/brace-expansion": {
5589
+
"version": "1.1.12",
5590
+
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
5591
+
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
5592
+
"dev": true,
5593
+
"license": "MIT",
5594
+
"dependencies": {
5595
+
"balanced-match": "^1.0.0",
5596
+
"concat-map": "0.0.1"
5597
+
}
5598
+
},
2613
5599
"node_modules/braces": {
2614
5600
"version": "3.0.3",
2615
5601
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
···
2664
5650
"node": ">=8"
2665
5651
}
2666
5652
},
5653
+
"node_modules/call-bind": {
5654
+
"version": "1.0.8",
5655
+
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz",
5656
+
"integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==",
5657
+
"dev": true,
5658
+
"license": "MIT",
5659
+
"dependencies": {
5660
+
"call-bind-apply-helpers": "^1.0.0",
5661
+
"es-define-property": "^1.0.0",
5662
+
"get-intrinsic": "^1.2.4",
5663
+
"set-function-length": "^1.2.2"
5664
+
},
5665
+
"engines": {
5666
+
"node": ">= 0.4"
5667
+
},
5668
+
"funding": {
5669
+
"url": "https://github.com/sponsors/ljharb"
5670
+
}
5671
+
},
5672
+
"node_modules/call-bind-apply-helpers": {
5673
+
"version": "1.0.2",
5674
+
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
5675
+
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
5676
+
"dev": true,
5677
+
"license": "MIT",
5678
+
"dependencies": {
5679
+
"es-errors": "^1.3.0",
5680
+
"function-bind": "^1.1.2"
5681
+
},
5682
+
"engines": {
5683
+
"node": ">= 0.4"
5684
+
}
5685
+
},
5686
+
"node_modules/call-bound": {
5687
+
"version": "1.0.4",
5688
+
"resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
5689
+
"integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
5690
+
"dev": true,
5691
+
"license": "MIT",
5692
+
"dependencies": {
5693
+
"call-bind-apply-helpers": "^1.0.2",
5694
+
"get-intrinsic": "^1.3.0"
5695
+
},
5696
+
"engines": {
5697
+
"node": ">= 0.4"
5698
+
},
5699
+
"funding": {
5700
+
"url": "https://github.com/sponsors/ljharb"
5701
+
}
5702
+
},
5703
+
"node_modules/callsites": {
5704
+
"version": "3.1.0",
5705
+
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
5706
+
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
5707
+
"dev": true,
5708
+
"license": "MIT",
5709
+
"engines": {
5710
+
"node": ">=6"
5711
+
}
5712
+
},
5713
+
"node_modules/camelcase": {
5714
+
"version": "6.3.0",
5715
+
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
5716
+
"integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
5717
+
"dev": true,
5718
+
"license": "MIT",
5719
+
"engines": {
5720
+
"node": ">=10"
5721
+
},
5722
+
"funding": {
5723
+
"url": "https://github.com/sponsors/sindresorhus"
5724
+
}
5725
+
},
2667
5726
"node_modules/caniuse-lite": {
2668
5727
"version": "1.0.30001737",
2669
5728
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001737.tgz",
···
2719
5778
"node": ">=18"
2720
5779
}
2721
5780
},
5781
+
"node_modules/chalk": {
5782
+
"version": "4.1.2",
5783
+
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
5784
+
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
5785
+
"dev": true,
5786
+
"license": "MIT",
5787
+
"peer": true,
5788
+
"dependencies": {
5789
+
"ansi-styles": "^4.1.0",
5790
+
"supports-color": "^7.1.0"
5791
+
},
5792
+
"engines": {
5793
+
"node": ">=10"
5794
+
},
5795
+
"funding": {
5796
+
"url": "https://github.com/chalk/chalk?sponsor=1"
5797
+
}
5798
+
},
5799
+
"node_modules/chalk/node_modules/ansi-styles": {
5800
+
"version": "4.3.0",
5801
+
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
5802
+
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
5803
+
"dev": true,
5804
+
"license": "MIT",
5805
+
"peer": true,
5806
+
"dependencies": {
5807
+
"color-convert": "^2.0.1"
5808
+
},
5809
+
"engines": {
5810
+
"node": ">=8"
5811
+
},
5812
+
"funding": {
5813
+
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
5814
+
}
5815
+
},
2722
5816
"node_modules/check-error": {
2723
5817
"version": "2.1.1",
2724
5818
"resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz",
···
2783
5877
"integrity": "sha512-eNk3TRV+xQMJ1PEj0FQGY8KD4m0GPxT487XJ+Iftm7mVa9WpPFDMWqPt+46buiP5j5Wzqe5oMIhqBcAeKfygSA==",
2784
5878
"license": "MIT"
2785
5879
},
5880
+
"node_modules/color-convert": {
5881
+
"version": "2.0.1",
5882
+
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
5883
+
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
5884
+
"dev": true,
5885
+
"license": "MIT",
5886
+
"peer": true,
5887
+
"dependencies": {
5888
+
"color-name": "~1.1.4"
5889
+
},
5890
+
"engines": {
5891
+
"node": ">=7.0.0"
5892
+
}
5893
+
},
5894
+
"node_modules/color-name": {
5895
+
"version": "1.1.4",
5896
+
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
5897
+
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
5898
+
"dev": true,
5899
+
"license": "MIT",
5900
+
"peer": true
5901
+
},
5902
+
"node_modules/compare-versions": {
5903
+
"version": "6.1.1",
5904
+
"resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.1.tgz",
5905
+
"integrity": "sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==",
5906
+
"dev": true,
5907
+
"license": "MIT"
5908
+
},
5909
+
"node_modules/concat-map": {
5910
+
"version": "0.0.1",
5911
+
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
5912
+
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
5913
+
"dev": true,
5914
+
"license": "MIT"
5915
+
},
5916
+
"node_modules/confbox": {
5917
+
"version": "0.2.2",
5918
+
"resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz",
5919
+
"integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==",
5920
+
"dev": true,
5921
+
"license": "MIT"
5922
+
},
2786
5923
"node_modules/convert-source-map": {
2787
5924
"version": "2.0.0",
2788
5925
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
···
2795
5932
"integrity": "sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==",
2796
5933
"license": "MIT"
2797
5934
},
5935
+
"node_modules/core-js": {
5936
+
"version": "3.46.0",
5937
+
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.46.0.tgz",
5938
+
"integrity": "sha512-vDMm9B0xnqqZ8uSBpZ8sNtRtOdmfShrvT6h2TuQGLs0Is+cR0DYbj/KWP6ALVNbWPpqA/qPLoOuppJN07humpA==",
5939
+
"hasInstallScript": true,
5940
+
"license": "MIT",
5941
+
"funding": {
5942
+
"type": "opencollective",
5943
+
"url": "https://opencollective.com/core-js"
5944
+
}
5945
+
},
5946
+
"node_modules/cosmiconfig": {
5947
+
"version": "8.3.6",
5948
+
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz",
5949
+
"integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==",
5950
+
"dev": true,
5951
+
"license": "MIT",
5952
+
"dependencies": {
5953
+
"import-fresh": "^3.3.0",
5954
+
"js-yaml": "^4.1.0",
5955
+
"parse-json": "^5.2.0",
5956
+
"path-type": "^4.0.0"
5957
+
},
5958
+
"engines": {
5959
+
"node": ">=14"
5960
+
},
5961
+
"funding": {
5962
+
"url": "https://github.com/sponsors/d-fischer"
5963
+
},
5964
+
"peerDependencies": {
5965
+
"typescript": ">=4.9.5"
5966
+
},
5967
+
"peerDependenciesMeta": {
5968
+
"typescript": {
5969
+
"optional": true
5970
+
}
5971
+
}
5972
+
},
5973
+
"node_modules/cross-spawn": {
5974
+
"version": "7.0.6",
5975
+
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
5976
+
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
5977
+
"dev": true,
5978
+
"license": "MIT",
5979
+
"peer": true,
5980
+
"dependencies": {
5981
+
"path-key": "^3.1.0",
5982
+
"shebang-command": "^2.0.0",
5983
+
"which": "^2.0.1"
5984
+
},
5985
+
"engines": {
5986
+
"node": ">= 8"
5987
+
}
5988
+
},
2798
5989
"node_modules/cssstyle": {
2799
5990
"version": "4.6.0",
2800
5991
"resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.6.0.tgz",
···
2863
6054
"node": ">=18"
2864
6055
}
2865
6056
},
6057
+
"node_modules/data-view-buffer": {
6058
+
"version": "1.0.2",
6059
+
"resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz",
6060
+
"integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==",
6061
+
"dev": true,
6062
+
"license": "MIT",
6063
+
"dependencies": {
6064
+
"call-bound": "^1.0.3",
6065
+
"es-errors": "^1.3.0",
6066
+
"is-data-view": "^1.0.2"
6067
+
},
6068
+
"engines": {
6069
+
"node": ">= 0.4"
6070
+
},
6071
+
"funding": {
6072
+
"url": "https://github.com/sponsors/ljharb"
6073
+
}
6074
+
},
6075
+
"node_modules/data-view-byte-length": {
6076
+
"version": "1.0.2",
6077
+
"resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz",
6078
+
"integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==",
6079
+
"dev": true,
6080
+
"license": "MIT",
6081
+
"dependencies": {
6082
+
"call-bound": "^1.0.3",
6083
+
"es-errors": "^1.3.0",
6084
+
"is-data-view": "^1.0.2"
6085
+
},
6086
+
"engines": {
6087
+
"node": ">= 0.4"
6088
+
},
6089
+
"funding": {
6090
+
"url": "https://github.com/sponsors/inspect-js"
6091
+
}
6092
+
},
6093
+
"node_modules/data-view-byte-offset": {
6094
+
"version": "1.0.1",
6095
+
"resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz",
6096
+
"integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==",
6097
+
"dev": true,
6098
+
"license": "MIT",
6099
+
"dependencies": {
6100
+
"call-bound": "^1.0.2",
6101
+
"es-errors": "^1.3.0",
6102
+
"is-data-view": "^1.0.1"
6103
+
},
6104
+
"engines": {
6105
+
"node": ">= 0.4"
6106
+
},
6107
+
"funding": {
6108
+
"url": "https://github.com/sponsors/ljharb"
6109
+
}
6110
+
},
2866
6111
"node_modules/debug": {
2867
-
"version": "4.4.1",
2868
-
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
2869
-
"integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
6112
+
"version": "4.4.3",
6113
+
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
6114
+
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
2870
6115
"license": "MIT",
2871
6116
"dependencies": {
2872
6117
"ms": "^2.1.3"
···
2897
6142
"node": ">=6"
2898
6143
}
2899
6144
},
6145
+
"node_modules/deep-is": {
6146
+
"version": "0.1.4",
6147
+
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
6148
+
"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
6149
+
"dev": true,
6150
+
"license": "MIT",
6151
+
"peer": true
6152
+
},
6153
+
"node_modules/define-data-property": {
6154
+
"version": "1.1.4",
6155
+
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
6156
+
"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
6157
+
"dev": true,
6158
+
"license": "MIT",
6159
+
"dependencies": {
6160
+
"es-define-property": "^1.0.0",
6161
+
"es-errors": "^1.3.0",
6162
+
"gopd": "^1.0.1"
6163
+
},
6164
+
"engines": {
6165
+
"node": ">= 0.4"
6166
+
},
6167
+
"funding": {
6168
+
"url": "https://github.com/sponsors/ljharb"
6169
+
}
6170
+
},
6171
+
"node_modules/define-properties": {
6172
+
"version": "1.2.1",
6173
+
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
6174
+
"integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
6175
+
"dev": true,
6176
+
"license": "MIT",
6177
+
"dependencies": {
6178
+
"define-data-property": "^1.0.1",
6179
+
"has-property-descriptors": "^1.0.0",
6180
+
"object-keys": "^1.1.1"
6181
+
},
6182
+
"engines": {
6183
+
"node": ">= 0.4"
6184
+
},
6185
+
"funding": {
6186
+
"url": "https://github.com/sponsors/ljharb"
6187
+
}
6188
+
},
2900
6189
"node_modules/dequal": {
2901
6190
"version": "2.0.3",
2902
6191
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
···
2915
6204
"engines": {
2916
6205
"node": ">=8"
2917
6206
}
6207
+
},
6208
+
"node_modules/detect-node-es": {
6209
+
"version": "1.1.0",
6210
+
"resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
6211
+
"integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="
2918
6212
},
2919
6213
"node_modules/diff": {
2920
6214
"version": "8.0.2",
···
2925
6219
"node": ">=0.3.1"
2926
6220
}
2927
6221
},
6222
+
"node_modules/doctrine": {
6223
+
"version": "2.1.0",
6224
+
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
6225
+
"integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
6226
+
"dev": true,
6227
+
"license": "Apache-2.0",
6228
+
"dependencies": {
6229
+
"esutils": "^2.0.2"
6230
+
},
6231
+
"engines": {
6232
+
"node": ">=0.10.0"
6233
+
}
6234
+
},
2928
6235
"node_modules/dom-accessibility-api": {
2929
6236
"version": "0.5.16",
2930
6237
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
···
2932
6239
"dev": true,
2933
6240
"license": "MIT"
2934
6241
},
6242
+
"node_modules/dompurify": {
6243
+
"version": "3.3.0",
6244
+
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.0.tgz",
6245
+
"integrity": "sha512-r+f6MYR1gGN1eJv0TVQbhA7if/U7P87cdPl3HN5rikqaBSBxLiCb/b9O+2eG0cxz0ghyU+mU1QkbsOwERMYlWQ==",
6246
+
"license": "(MPL-2.0 OR Apache-2.0)",
6247
+
"optionalDependencies": {
6248
+
"@types/trusted-types": "^2.0.7"
6249
+
}
6250
+
},
6251
+
"node_modules/dot-case": {
6252
+
"version": "3.0.4",
6253
+
"resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz",
6254
+
"integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==",
6255
+
"dev": true,
6256
+
"license": "MIT",
6257
+
"dependencies": {
6258
+
"no-case": "^3.0.4",
6259
+
"tslib": "^2.0.3"
6260
+
}
6261
+
},
6262
+
"node_modules/dunder-proto": {
6263
+
"version": "1.0.1",
6264
+
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
6265
+
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
6266
+
"dev": true,
6267
+
"license": "MIT",
6268
+
"dependencies": {
6269
+
"call-bind-apply-helpers": "^1.0.1",
6270
+
"es-errors": "^1.3.0",
6271
+
"gopd": "^1.2.0"
6272
+
},
6273
+
"engines": {
6274
+
"node": ">= 0.4"
6275
+
}
6276
+
},
2935
6277
"node_modules/electron-to-chromium": {
2936
6278
"version": "1.5.211",
2937
6279
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.211.tgz",
···
2964
6306
"url": "https://github.com/fb55/entities?sponsor=1"
2965
6307
}
2966
6308
},
6309
+
"node_modules/error-ex": {
6310
+
"version": "1.3.4",
6311
+
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz",
6312
+
"integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==",
6313
+
"dev": true,
6314
+
"license": "MIT",
6315
+
"dependencies": {
6316
+
"is-arrayish": "^0.2.1"
6317
+
}
6318
+
},
6319
+
"node_modules/es-abstract": {
6320
+
"version": "1.24.0",
6321
+
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz",
6322
+
"integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==",
6323
+
"dev": true,
6324
+
"license": "MIT",
6325
+
"dependencies": {
6326
+
"array-buffer-byte-length": "^1.0.2",
6327
+
"arraybuffer.prototype.slice": "^1.0.4",
6328
+
"available-typed-arrays": "^1.0.7",
6329
+
"call-bind": "^1.0.8",
6330
+
"call-bound": "^1.0.4",
6331
+
"data-view-buffer": "^1.0.2",
6332
+
"data-view-byte-length": "^1.0.2",
6333
+
"data-view-byte-offset": "^1.0.1",
6334
+
"es-define-property": "^1.0.1",
6335
+
"es-errors": "^1.3.0",
6336
+
"es-object-atoms": "^1.1.1",
6337
+
"es-set-tostringtag": "^2.1.0",
6338
+
"es-to-primitive": "^1.3.0",
6339
+
"function.prototype.name": "^1.1.8",
6340
+
"get-intrinsic": "^1.3.0",
6341
+
"get-proto": "^1.0.1",
6342
+
"get-symbol-description": "^1.1.0",
6343
+
"globalthis": "^1.0.4",
6344
+
"gopd": "^1.2.0",
6345
+
"has-property-descriptors": "^1.0.2",
6346
+
"has-proto": "^1.2.0",
6347
+
"has-symbols": "^1.1.0",
6348
+
"hasown": "^2.0.2",
6349
+
"internal-slot": "^1.1.0",
6350
+
"is-array-buffer": "^3.0.5",
6351
+
"is-callable": "^1.2.7",
6352
+
"is-data-view": "^1.0.2",
6353
+
"is-negative-zero": "^2.0.3",
6354
+
"is-regex": "^1.2.1",
6355
+
"is-set": "^2.0.3",
6356
+
"is-shared-array-buffer": "^1.0.4",
6357
+
"is-string": "^1.1.1",
6358
+
"is-typed-array": "^1.1.15",
6359
+
"is-weakref": "^1.1.1",
6360
+
"math-intrinsics": "^1.1.0",
6361
+
"object-inspect": "^1.13.4",
6362
+
"object-keys": "^1.1.1",
6363
+
"object.assign": "^4.1.7",
6364
+
"own-keys": "^1.0.1",
6365
+
"regexp.prototype.flags": "^1.5.4",
6366
+
"safe-array-concat": "^1.1.3",
6367
+
"safe-push-apply": "^1.0.0",
6368
+
"safe-regex-test": "^1.1.0",
6369
+
"set-proto": "^1.0.0",
6370
+
"stop-iteration-iterator": "^1.1.0",
6371
+
"string.prototype.trim": "^1.2.10",
6372
+
"string.prototype.trimend": "^1.0.9",
6373
+
"string.prototype.trimstart": "^1.0.8",
6374
+
"typed-array-buffer": "^1.0.3",
6375
+
"typed-array-byte-length": "^1.0.3",
6376
+
"typed-array-byte-offset": "^1.0.4",
6377
+
"typed-array-length": "^1.0.7",
6378
+
"unbox-primitive": "^1.1.0",
6379
+
"which-typed-array": "^1.1.19"
6380
+
},
6381
+
"engines": {
6382
+
"node": ">= 0.4"
6383
+
},
6384
+
"funding": {
6385
+
"url": "https://github.com/sponsors/ljharb"
6386
+
}
6387
+
},
6388
+
"node_modules/es-define-property": {
6389
+
"version": "1.0.1",
6390
+
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
6391
+
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
6392
+
"dev": true,
6393
+
"license": "MIT",
6394
+
"engines": {
6395
+
"node": ">= 0.4"
6396
+
}
6397
+
},
6398
+
"node_modules/es-errors": {
6399
+
"version": "1.3.0",
6400
+
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
6401
+
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
6402
+
"dev": true,
6403
+
"license": "MIT",
6404
+
"engines": {
6405
+
"node": ">= 0.4"
6406
+
}
6407
+
},
6408
+
"node_modules/es-iterator-helpers": {
6409
+
"version": "1.2.1",
6410
+
"resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.1.tgz",
6411
+
"integrity": "sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==",
6412
+
"dev": true,
6413
+
"license": "MIT",
6414
+
"dependencies": {
6415
+
"call-bind": "^1.0.8",
6416
+
"call-bound": "^1.0.3",
6417
+
"define-properties": "^1.2.1",
6418
+
"es-abstract": "^1.23.6",
6419
+
"es-errors": "^1.3.0",
6420
+
"es-set-tostringtag": "^2.0.3",
6421
+
"function-bind": "^1.1.2",
6422
+
"get-intrinsic": "^1.2.6",
6423
+
"globalthis": "^1.0.4",
6424
+
"gopd": "^1.2.0",
6425
+
"has-property-descriptors": "^1.0.2",
6426
+
"has-proto": "^1.2.0",
6427
+
"has-symbols": "^1.1.0",
6428
+
"internal-slot": "^1.1.0",
6429
+
"iterator.prototype": "^1.1.4",
6430
+
"safe-array-concat": "^1.1.3"
6431
+
},
6432
+
"engines": {
6433
+
"node": ">= 0.4"
6434
+
}
6435
+
},
2967
6436
"node_modules/es-module-lexer": {
2968
6437
"version": "1.7.0",
2969
6438
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz",
···
2971
6440
"dev": true,
2972
6441
"license": "MIT"
2973
6442
},
6443
+
"node_modules/es-object-atoms": {
6444
+
"version": "1.1.1",
6445
+
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
6446
+
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
6447
+
"dev": true,
6448
+
"license": "MIT",
6449
+
"dependencies": {
6450
+
"es-errors": "^1.3.0"
6451
+
},
6452
+
"engines": {
6453
+
"node": ">= 0.4"
6454
+
}
6455
+
},
6456
+
"node_modules/es-set-tostringtag": {
6457
+
"version": "2.1.0",
6458
+
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
6459
+
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
6460
+
"dev": true,
6461
+
"license": "MIT",
6462
+
"dependencies": {
6463
+
"es-errors": "^1.3.0",
6464
+
"get-intrinsic": "^1.2.6",
6465
+
"has-tostringtag": "^1.0.2",
6466
+
"hasown": "^2.0.2"
6467
+
},
6468
+
"engines": {
6469
+
"node": ">= 0.4"
6470
+
}
6471
+
},
6472
+
"node_modules/es-shim-unscopables": {
6473
+
"version": "1.1.0",
6474
+
"resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz",
6475
+
"integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==",
6476
+
"dev": true,
6477
+
"license": "MIT",
6478
+
"dependencies": {
6479
+
"hasown": "^2.0.2"
6480
+
},
6481
+
"engines": {
6482
+
"node": ">= 0.4"
6483
+
}
6484
+
},
6485
+
"node_modules/es-to-primitive": {
6486
+
"version": "1.3.0",
6487
+
"resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz",
6488
+
"integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==",
6489
+
"dev": true,
6490
+
"license": "MIT",
6491
+
"dependencies": {
6492
+
"is-callable": "^1.2.7",
6493
+
"is-date-object": "^1.0.5",
6494
+
"is-symbol": "^1.0.4"
6495
+
},
6496
+
"engines": {
6497
+
"node": ">= 0.4"
6498
+
},
6499
+
"funding": {
6500
+
"url": "https://github.com/sponsors/ljharb"
6501
+
}
6502
+
},
2974
6503
"node_modules/esbuild": {
2975
6504
"version": "0.25.9",
2976
6505
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz",
···
3021
6550
"node": ">=6"
3022
6551
}
3023
6552
},
6553
+
"node_modules/escape-string-regexp": {
6554
+
"version": "4.0.0",
6555
+
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
6556
+
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
6557
+
"dev": true,
6558
+
"license": "MIT",
6559
+
"peer": true,
6560
+
"engines": {
6561
+
"node": ">=10"
6562
+
},
6563
+
"funding": {
6564
+
"url": "https://github.com/sponsors/sindresorhus"
6565
+
}
6566
+
},
6567
+
"node_modules/eslint": {
6568
+
"version": "9.37.0",
6569
+
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.37.0.tgz",
6570
+
"integrity": "sha512-XyLmROnACWqSxiGYArdef1fItQd47weqB7iwtfr9JHwRrqIXZdcFMvvEcL9xHCmL0SNsOvF0c42lWyM1U5dgig==",
6571
+
"dev": true,
6572
+
"license": "MIT",
6573
+
"peer": true,
6574
+
"dependencies": {
6575
+
"@eslint-community/eslint-utils": "^4.8.0",
6576
+
"@eslint-community/regexpp": "^4.12.1",
6577
+
"@eslint/config-array": "^0.21.0",
6578
+
"@eslint/config-helpers": "^0.4.0",
6579
+
"@eslint/core": "^0.16.0",
6580
+
"@eslint/eslintrc": "^3.3.1",
6581
+
"@eslint/js": "9.37.0",
6582
+
"@eslint/plugin-kit": "^0.4.0",
6583
+
"@humanfs/node": "^0.16.6",
6584
+
"@humanwhocodes/module-importer": "^1.0.1",
6585
+
"@humanwhocodes/retry": "^0.4.2",
6586
+
"@types/estree": "^1.0.6",
6587
+
"@types/json-schema": "^7.0.15",
6588
+
"ajv": "^6.12.4",
6589
+
"chalk": "^4.0.0",
6590
+
"cross-spawn": "^7.0.6",
6591
+
"debug": "^4.3.2",
6592
+
"escape-string-regexp": "^4.0.0",
6593
+
"eslint-scope": "^8.4.0",
6594
+
"eslint-visitor-keys": "^4.2.1",
6595
+
"espree": "^10.4.0",
6596
+
"esquery": "^1.5.0",
6597
+
"esutils": "^2.0.2",
6598
+
"fast-deep-equal": "^3.1.3",
6599
+
"file-entry-cache": "^8.0.0",
6600
+
"find-up": "^5.0.0",
6601
+
"glob-parent": "^6.0.2",
6602
+
"ignore": "^5.2.0",
6603
+
"imurmurhash": "^0.1.4",
6604
+
"is-glob": "^4.0.0",
6605
+
"json-stable-stringify-without-jsonify": "^1.0.1",
6606
+
"lodash.merge": "^4.6.2",
6607
+
"minimatch": "^3.1.2",
6608
+
"natural-compare": "^1.4.0",
6609
+
"optionator": "^0.9.3"
6610
+
},
6611
+
"bin": {
6612
+
"eslint": "bin/eslint.js"
6613
+
},
6614
+
"engines": {
6615
+
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
6616
+
},
6617
+
"funding": {
6618
+
"url": "https://eslint.org/donate"
6619
+
},
6620
+
"peerDependencies": {
6621
+
"jiti": "*"
6622
+
},
6623
+
"peerDependenciesMeta": {
6624
+
"jiti": {
6625
+
"optional": true
6626
+
}
6627
+
}
6628
+
},
6629
+
"node_modules/eslint-plugin-react": {
6630
+
"version": "7.37.5",
6631
+
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz",
6632
+
"integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==",
6633
+
"dev": true,
6634
+
"license": "MIT",
6635
+
"dependencies": {
6636
+
"array-includes": "^3.1.8",
6637
+
"array.prototype.findlast": "^1.2.5",
6638
+
"array.prototype.flatmap": "^1.3.3",
6639
+
"array.prototype.tosorted": "^1.1.4",
6640
+
"doctrine": "^2.1.0",
6641
+
"es-iterator-helpers": "^1.2.1",
6642
+
"estraverse": "^5.3.0",
6643
+
"hasown": "^2.0.2",
6644
+
"jsx-ast-utils": "^2.4.1 || ^3.0.0",
6645
+
"minimatch": "^3.1.2",
6646
+
"object.entries": "^1.1.9",
6647
+
"object.fromentries": "^2.0.8",
6648
+
"object.values": "^1.2.1",
6649
+
"prop-types": "^15.8.1",
6650
+
"resolve": "^2.0.0-next.5",
6651
+
"semver": "^6.3.1",
6652
+
"string.prototype.matchall": "^4.0.12",
6653
+
"string.prototype.repeat": "^1.0.0"
6654
+
},
6655
+
"engines": {
6656
+
"node": ">=4"
6657
+
},
6658
+
"peerDependencies": {
6659
+
"eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7"
6660
+
}
6661
+
},
6662
+
"node_modules/eslint-plugin-react-dom": {
6663
+
"version": "2.2.1",
6664
+
"resolved": "https://registry.npmjs.org/eslint-plugin-react-dom/-/eslint-plugin-react-dom-2.2.1.tgz",
6665
+
"integrity": "sha512-g6B4yTLHWhgqu3mN0kUJvrQp285uFMQYXzWVAIBqziV6n93sgPH8Eb8ht3gTzRUfA9Rt3JQr8QaxBxpfSkp67w==",
6666
+
"dev": true,
6667
+
"license": "MIT",
6668
+
"dependencies": {
6669
+
"@eslint-react/ast": "2.2.1",
6670
+
"@eslint-react/core": "2.2.1",
6671
+
"@eslint-react/eff": "2.2.1",
6672
+
"@eslint-react/shared": "2.2.1",
6673
+
"@eslint-react/var": "2.2.1",
6674
+
"@typescript-eslint/scope-manager": "^8.46.0",
6675
+
"@typescript-eslint/types": "^8.46.0",
6676
+
"@typescript-eslint/utils": "^8.46.0",
6677
+
"compare-versions": "^6.1.1",
6678
+
"string-ts": "^2.2.1",
6679
+
"ts-pattern": "^5.8.0"
6680
+
},
6681
+
"engines": {
6682
+
"node": ">=20.19.0"
6683
+
},
6684
+
"peerDependencies": {
6685
+
"eslint": "^9.37.0",
6686
+
"typescript": "^5.9.3"
6687
+
}
6688
+
},
6689
+
"node_modules/eslint-plugin-react-hooks": {
6690
+
"version": "7.0.0",
6691
+
"resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.0.0.tgz",
6692
+
"integrity": "sha512-fNXaOwvKwq2+pXiRpXc825Vd63+KM4DLL40Rtlycb8m7fYpp6efrTp1sa6ZbP/Ap58K2bEKFXRmhURE+CJAQWw==",
6693
+
"dev": true,
6694
+
"license": "MIT",
6695
+
"dependencies": {
6696
+
"@babel/core": "^7.24.4",
6697
+
"@babel/parser": "^7.24.4",
6698
+
"hermes-parser": "^0.25.1",
6699
+
"zod": "^3.22.4 || ^4.0.0",
6700
+
"zod-validation-error": "^3.0.3 || ^4.0.0"
6701
+
},
6702
+
"engines": {
6703
+
"node": ">=18"
6704
+
},
6705
+
"peerDependencies": {
6706
+
"eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0"
6707
+
}
6708
+
},
6709
+
"node_modules/eslint-plugin-react-hooks-extra": {
6710
+
"version": "2.2.1",
6711
+
"resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks-extra/-/eslint-plugin-react-hooks-extra-2.2.1.tgz",
6712
+
"integrity": "sha512-MfUbjKIEhF0qEpfXIPgcmmteCx5h9lMuuMGLaau4KmOKh3vewj6DW/JubVuhQ+7eaHqpuCz8/0uBH0k2lfavjg==",
6713
+
"dev": true,
6714
+
"license": "MIT",
6715
+
"dependencies": {
6716
+
"@eslint-react/ast": "2.2.1",
6717
+
"@eslint-react/core": "2.2.1",
6718
+
"@eslint-react/eff": "2.2.1",
6719
+
"@eslint-react/shared": "2.2.1",
6720
+
"@eslint-react/var": "2.2.1",
6721
+
"@typescript-eslint/scope-manager": "^8.46.0",
6722
+
"@typescript-eslint/type-utils": "^8.46.0",
6723
+
"@typescript-eslint/types": "^8.46.0",
6724
+
"@typescript-eslint/utils": "^8.46.0",
6725
+
"string-ts": "^2.2.1",
6726
+
"ts-pattern": "^5.8.0"
6727
+
},
6728
+
"engines": {
6729
+
"node": ">=20.0.0"
6730
+
},
6731
+
"peerDependencies": {
6732
+
"eslint": "^9.37.0",
6733
+
"typescript": "^5.9.3"
6734
+
}
6735
+
},
6736
+
"node_modules/eslint-plugin-react-naming-convention": {
6737
+
"version": "2.2.1",
6738
+
"resolved": "https://registry.npmjs.org/eslint-plugin-react-naming-convention/-/eslint-plugin-react-naming-convention-2.2.1.tgz",
6739
+
"integrity": "sha512-yjNfzPmYAJDFp7yZ4BkmwBRmK3mAGYGXFDyb5Ws2vZBj6R8BKbh5Ao/Chmemo/LmW7a2IoySICuBp6wxuBC9Yg==",
6740
+
"dev": true,
6741
+
"license": "MIT",
6742
+
"dependencies": {
6743
+
"@eslint-react/ast": "2.2.1",
6744
+
"@eslint-react/core": "2.2.1",
6745
+
"@eslint-react/eff": "2.2.1",
6746
+
"@eslint-react/shared": "2.2.1",
6747
+
"@eslint-react/var": "2.2.1",
6748
+
"@typescript-eslint/scope-manager": "^8.46.0",
6749
+
"@typescript-eslint/type-utils": "^8.46.0",
6750
+
"@typescript-eslint/types": "^8.46.0",
6751
+
"@typescript-eslint/utils": "^8.46.0",
6752
+
"string-ts": "^2.2.1",
6753
+
"ts-pattern": "^5.8.0"
6754
+
},
6755
+
"engines": {
6756
+
"node": ">=20.19.0"
6757
+
},
6758
+
"peerDependencies": {
6759
+
"eslint": "^9.37.0",
6760
+
"typescript": "^5.9.3"
6761
+
}
6762
+
},
6763
+
"node_modules/eslint-plugin-react-web-api": {
6764
+
"version": "2.2.1",
6765
+
"resolved": "https://registry.npmjs.org/eslint-plugin-react-web-api/-/eslint-plugin-react-web-api-2.2.1.tgz",
6766
+
"integrity": "sha512-JGRufRDJ8rmckQ82R+3kKhl9ybVeCjRt8fo8/IvxCQJukyyL4Y5b+mOwnPTRDJLQMeDzql4VDeeLegcjweTmAw==",
6767
+
"dev": true,
6768
+
"license": "MIT",
6769
+
"dependencies": {
6770
+
"@eslint-react/ast": "2.2.1",
6771
+
"@eslint-react/core": "2.2.1",
6772
+
"@eslint-react/eff": "2.2.1",
6773
+
"@eslint-react/shared": "2.2.1",
6774
+
"@eslint-react/var": "2.2.1",
6775
+
"@typescript-eslint/scope-manager": "^8.46.0",
6776
+
"@typescript-eslint/types": "^8.46.0",
6777
+
"@typescript-eslint/utils": "^8.46.0",
6778
+
"string-ts": "^2.2.1",
6779
+
"ts-pattern": "^5.8.0"
6780
+
},
6781
+
"engines": {
6782
+
"node": ">=20.19.0"
6783
+
},
6784
+
"peerDependencies": {
6785
+
"eslint": "^9.37.0",
6786
+
"typescript": "^5.9.3"
6787
+
}
6788
+
},
6789
+
"node_modules/eslint-plugin-react-x": {
6790
+
"version": "2.2.1",
6791
+
"resolved": "https://registry.npmjs.org/eslint-plugin-react-x/-/eslint-plugin-react-x-2.2.1.tgz",
6792
+
"integrity": "sha512-Bz5MoLgimALqiJ5O7/KQ/JhZ7AC24qILvA7KHsjT5n0XEQKrktGKGZEm4AKiKsTmboAitpVbHDB9kGpwXIrFXw==",
6793
+
"dev": true,
6794
+
"license": "MIT",
6795
+
"dependencies": {
6796
+
"@eslint-react/ast": "2.2.1",
6797
+
"@eslint-react/core": "2.2.1",
6798
+
"@eslint-react/eff": "2.2.1",
6799
+
"@eslint-react/shared": "2.2.1",
6800
+
"@eslint-react/var": "2.2.1",
6801
+
"@typescript-eslint/scope-manager": "^8.46.0",
6802
+
"@typescript-eslint/type-utils": "^8.46.0",
6803
+
"@typescript-eslint/types": "^8.46.0",
6804
+
"@typescript-eslint/utils": "^8.46.0",
6805
+
"compare-versions": "^6.1.1",
6806
+
"is-immutable-type": "^5.0.1",
6807
+
"string-ts": "^2.2.1",
6808
+
"ts-api-utils": "^2.1.0",
6809
+
"ts-pattern": "^5.8.0"
6810
+
},
6811
+
"engines": {
6812
+
"node": ">=20.19.0"
6813
+
},
6814
+
"peerDependencies": {
6815
+
"eslint": "^9.37.0",
6816
+
"typescript": "^5.9.3"
6817
+
}
6818
+
},
6819
+
"node_modules/eslint-plugin-simple-import-sort": {
6820
+
"version": "12.1.1",
6821
+
"resolved": "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-12.1.1.tgz",
6822
+
"integrity": "sha512-6nuzu4xwQtE3332Uz0to+TxDQYRLTKRESSc2hefVT48Zc8JthmN23Gx9lnYhu0FtkRSL1oxny3kJ2aveVhmOVA==",
6823
+
"dev": true,
6824
+
"license": "MIT",
6825
+
"peerDependencies": {
6826
+
"eslint": ">=5.0.0"
6827
+
}
6828
+
},
6829
+
"node_modules/eslint-plugin-unused-imports": {
6830
+
"version": "4.2.0",
6831
+
"resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-4.2.0.tgz",
6832
+
"integrity": "sha512-hLbJ2/wnjKq4kGA9AUaExVFIbNzyxYdVo49QZmKCnhk5pc9wcYRbfgLHvWJ8tnsdcseGhoUAddm9gn/lt+d74w==",
6833
+
"dev": true,
6834
+
"license": "MIT",
6835
+
"peerDependencies": {
6836
+
"@typescript-eslint/eslint-plugin": "^8.0.0-0 || ^7.0.0 || ^6.0.0 || ^5.0.0",
6837
+
"eslint": "^9.0.0 || ^8.0.0"
6838
+
},
6839
+
"peerDependenciesMeta": {
6840
+
"@typescript-eslint/eslint-plugin": {
6841
+
"optional": true
6842
+
}
6843
+
}
6844
+
},
6845
+
"node_modules/eslint-scope": {
6846
+
"version": "8.4.0",
6847
+
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz",
6848
+
"integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
6849
+
"dev": true,
6850
+
"license": "BSD-2-Clause",
6851
+
"peer": true,
6852
+
"dependencies": {
6853
+
"esrecurse": "^4.3.0",
6854
+
"estraverse": "^5.2.0"
6855
+
},
6856
+
"engines": {
6857
+
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
6858
+
},
6859
+
"funding": {
6860
+
"url": "https://opencollective.com/eslint"
6861
+
}
6862
+
},
6863
+
"node_modules/eslint-visitor-keys": {
6864
+
"version": "4.2.1",
6865
+
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
6866
+
"integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
6867
+
"dev": true,
6868
+
"license": "Apache-2.0",
6869
+
"engines": {
6870
+
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
6871
+
},
6872
+
"funding": {
6873
+
"url": "https://opencollective.com/eslint"
6874
+
}
6875
+
},
6876
+
"node_modules/eslint/node_modules/glob-parent": {
6877
+
"version": "6.0.2",
6878
+
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
6879
+
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
6880
+
"dev": true,
6881
+
"license": "ISC",
6882
+
"peer": true,
6883
+
"dependencies": {
6884
+
"is-glob": "^4.0.3"
6885
+
},
6886
+
"engines": {
6887
+
"node": ">=10.13.0"
6888
+
}
6889
+
},
6890
+
"node_modules/espree": {
6891
+
"version": "10.4.0",
6892
+
"resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
6893
+
"integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
6894
+
"dev": true,
6895
+
"license": "BSD-2-Clause",
6896
+
"peer": true,
6897
+
"dependencies": {
6898
+
"acorn": "^8.15.0",
6899
+
"acorn-jsx": "^5.3.2",
6900
+
"eslint-visitor-keys": "^4.2.1"
6901
+
},
6902
+
"engines": {
6903
+
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
6904
+
},
6905
+
"funding": {
6906
+
"url": "https://opencollective.com/eslint"
6907
+
}
6908
+
},
3024
6909
"node_modules/esprima": {
3025
6910
"version": "4.0.1",
3026
6911
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
···
3034
6919
"node": ">=4"
3035
6920
}
3036
6921
},
6922
+
"node_modules/esquery": {
6923
+
"version": "1.6.0",
6924
+
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
6925
+
"integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",
6926
+
"dev": true,
6927
+
"license": "BSD-3-Clause",
6928
+
"peer": true,
6929
+
"dependencies": {
6930
+
"estraverse": "^5.1.0"
6931
+
},
6932
+
"engines": {
6933
+
"node": ">=0.10"
6934
+
}
6935
+
},
6936
+
"node_modules/esrecurse": {
6937
+
"version": "4.3.0",
6938
+
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
6939
+
"integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
6940
+
"dev": true,
6941
+
"license": "BSD-2-Clause",
6942
+
"peer": true,
6943
+
"dependencies": {
6944
+
"estraverse": "^5.2.0"
6945
+
},
6946
+
"engines": {
6947
+
"node": ">=4.0"
6948
+
}
6949
+
},
6950
+
"node_modules/estraverse": {
6951
+
"version": "5.3.0",
6952
+
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
6953
+
"integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
6954
+
"dev": true,
6955
+
"license": "BSD-2-Clause",
6956
+
"engines": {
6957
+
"node": ">=4.0"
6958
+
}
6959
+
},
3037
6960
"node_modules/estree-walker": {
3038
6961
"version": "3.0.3",
3039
6962
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
···
3044
6967
"@types/estree": "^1.0.0"
3045
6968
}
3046
6969
},
6970
+
"node_modules/esutils": {
6971
+
"version": "2.0.3",
6972
+
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
6973
+
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
6974
+
"dev": true,
6975
+
"license": "BSD-2-Clause",
6976
+
"engines": {
6977
+
"node": ">=0.10.0"
6978
+
}
6979
+
},
6980
+
"node_modules/eventemitter3": {
6981
+
"version": "5.0.1",
6982
+
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz",
6983
+
"integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==",
6984
+
"license": "MIT"
6985
+
},
3047
6986
"node_modules/expect-type": {
3048
6987
"version": "1.2.2",
3049
6988
"resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz",
···
3054
6993
"node": ">=12.0.0"
3055
6994
}
3056
6995
},
6996
+
"node_modules/exsolve": {
6997
+
"version": "1.0.7",
6998
+
"resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.7.tgz",
6999
+
"integrity": "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==",
7000
+
"dev": true,
7001
+
"license": "MIT"
7002
+
},
3057
7003
"node_modules/fast-deep-equal": {
3058
7004
"version": "3.1.3",
3059
7005
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
3060
7006
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
3061
7007
"license": "MIT"
3062
7008
},
7009
+
"node_modules/fast-glob": {
7010
+
"version": "3.3.3",
7011
+
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
7012
+
"integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
7013
+
"dev": true,
7014
+
"license": "MIT",
7015
+
"dependencies": {
7016
+
"@nodelib/fs.stat": "^2.0.2",
7017
+
"@nodelib/fs.walk": "^1.2.3",
7018
+
"glob-parent": "^5.1.2",
7019
+
"merge2": "^1.3.0",
7020
+
"micromatch": "^4.0.8"
7021
+
},
7022
+
"engines": {
7023
+
"node": ">=8.6.0"
7024
+
}
7025
+
},
7026
+
"node_modules/fast-json-stable-stringify": {
7027
+
"version": "2.1.0",
7028
+
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
7029
+
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
7030
+
"dev": true,
7031
+
"license": "MIT",
7032
+
"peer": true
7033
+
},
7034
+
"node_modules/fast-levenshtein": {
7035
+
"version": "2.0.6",
7036
+
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
7037
+
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
7038
+
"dev": true,
7039
+
"license": "MIT",
7040
+
"peer": true
7041
+
},
7042
+
"node_modules/fastq": {
7043
+
"version": "1.19.1",
7044
+
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz",
7045
+
"integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==",
7046
+
"dev": true,
7047
+
"license": "ISC",
7048
+
"dependencies": {
7049
+
"reusify": "^1.0.4"
7050
+
}
7051
+
},
7052
+
"node_modules/file-entry-cache": {
7053
+
"version": "8.0.0",
7054
+
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
7055
+
"integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==",
7056
+
"dev": true,
7057
+
"license": "MIT",
7058
+
"peer": true,
7059
+
"dependencies": {
7060
+
"flat-cache": "^4.0.0"
7061
+
},
7062
+
"engines": {
7063
+
"node": ">=16.0.0"
7064
+
}
7065
+
},
3063
7066
"node_modules/fill-range": {
3064
7067
"version": "7.1.1",
3065
7068
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
···
3072
7075
"node": ">=8"
3073
7076
}
3074
7077
},
7078
+
"node_modules/find-up": {
7079
+
"version": "5.0.0",
7080
+
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
7081
+
"integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
7082
+
"dev": true,
7083
+
"license": "MIT",
7084
+
"peer": true,
7085
+
"dependencies": {
7086
+
"locate-path": "^6.0.0",
7087
+
"path-exists": "^4.0.0"
7088
+
},
7089
+
"engines": {
7090
+
"node": ">=10"
7091
+
},
7092
+
"funding": {
7093
+
"url": "https://github.com/sponsors/sindresorhus"
7094
+
}
7095
+
},
7096
+
"node_modules/flat-cache": {
7097
+
"version": "4.0.1",
7098
+
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
7099
+
"integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==",
7100
+
"dev": true,
7101
+
"license": "MIT",
7102
+
"peer": true,
7103
+
"dependencies": {
7104
+
"flatted": "^3.2.9",
7105
+
"keyv": "^4.5.4"
7106
+
},
7107
+
"engines": {
7108
+
"node": ">=16"
7109
+
}
7110
+
},
7111
+
"node_modules/flatted": {
7112
+
"version": "3.3.3",
7113
+
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
7114
+
"integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
7115
+
"dev": true,
7116
+
"license": "ISC",
7117
+
"peer": true
7118
+
},
7119
+
"node_modules/for-each": {
7120
+
"version": "0.3.5",
7121
+
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
7122
+
"integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==",
7123
+
"dev": true,
7124
+
"license": "MIT",
7125
+
"dependencies": {
7126
+
"is-callable": "^1.2.7"
7127
+
},
7128
+
"engines": {
7129
+
"node": ">= 0.4"
7130
+
},
7131
+
"funding": {
7132
+
"url": "https://github.com/sponsors/ljharb"
7133
+
}
7134
+
},
3075
7135
"node_modules/fsevents": {
3076
7136
"version": "2.3.3",
3077
7137
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
···
3086
7146
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
3087
7147
}
3088
7148
},
7149
+
"node_modules/function-bind": {
7150
+
"version": "1.1.2",
7151
+
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
7152
+
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
7153
+
"dev": true,
7154
+
"license": "MIT",
7155
+
"funding": {
7156
+
"url": "https://github.com/sponsors/ljharb"
7157
+
}
7158
+
},
7159
+
"node_modules/function.prototype.name": {
7160
+
"version": "1.1.8",
7161
+
"resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz",
7162
+
"integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==",
7163
+
"dev": true,
7164
+
"license": "MIT",
7165
+
"dependencies": {
7166
+
"call-bind": "^1.0.8",
7167
+
"call-bound": "^1.0.3",
7168
+
"define-properties": "^1.2.1",
7169
+
"functions-have-names": "^1.2.3",
7170
+
"hasown": "^2.0.2",
7171
+
"is-callable": "^1.2.7"
7172
+
},
7173
+
"engines": {
7174
+
"node": ">= 0.4"
7175
+
},
7176
+
"funding": {
7177
+
"url": "https://github.com/sponsors/ljharb"
7178
+
}
7179
+
},
7180
+
"node_modules/functions-have-names": {
7181
+
"version": "1.2.3",
7182
+
"resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
7183
+
"integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
7184
+
"dev": true,
7185
+
"license": "MIT",
7186
+
"funding": {
7187
+
"url": "https://github.com/sponsors/ljharb"
7188
+
}
7189
+
},
7190
+
"node_modules/generator-function": {
7191
+
"version": "2.0.1",
7192
+
"resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz",
7193
+
"integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==",
7194
+
"dev": true,
7195
+
"license": "MIT",
7196
+
"engines": {
7197
+
"node": ">= 0.4"
7198
+
}
7199
+
},
3089
7200
"node_modules/gensync": {
3090
7201
"version": "1.0.0-beta.2",
3091
7202
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
···
3095
7206
"node": ">=6.9.0"
3096
7207
}
3097
7208
},
7209
+
"node_modules/get-intrinsic": {
7210
+
"version": "1.3.0",
7211
+
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
7212
+
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
7213
+
"dev": true,
7214
+
"license": "MIT",
7215
+
"dependencies": {
7216
+
"call-bind-apply-helpers": "^1.0.2",
7217
+
"es-define-property": "^1.0.1",
7218
+
"es-errors": "^1.3.0",
7219
+
"es-object-atoms": "^1.1.1",
7220
+
"function-bind": "^1.1.2",
7221
+
"get-proto": "^1.0.1",
7222
+
"gopd": "^1.2.0",
7223
+
"has-symbols": "^1.1.0",
7224
+
"hasown": "^2.0.2",
7225
+
"math-intrinsics": "^1.1.0"
7226
+
},
7227
+
"engines": {
7228
+
"node": ">= 0.4"
7229
+
},
7230
+
"funding": {
7231
+
"url": "https://github.com/sponsors/ljharb"
7232
+
}
7233
+
},
7234
+
"node_modules/get-nonce": {
7235
+
"version": "1.0.1",
7236
+
"resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz",
7237
+
"integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==",
7238
+
"engines": {
7239
+
"node": ">=6"
7240
+
}
7241
+
},
7242
+
"node_modules/get-proto": {
7243
+
"version": "1.0.1",
7244
+
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
7245
+
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
7246
+
"dev": true,
7247
+
"license": "MIT",
7248
+
"dependencies": {
7249
+
"dunder-proto": "^1.0.1",
7250
+
"es-object-atoms": "^1.0.0"
7251
+
},
7252
+
"engines": {
7253
+
"node": ">= 0.4"
7254
+
}
7255
+
},
7256
+
"node_modules/get-symbol-description": {
7257
+
"version": "1.1.0",
7258
+
"resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz",
7259
+
"integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==",
7260
+
"dev": true,
7261
+
"license": "MIT",
7262
+
"dependencies": {
7263
+
"call-bound": "^1.0.3",
7264
+
"es-errors": "^1.3.0",
7265
+
"get-intrinsic": "^1.2.6"
7266
+
},
7267
+
"engines": {
7268
+
"node": ">= 0.4"
7269
+
},
7270
+
"funding": {
7271
+
"url": "https://github.com/sponsors/ljharb"
7272
+
}
7273
+
},
3098
7274
"node_modules/get-tsconfig": {
3099
7275
"version": "4.10.1",
3100
7276
"resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz",
···
3119
7295
"node": ">= 6"
3120
7296
}
3121
7297
},
7298
+
"node_modules/globals": {
7299
+
"version": "14.0.0",
7300
+
"resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
7301
+
"integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
7302
+
"dev": true,
7303
+
"license": "MIT",
7304
+
"peer": true,
7305
+
"engines": {
7306
+
"node": ">=18"
7307
+
},
7308
+
"funding": {
7309
+
"url": "https://github.com/sponsors/sindresorhus"
7310
+
}
7311
+
},
7312
+
"node_modules/globalthis": {
7313
+
"version": "1.0.4",
7314
+
"resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
7315
+
"integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
7316
+
"dev": true,
7317
+
"license": "MIT",
7318
+
"dependencies": {
7319
+
"define-properties": "^1.2.1",
7320
+
"gopd": "^1.0.1"
7321
+
},
7322
+
"engines": {
7323
+
"node": ">= 0.4"
7324
+
},
7325
+
"funding": {
7326
+
"url": "https://github.com/sponsors/ljharb"
7327
+
}
7328
+
},
3122
7329
"node_modules/goober": {
3123
7330
"version": "2.1.16",
3124
7331
"resolved": "https://registry.npmjs.org/goober/-/goober-2.1.16.tgz",
···
3128
7335
"csstype": "^3.0.10"
3129
7336
}
3130
7337
},
7338
+
"node_modules/gopd": {
7339
+
"version": "1.2.0",
7340
+
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
7341
+
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
7342
+
"dev": true,
7343
+
"license": "MIT",
7344
+
"engines": {
7345
+
"node": ">= 0.4"
7346
+
},
7347
+
"funding": {
7348
+
"url": "https://github.com/sponsors/ljharb"
7349
+
}
7350
+
},
3131
7351
"node_modules/graceful-fs": {
3132
7352
"version": "4.2.11",
3133
7353
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
···
3140
7360
"integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
3141
7361
"license": "MIT"
3142
7362
},
7363
+
"node_modules/has-bigints": {
7364
+
"version": "1.1.0",
7365
+
"resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz",
7366
+
"integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==",
7367
+
"dev": true,
7368
+
"license": "MIT",
7369
+
"engines": {
7370
+
"node": ">= 0.4"
7371
+
},
7372
+
"funding": {
7373
+
"url": "https://github.com/sponsors/ljharb"
7374
+
}
7375
+
},
7376
+
"node_modules/has-flag": {
7377
+
"version": "4.0.0",
7378
+
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
7379
+
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
7380
+
"dev": true,
7381
+
"license": "MIT",
7382
+
"peer": true,
7383
+
"engines": {
7384
+
"node": ">=8"
7385
+
}
7386
+
},
7387
+
"node_modules/has-property-descriptors": {
7388
+
"version": "1.0.2",
7389
+
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
7390
+
"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
7391
+
"dev": true,
7392
+
"license": "MIT",
7393
+
"dependencies": {
7394
+
"es-define-property": "^1.0.0"
7395
+
},
7396
+
"funding": {
7397
+
"url": "https://github.com/sponsors/ljharb"
7398
+
}
7399
+
},
7400
+
"node_modules/has-proto": {
7401
+
"version": "1.2.0",
7402
+
"resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz",
7403
+
"integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==",
7404
+
"dev": true,
7405
+
"license": "MIT",
7406
+
"dependencies": {
7407
+
"dunder-proto": "^1.0.0"
7408
+
},
7409
+
"engines": {
7410
+
"node": ">= 0.4"
7411
+
},
7412
+
"funding": {
7413
+
"url": "https://github.com/sponsors/ljharb"
7414
+
}
7415
+
},
7416
+
"node_modules/has-symbols": {
7417
+
"version": "1.1.0",
7418
+
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
7419
+
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
7420
+
"dev": true,
7421
+
"license": "MIT",
7422
+
"engines": {
7423
+
"node": ">= 0.4"
7424
+
},
7425
+
"funding": {
7426
+
"url": "https://github.com/sponsors/ljharb"
7427
+
}
7428
+
},
7429
+
"node_modules/has-tostringtag": {
7430
+
"version": "1.0.2",
7431
+
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
7432
+
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
7433
+
"dev": true,
7434
+
"license": "MIT",
7435
+
"dependencies": {
7436
+
"has-symbols": "^1.0.3"
7437
+
},
7438
+
"engines": {
7439
+
"node": ">= 0.4"
7440
+
},
7441
+
"funding": {
7442
+
"url": "https://github.com/sponsors/ljharb"
7443
+
}
7444
+
},
7445
+
"node_modules/hasown": {
7446
+
"version": "2.0.2",
7447
+
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
7448
+
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
7449
+
"dev": true,
7450
+
"license": "MIT",
7451
+
"dependencies": {
7452
+
"function-bind": "^1.1.2"
7453
+
},
7454
+
"engines": {
7455
+
"node": ">= 0.4"
7456
+
}
7457
+
},
7458
+
"node_modules/hermes-estree": {
7459
+
"version": "0.25.1",
7460
+
"resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz",
7461
+
"integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==",
7462
+
"dev": true,
7463
+
"license": "MIT"
7464
+
},
7465
+
"node_modules/hermes-parser": {
7466
+
"version": "0.25.1",
7467
+
"resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz",
7468
+
"integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==",
7469
+
"dev": true,
7470
+
"license": "MIT",
7471
+
"dependencies": {
7472
+
"hermes-estree": "0.25.1"
7473
+
}
7474
+
},
3143
7475
"node_modules/hls-video-element": {
3144
7476
"version": "1.5.7",
3145
7477
"resolved": "https://registry.npmjs.org/hls-video-element/-/hls-video-element-1.5.7.tgz",
···
3214
7546
"node": ">= 14"
3215
7547
}
3216
7548
},
7549
+
"node_modules/i": {
7550
+
"version": "0.3.7",
7551
+
"resolved": "https://registry.npmjs.org/i/-/i-0.3.7.tgz",
7552
+
"integrity": "sha512-FYz4wlXgkQwIPqhzC5TdNMLSE5+GS1IIDJZY/1ZiEPCT2S3COUVZeT5OW4BmW4r5LHLQuOosSwsvnroG9GR59Q==",
7553
+
"engines": {
7554
+
"node": ">=0.4"
7555
+
}
7556
+
},
7557
+
"node_modules/iconify-icon": {
7558
+
"version": "3.0.1",
7559
+
"resolved": "https://registry.npmjs.org/iconify-icon/-/iconify-icon-3.0.1.tgz",
7560
+
"integrity": "sha512-M3/kH3C+e/ufhmQuOSYSb1Ri1ImJ+ZEQYcVRMKnlSc8Nrdoy+iY9YvFnplX8t/3aCRuo5wN4RVPtCSHGnbt8dg==",
7561
+
"dev": true,
7562
+
"license": "MIT",
7563
+
"dependencies": {
7564
+
"@iconify/types": "^2.0.0"
7565
+
},
7566
+
"funding": {
7567
+
"url": "https://github.com/sponsors/cyberalien"
7568
+
}
7569
+
},
3217
7570
"node_modules/iconv-lite": {
3218
7571
"version": "0.6.3",
3219
7572
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
···
3233
7586
"integrity": "sha512-yjD9nARJ/jb1g+CvD0tlhUHOrJ9Sy0P8T9MF3YaLlHnSRpwPfpTX0XIvpmw3gAJUmEu3FiICLBDPXVwyEvrleg==",
3234
7587
"license": "Apache-2.0"
3235
7588
},
7589
+
"node_modules/ignore": {
7590
+
"version": "5.3.2",
7591
+
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
7592
+
"integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
7593
+
"dev": true,
7594
+
"license": "MIT",
7595
+
"peer": true,
7596
+
"engines": {
7597
+
"node": ">= 4"
7598
+
}
7599
+
},
3236
7600
"node_modules/immediate": {
3237
7601
"version": "3.0.6",
3238
7602
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
3239
7603
"integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==",
3240
7604
"license": "MIT"
3241
7605
},
7606
+
"node_modules/import-fresh": {
7607
+
"version": "3.3.1",
7608
+
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
7609
+
"integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
7610
+
"dev": true,
7611
+
"license": "MIT",
7612
+
"dependencies": {
7613
+
"parent-module": "^1.0.0",
7614
+
"resolve-from": "^4.0.0"
7615
+
},
7616
+
"engines": {
7617
+
"node": ">=6"
7618
+
},
7619
+
"funding": {
7620
+
"url": "https://github.com/sponsors/sindresorhus"
7621
+
}
7622
+
},
3242
7623
"node_modules/imsc": {
3243
7624
"version": "1.1.5",
3244
7625
"resolved": "https://registry.npmjs.org/imsc/-/imsc-1.1.5.tgz",
···
3248
7629
"sax": "1.2.1"
3249
7630
}
3250
7631
},
7632
+
"node_modules/imurmurhash": {
7633
+
"version": "0.1.4",
7634
+
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
7635
+
"integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
7636
+
"dev": true,
7637
+
"license": "MIT",
7638
+
"peer": true,
7639
+
"engines": {
7640
+
"node": ">=0.8.19"
7641
+
}
7642
+
},
7643
+
"node_modules/internal-slot": {
7644
+
"version": "1.1.0",
7645
+
"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz",
7646
+
"integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==",
7647
+
"dev": true,
7648
+
"license": "MIT",
7649
+
"dependencies": {
7650
+
"es-errors": "^1.3.0",
7651
+
"hasown": "^2.0.2",
7652
+
"side-channel": "^1.1.0"
7653
+
},
7654
+
"engines": {
7655
+
"node": ">= 0.4"
7656
+
}
7657
+
},
3251
7658
"node_modules/is-alphabetical": {
3252
7659
"version": "2.0.1",
3253
7660
"resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz",
···
3272
7679
"url": "https://github.com/sponsors/wooorm"
3273
7680
}
3274
7681
},
7682
+
"node_modules/is-array-buffer": {
7683
+
"version": "3.0.5",
7684
+
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
7685
+
"integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==",
7686
+
"dev": true,
7687
+
"license": "MIT",
7688
+
"dependencies": {
7689
+
"call-bind": "^1.0.8",
7690
+
"call-bound": "^1.0.3",
7691
+
"get-intrinsic": "^1.2.6"
7692
+
},
7693
+
"engines": {
7694
+
"node": ">= 0.4"
7695
+
},
7696
+
"funding": {
7697
+
"url": "https://github.com/sponsors/ljharb"
7698
+
}
7699
+
},
7700
+
"node_modules/is-arrayish": {
7701
+
"version": "0.2.1",
7702
+
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
7703
+
"integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
7704
+
"dev": true,
7705
+
"license": "MIT"
7706
+
},
7707
+
"node_modules/is-async-function": {
7708
+
"version": "2.1.1",
7709
+
"resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz",
7710
+
"integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==",
7711
+
"dev": true,
7712
+
"license": "MIT",
7713
+
"dependencies": {
7714
+
"async-function": "^1.0.0",
7715
+
"call-bound": "^1.0.3",
7716
+
"get-proto": "^1.0.1",
7717
+
"has-tostringtag": "^1.0.2",
7718
+
"safe-regex-test": "^1.1.0"
7719
+
},
7720
+
"engines": {
7721
+
"node": ">= 0.4"
7722
+
},
7723
+
"funding": {
7724
+
"url": "https://github.com/sponsors/ljharb"
7725
+
}
7726
+
},
7727
+
"node_modules/is-bigint": {
7728
+
"version": "1.1.0",
7729
+
"resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz",
7730
+
"integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==",
7731
+
"dev": true,
7732
+
"license": "MIT",
7733
+
"dependencies": {
7734
+
"has-bigints": "^1.0.2"
7735
+
},
7736
+
"engines": {
7737
+
"node": ">= 0.4"
7738
+
},
7739
+
"funding": {
7740
+
"url": "https://github.com/sponsors/ljharb"
7741
+
}
7742
+
},
3275
7743
"node_modules/is-binary-path": {
3276
7744
"version": "2.1.0",
3277
7745
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
···
3284
7752
"node": ">=8"
3285
7753
}
3286
7754
},
7755
+
"node_modules/is-boolean-object": {
7756
+
"version": "1.2.2",
7757
+
"resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz",
7758
+
"integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==",
7759
+
"dev": true,
7760
+
"license": "MIT",
7761
+
"dependencies": {
7762
+
"call-bound": "^1.0.3",
7763
+
"has-tostringtag": "^1.0.2"
7764
+
},
7765
+
"engines": {
7766
+
"node": ">= 0.4"
7767
+
},
7768
+
"funding": {
7769
+
"url": "https://github.com/sponsors/ljharb"
7770
+
}
7771
+
},
7772
+
"node_modules/is-callable": {
7773
+
"version": "1.2.7",
7774
+
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
7775
+
"integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
7776
+
"dev": true,
7777
+
"license": "MIT",
7778
+
"engines": {
7779
+
"node": ">= 0.4"
7780
+
},
7781
+
"funding": {
7782
+
"url": "https://github.com/sponsors/ljharb"
7783
+
}
7784
+
},
7785
+
"node_modules/is-core-module": {
7786
+
"version": "2.16.1",
7787
+
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
7788
+
"integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
7789
+
"dev": true,
7790
+
"license": "MIT",
7791
+
"dependencies": {
7792
+
"hasown": "^2.0.2"
7793
+
},
7794
+
"engines": {
7795
+
"node": ">= 0.4"
7796
+
},
7797
+
"funding": {
7798
+
"url": "https://github.com/sponsors/ljharb"
7799
+
}
7800
+
},
7801
+
"node_modules/is-data-view": {
7802
+
"version": "1.0.2",
7803
+
"resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz",
7804
+
"integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==",
7805
+
"dev": true,
7806
+
"license": "MIT",
7807
+
"dependencies": {
7808
+
"call-bound": "^1.0.2",
7809
+
"get-intrinsic": "^1.2.6",
7810
+
"is-typed-array": "^1.1.13"
7811
+
},
7812
+
"engines": {
7813
+
"node": ">= 0.4"
7814
+
},
7815
+
"funding": {
7816
+
"url": "https://github.com/sponsors/ljharb"
7817
+
}
7818
+
},
7819
+
"node_modules/is-date-object": {
7820
+
"version": "1.1.0",
7821
+
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz",
7822
+
"integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==",
7823
+
"dev": true,
7824
+
"license": "MIT",
7825
+
"dependencies": {
7826
+
"call-bound": "^1.0.2",
7827
+
"has-tostringtag": "^1.0.2"
7828
+
},
7829
+
"engines": {
7830
+
"node": ">= 0.4"
7831
+
},
7832
+
"funding": {
7833
+
"url": "https://github.com/sponsors/ljharb"
7834
+
}
7835
+
},
3287
7836
"node_modules/is-decimal": {
3288
7837
"version": "2.0.1",
3289
7838
"resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz",
···
3303
7852
"node": ">=0.10.0"
3304
7853
}
3305
7854
},
7855
+
"node_modules/is-finalizationregistry": {
7856
+
"version": "1.1.1",
7857
+
"resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz",
7858
+
"integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==",
7859
+
"dev": true,
7860
+
"license": "MIT",
7861
+
"dependencies": {
7862
+
"call-bound": "^1.0.3"
7863
+
},
7864
+
"engines": {
7865
+
"node": ">= 0.4"
7866
+
},
7867
+
"funding": {
7868
+
"url": "https://github.com/sponsors/ljharb"
7869
+
}
7870
+
},
7871
+
"node_modules/is-generator-function": {
7872
+
"version": "1.1.2",
7873
+
"resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz",
7874
+
"integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==",
7875
+
"dev": true,
7876
+
"license": "MIT",
7877
+
"dependencies": {
7878
+
"call-bound": "^1.0.4",
7879
+
"generator-function": "^2.0.0",
7880
+
"get-proto": "^1.0.1",
7881
+
"has-tostringtag": "^1.0.2",
7882
+
"safe-regex-test": "^1.1.0"
7883
+
},
7884
+
"engines": {
7885
+
"node": ">= 0.4"
7886
+
},
7887
+
"funding": {
7888
+
"url": "https://github.com/sponsors/ljharb"
7889
+
}
7890
+
},
3306
7891
"node_modules/is-glob": {
3307
7892
"version": "4.0.3",
3308
7893
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
···
3315
7900
"node": ">=0.10.0"
3316
7901
}
3317
7902
},
7903
+
"node_modules/is-immutable-type": {
7904
+
"version": "5.0.1",
7905
+
"resolved": "https://registry.npmjs.org/is-immutable-type/-/is-immutable-type-5.0.1.tgz",
7906
+
"integrity": "sha512-LkHEOGVZZXxGl8vDs+10k3DvP++SEoYEAJLRk6buTFi6kD7QekThV7xHS0j6gpnUCQ0zpud/gMDGiV4dQneLTg==",
7907
+
"dev": true,
7908
+
"license": "BSD-3-Clause",
7909
+
"dependencies": {
7910
+
"@typescript-eslint/type-utils": "^8.0.0",
7911
+
"ts-api-utils": "^2.0.0",
7912
+
"ts-declaration-location": "^1.0.4"
7913
+
},
7914
+
"peerDependencies": {
7915
+
"eslint": "*",
7916
+
"typescript": ">=4.7.4"
7917
+
}
7918
+
},
7919
+
"node_modules/is-map": {
7920
+
"version": "2.0.3",
7921
+
"resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz",
7922
+
"integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==",
7923
+
"dev": true,
7924
+
"license": "MIT",
7925
+
"engines": {
7926
+
"node": ">= 0.4"
7927
+
},
7928
+
"funding": {
7929
+
"url": "https://github.com/sponsors/ljharb"
7930
+
}
7931
+
},
7932
+
"node_modules/is-negative-zero": {
7933
+
"version": "2.0.3",
7934
+
"resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz",
7935
+
"integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==",
7936
+
"dev": true,
7937
+
"license": "MIT",
7938
+
"engines": {
7939
+
"node": ">= 0.4"
7940
+
},
7941
+
"funding": {
7942
+
"url": "https://github.com/sponsors/ljharb"
7943
+
}
7944
+
},
3318
7945
"node_modules/is-number": {
3319
7946
"version": "7.0.0",
3320
7947
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
···
3324
7951
"node": ">=0.12.0"
3325
7952
}
3326
7953
},
7954
+
"node_modules/is-number-object": {
7955
+
"version": "1.1.1",
7956
+
"resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz",
7957
+
"integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==",
7958
+
"dev": true,
7959
+
"license": "MIT",
7960
+
"dependencies": {
7961
+
"call-bound": "^1.0.3",
7962
+
"has-tostringtag": "^1.0.2"
7963
+
},
7964
+
"engines": {
7965
+
"node": ">= 0.4"
7966
+
},
7967
+
"funding": {
7968
+
"url": "https://github.com/sponsors/ljharb"
7969
+
}
7970
+
},
3327
7971
"node_modules/is-potential-custom-element-name": {
3328
7972
"version": "1.0.1",
3329
7973
"resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
···
3331
7975
"dev": true,
3332
7976
"license": "MIT"
3333
7977
},
7978
+
"node_modules/is-regex": {
7979
+
"version": "1.2.1",
7980
+
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
7981
+
"integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==",
7982
+
"dev": true,
7983
+
"license": "MIT",
7984
+
"dependencies": {
7985
+
"call-bound": "^1.0.2",
7986
+
"gopd": "^1.2.0",
7987
+
"has-tostringtag": "^1.0.2",
7988
+
"hasown": "^2.0.2"
7989
+
},
7990
+
"engines": {
7991
+
"node": ">= 0.4"
7992
+
},
7993
+
"funding": {
7994
+
"url": "https://github.com/sponsors/ljharb"
7995
+
}
7996
+
},
7997
+
"node_modules/is-set": {
7998
+
"version": "2.0.3",
7999
+
"resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz",
8000
+
"integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==",
8001
+
"dev": true,
8002
+
"license": "MIT",
8003
+
"engines": {
8004
+
"node": ">= 0.4"
8005
+
},
8006
+
"funding": {
8007
+
"url": "https://github.com/sponsors/ljharb"
8008
+
}
8009
+
},
8010
+
"node_modules/is-shared-array-buffer": {
8011
+
"version": "1.0.4",
8012
+
"resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz",
8013
+
"integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==",
8014
+
"dev": true,
8015
+
"license": "MIT",
8016
+
"dependencies": {
8017
+
"call-bound": "^1.0.3"
8018
+
},
8019
+
"engines": {
8020
+
"node": ">= 0.4"
8021
+
},
8022
+
"funding": {
8023
+
"url": "https://github.com/sponsors/ljharb"
8024
+
}
8025
+
},
8026
+
"node_modules/is-string": {
8027
+
"version": "1.1.1",
8028
+
"resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz",
8029
+
"integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==",
8030
+
"dev": true,
8031
+
"license": "MIT",
8032
+
"dependencies": {
8033
+
"call-bound": "^1.0.3",
8034
+
"has-tostringtag": "^1.0.2"
8035
+
},
8036
+
"engines": {
8037
+
"node": ">= 0.4"
8038
+
},
8039
+
"funding": {
8040
+
"url": "https://github.com/sponsors/ljharb"
8041
+
}
8042
+
},
8043
+
"node_modules/is-symbol": {
8044
+
"version": "1.1.1",
8045
+
"resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz",
8046
+
"integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==",
8047
+
"dev": true,
8048
+
"license": "MIT",
8049
+
"dependencies": {
8050
+
"call-bound": "^1.0.2",
8051
+
"has-symbols": "^1.1.0",
8052
+
"safe-regex-test": "^1.1.0"
8053
+
},
8054
+
"engines": {
8055
+
"node": ">= 0.4"
8056
+
},
8057
+
"funding": {
8058
+
"url": "https://github.com/sponsors/ljharb"
8059
+
}
8060
+
},
8061
+
"node_modules/is-typed-array": {
8062
+
"version": "1.1.15",
8063
+
"resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz",
8064
+
"integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==",
8065
+
"dev": true,
8066
+
"license": "MIT",
8067
+
"dependencies": {
8068
+
"which-typed-array": "^1.1.16"
8069
+
},
8070
+
"engines": {
8071
+
"node": ">= 0.4"
8072
+
},
8073
+
"funding": {
8074
+
"url": "https://github.com/sponsors/ljharb"
8075
+
}
8076
+
},
8077
+
"node_modules/is-weakmap": {
8078
+
"version": "2.0.2",
8079
+
"resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz",
8080
+
"integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==",
8081
+
"dev": true,
8082
+
"license": "MIT",
8083
+
"engines": {
8084
+
"node": ">= 0.4"
8085
+
},
8086
+
"funding": {
8087
+
"url": "https://github.com/sponsors/ljharb"
8088
+
}
8089
+
},
8090
+
"node_modules/is-weakref": {
8091
+
"version": "1.1.1",
8092
+
"resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz",
8093
+
"integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==",
8094
+
"dev": true,
8095
+
"license": "MIT",
8096
+
"dependencies": {
8097
+
"call-bound": "^1.0.3"
8098
+
},
8099
+
"engines": {
8100
+
"node": ">= 0.4"
8101
+
},
8102
+
"funding": {
8103
+
"url": "https://github.com/sponsors/ljharb"
8104
+
}
8105
+
},
8106
+
"node_modules/is-weakset": {
8107
+
"version": "2.0.4",
8108
+
"resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz",
8109
+
"integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==",
8110
+
"dev": true,
8111
+
"license": "MIT",
8112
+
"dependencies": {
8113
+
"call-bound": "^1.0.3",
8114
+
"get-intrinsic": "^1.2.6"
8115
+
},
8116
+
"engines": {
8117
+
"node": ">= 0.4"
8118
+
},
8119
+
"funding": {
8120
+
"url": "https://github.com/sponsors/ljharb"
8121
+
}
8122
+
},
8123
+
"node_modules/isarray": {
8124
+
"version": "2.0.5",
8125
+
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
8126
+
"integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
8127
+
"dev": true,
8128
+
"license": "MIT"
8129
+
},
3334
8130
"node_modules/isbot": {
3335
8131
"version": "5.1.30",
3336
8132
"resolved": "https://registry.npmjs.org/isbot/-/isbot-5.1.30.tgz",
···
3340
8136
"node": ">=18"
3341
8137
}
3342
8138
},
8139
+
"node_modules/isexe": {
8140
+
"version": "2.0.0",
8141
+
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
8142
+
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
8143
+
"dev": true,
8144
+
"license": "ISC",
8145
+
"peer": true
8146
+
},
3343
8147
"node_modules/iso-datestring-validator": {
3344
8148
"version": "2.2.2",
3345
8149
"resolved": "https://registry.npmjs.org/iso-datestring-validator/-/iso-datestring-validator-2.2.2.tgz",
3346
8150
"integrity": "sha512-yLEMkBbLZTlVQqOnQ4FiMujR6T4DEcCb1xizmvXS+OxuhwcbtynoosRzdMA69zZCShCNAbi+gJ71FxZBBXx1SA==",
3347
8151
"license": "MIT"
3348
8152
},
8153
+
"node_modules/iterator.prototype": {
8154
+
"version": "1.1.5",
8155
+
"resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz",
8156
+
"integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==",
8157
+
"dev": true,
8158
+
"license": "MIT",
8159
+
"dependencies": {
8160
+
"define-data-property": "^1.1.4",
8161
+
"es-object-atoms": "^1.0.0",
8162
+
"get-intrinsic": "^1.2.6",
8163
+
"get-proto": "^1.0.0",
8164
+
"has-symbols": "^1.1.0",
8165
+
"set-function-name": "^2.0.2"
8166
+
},
8167
+
"engines": {
8168
+
"node": ">= 0.4"
8169
+
}
8170
+
},
3349
8171
"node_modules/jiti": {
3350
8172
"version": "2.5.1",
3351
8173
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz",
···
3355
8177
"jiti": "lib/jiti-cli.mjs"
3356
8178
}
3357
8179
},
8180
+
"node_modules/jose": {
8181
+
"version": "5.10.0",
8182
+
"resolved": "https://registry.npmjs.org/jose/-/jose-5.10.0.tgz",
8183
+
"integrity": "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==",
8184
+
"license": "MIT",
8185
+
"funding": {
8186
+
"url": "https://github.com/sponsors/panva"
8187
+
}
8188
+
},
8189
+
"node_modules/jotai": {
8190
+
"version": "2.13.1",
8191
+
"resolved": "https://registry.npmjs.org/jotai/-/jotai-2.13.1.tgz",
8192
+
"integrity": "sha512-cRsw6kFeGC9Z/D3egVKrTXRweycZ4z/k7i2MrfCzPYsL9SIWcPXTyqv258/+Ay8VUEcihNiE/coBLE6Kic6b8A==",
8193
+
"license": "MIT",
8194
+
"engines": {
8195
+
"node": ">=12.20.0"
8196
+
},
8197
+
"peerDependencies": {
8198
+
"@babel/core": ">=7.0.0",
8199
+
"@babel/template": ">=7.0.0",
8200
+
"@types/react": ">=17.0.0",
8201
+
"react": ">=17.0.0"
8202
+
},
8203
+
"peerDependenciesMeta": {
8204
+
"@babel/core": {
8205
+
"optional": true
8206
+
},
8207
+
"@babel/template": {
8208
+
"optional": true
8209
+
},
8210
+
"@types/react": {
8211
+
"optional": true
8212
+
},
8213
+
"react": {
8214
+
"optional": true
8215
+
}
8216
+
}
8217
+
},
3358
8218
"node_modules/js-tokens": {
3359
8219
"version": "4.0.0",
3360
8220
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
3361
8221
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
3362
8222
"license": "MIT"
8223
+
},
8224
+
"node_modules/js-yaml": {
8225
+
"version": "4.1.0",
8226
+
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
8227
+
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
8228
+
"dev": true,
8229
+
"license": "MIT",
8230
+
"dependencies": {
8231
+
"argparse": "^2.0.1"
8232
+
},
8233
+
"bin": {
8234
+
"js-yaml": "bin/js-yaml.js"
8235
+
}
3363
8236
},
3364
8237
"node_modules/jsdom": {
3365
8238
"version": "26.1.0",
···
3413
8286
"node": ">=6"
3414
8287
}
3415
8288
},
8289
+
"node_modules/json-buffer": {
8290
+
"version": "3.0.1",
8291
+
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
8292
+
"integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
8293
+
"dev": true,
8294
+
"license": "MIT",
8295
+
"peer": true
8296
+
},
8297
+
"node_modules/json-parse-even-better-errors": {
8298
+
"version": "2.3.1",
8299
+
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
8300
+
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
8301
+
"dev": true,
8302
+
"license": "MIT"
8303
+
},
8304
+
"node_modules/json-schema-traverse": {
8305
+
"version": "0.4.1",
8306
+
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
8307
+
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
8308
+
"dev": true,
8309
+
"license": "MIT",
8310
+
"peer": true
8311
+
},
8312
+
"node_modules/json-stable-stringify-without-jsonify": {
8313
+
"version": "1.0.1",
8314
+
"resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
8315
+
"integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
8316
+
"dev": true,
8317
+
"license": "MIT",
8318
+
"peer": true
8319
+
},
3416
8320
"node_modules/json5": {
3417
8321
"version": "2.2.3",
3418
8322
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
···
3423
8327
},
3424
8328
"engines": {
3425
8329
"node": ">=6"
8330
+
}
8331
+
},
8332
+
"node_modules/jsx-ast-utils": {
8333
+
"version": "3.3.5",
8334
+
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
8335
+
"integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==",
8336
+
"dev": true,
8337
+
"license": "MIT",
8338
+
"dependencies": {
8339
+
"array-includes": "^3.1.6",
8340
+
"array.prototype.flat": "^1.3.1",
8341
+
"object.assign": "^4.1.4",
8342
+
"object.values": "^1.1.6"
8343
+
},
8344
+
"engines": {
8345
+
"node": ">=4.0"
8346
+
}
8347
+
},
8348
+
"node_modules/keyv": {
8349
+
"version": "4.5.4",
8350
+
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
8351
+
"integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
8352
+
"dev": true,
8353
+
"license": "MIT",
8354
+
"peer": true,
8355
+
"dependencies": {
8356
+
"json-buffer": "3.0.1"
8357
+
}
8358
+
},
8359
+
"node_modules/kolorist": {
8360
+
"version": "1.8.0",
8361
+
"resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz",
8362
+
"integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==",
8363
+
"dev": true,
8364
+
"license": "MIT"
8365
+
},
8366
+
"node_modules/levn": {
8367
+
"version": "0.4.1",
8368
+
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
8369
+
"integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
8370
+
"dev": true,
8371
+
"license": "MIT",
8372
+
"peer": true,
8373
+
"dependencies": {
8374
+
"prelude-ls": "^1.2.1",
8375
+
"type-check": "~0.4.0"
8376
+
},
8377
+
"engines": {
8378
+
"node": ">= 0.8.0"
3426
8379
}
3427
8380
},
3428
8381
"node_modules/lie": {
···
3662
8615
"url": "https://opencollective.com/parcel"
3663
8616
}
3664
8617
},
8618
+
"node_modules/lines-and-columns": {
8619
+
"version": "1.2.4",
8620
+
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
8621
+
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
8622
+
"dev": true,
8623
+
"license": "MIT"
8624
+
},
8625
+
"node_modules/local-pkg": {
8626
+
"version": "1.1.2",
8627
+
"resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.1.2.tgz",
8628
+
"integrity": "sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==",
8629
+
"dev": true,
8630
+
"license": "MIT",
8631
+
"dependencies": {
8632
+
"mlly": "^1.7.4",
8633
+
"pkg-types": "^2.3.0",
8634
+
"quansync": "^0.2.11"
8635
+
},
8636
+
"engines": {
8637
+
"node": ">=14"
8638
+
},
8639
+
"funding": {
8640
+
"url": "https://github.com/sponsors/antfu"
8641
+
}
8642
+
},
3665
8643
"node_modules/localforage": {
3666
8644
"version": "1.10.0",
3667
8645
"resolved": "https://registry.npmjs.org/localforage/-/localforage-1.10.0.tgz",
···
3671
8649
"lie": "3.1.1"
3672
8650
}
3673
8651
},
8652
+
"node_modules/locate-path": {
8653
+
"version": "6.0.0",
8654
+
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
8655
+
"integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
8656
+
"dev": true,
8657
+
"license": "MIT",
8658
+
"peer": true,
8659
+
"dependencies": {
8660
+
"p-locate": "^5.0.0"
8661
+
},
8662
+
"engines": {
8663
+
"node": ">=10"
8664
+
},
8665
+
"funding": {
8666
+
"url": "https://github.com/sponsors/sindresorhus"
8667
+
}
8668
+
},
8669
+
"node_modules/lodash.clonedeep": {
8670
+
"version": "4.5.0",
8671
+
"resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
8672
+
"integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==",
8673
+
"license": "MIT"
8674
+
},
8675
+
"node_modules/lodash.merge": {
8676
+
"version": "4.6.2",
8677
+
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
8678
+
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
8679
+
"dev": true,
8680
+
"license": "MIT",
8681
+
"peer": true
8682
+
},
3674
8683
"node_modules/loose-envify": {
3675
8684
"version": "1.4.0",
3676
8685
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
···
3690
8699
"dev": true,
3691
8700
"license": "MIT"
3692
8701
},
8702
+
"node_modules/lower-case": {
8703
+
"version": "2.0.2",
8704
+
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
8705
+
"integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==",
8706
+
"dev": true,
8707
+
"license": "MIT",
8708
+
"dependencies": {
8709
+
"tslib": "^2.0.3"
8710
+
}
8711
+
},
3693
8712
"node_modules/lru-cache": {
3694
8713
"version": "5.1.1",
3695
8714
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
···
3710
8729
}
3711
8730
},
3712
8731
"node_modules/magic-string": {
3713
-
"version": "0.30.18",
3714
-
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.18.tgz",
3715
-
"integrity": "sha512-yi8swmWbO17qHhwIBNeeZxTceJMeBvWJaId6dyvTSOwTipqeHhMhOrz6513r1sOKnpvQ7zkhlG8tPrpilwTxHQ==",
8732
+
"version": "0.30.19",
8733
+
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz",
8734
+
"integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==",
3716
8735
"license": "MIT",
3717
8736
"dependencies": {
3718
8737
"@jridgewell/sourcemap-codec": "^1.5.5"
3719
8738
}
3720
8739
},
8740
+
"node_modules/math-intrinsics": {
8741
+
"version": "1.1.0",
8742
+
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
8743
+
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
8744
+
"dev": true,
8745
+
"license": "MIT",
8746
+
"engines": {
8747
+
"node": ">= 0.4"
8748
+
}
8749
+
},
3721
8750
"node_modules/media-chrome": {
3722
8751
"version": "4.11.1",
3723
8752
"resolved": "https://registry.npmjs.org/media-chrome/-/media-chrome-4.11.1.tgz",
···
3734
8763
"integrity": "sha512-9P2FuUHnZZ3iji+2RQk7Zkh5AmZTnOG5fODACnjhCVveX1McY3jmCRHofIEI+yTBqplz7LXy48c7fQ3Uigp88w==",
3735
8764
"license": "MIT"
3736
8765
},
8766
+
"node_modules/merge2": {
8767
+
"version": "1.4.1",
8768
+
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
8769
+
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
8770
+
"dev": true,
8771
+
"license": "MIT",
8772
+
"engines": {
8773
+
"node": ">= 8"
8774
+
}
8775
+
},
8776
+
"node_modules/micromatch": {
8777
+
"version": "4.0.8",
8778
+
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
8779
+
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
8780
+
"dev": true,
8781
+
"license": "MIT",
8782
+
"dependencies": {
8783
+
"braces": "^3.0.3",
8784
+
"picomatch": "^2.3.1"
8785
+
},
8786
+
"engines": {
8787
+
"node": ">=8.6"
8788
+
}
8789
+
},
8790
+
"node_modules/minimatch": {
8791
+
"version": "3.1.2",
8792
+
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
8793
+
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
8794
+
"dev": true,
8795
+
"license": "ISC",
8796
+
"dependencies": {
8797
+
"brace-expansion": "^1.1.7"
8798
+
},
8799
+
"engines": {
8800
+
"node": "*"
8801
+
}
8802
+
},
3737
8803
"node_modules/minipass": {
3738
8804
"version": "7.1.2",
3739
8805
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
···
3770
8836
"url": "https://github.com/sponsors/isaacs"
3771
8837
}
3772
8838
},
8839
+
"node_modules/mlly": {
8840
+
"version": "1.8.0",
8841
+
"resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz",
8842
+
"integrity": "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==",
8843
+
"dev": true,
8844
+
"license": "MIT",
8845
+
"dependencies": {
8846
+
"acorn": "^8.15.0",
8847
+
"pathe": "^2.0.3",
8848
+
"pkg-types": "^1.3.1",
8849
+
"ufo": "^1.6.1"
8850
+
}
8851
+
},
8852
+
"node_modules/mlly/node_modules/confbox": {
8853
+
"version": "0.1.8",
8854
+
"resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz",
8855
+
"integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==",
8856
+
"dev": true,
8857
+
"license": "MIT"
8858
+
},
8859
+
"node_modules/mlly/node_modules/pkg-types": {
8860
+
"version": "1.3.1",
8861
+
"resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz",
8862
+
"integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==",
8863
+
"dev": true,
8864
+
"license": "MIT",
8865
+
"dependencies": {
8866
+
"confbox": "^0.1.8",
8867
+
"mlly": "^1.7.4",
8868
+
"pathe": "^2.0.1"
8869
+
}
8870
+
},
3773
8871
"node_modules/ms": {
3774
8872
"version": "2.1.3",
3775
8873
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
···
3812
8910
"integrity": "sha512-zkVhZUA3y8mbz652WrL5x0fB0ehrBkulWT3TomAQ9iDtyXZvzKeEA6GPxAItBYeNYl5yngKRX612qHOhvMkDeg==",
3813
8911
"license": "MIT"
3814
8912
},
8913
+
"node_modules/natural-compare": {
8914
+
"version": "1.4.0",
8915
+
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
8916
+
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
8917
+
"dev": true,
8918
+
"license": "MIT"
8919
+
},
8920
+
"node_modules/no-case": {
8921
+
"version": "3.0.4",
8922
+
"resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz",
8923
+
"integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==",
8924
+
"dev": true,
8925
+
"license": "MIT",
8926
+
"dependencies": {
8927
+
"lower-case": "^2.0.2",
8928
+
"tslib": "^2.0.3"
8929
+
}
8930
+
},
3815
8931
"node_modules/node-releases": {
3816
8932
"version": "2.0.19",
3817
8933
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
···
3827
8943
"node": ">=0.10.0"
3828
8944
}
3829
8945
},
8946
+
"node_modules/npm": {
8947
+
"version": "11.6.2",
8948
+
"resolved": "https://registry.npmjs.org/npm/-/npm-11.6.2.tgz",
8949
+
"integrity": "sha512-7iKzNfy8lWYs3zq4oFPa8EXZz5xt9gQNKJZau3B1ErLBb6bF7sBJ00x09485DOvRT2l5Gerbl3VlZNT57MxJVA==",
8950
+
"bundleDependencies": [
8951
+
"@isaacs/string-locale-compare",
8952
+
"@npmcli/arborist",
8953
+
"@npmcli/config",
8954
+
"@npmcli/fs",
8955
+
"@npmcli/map-workspaces",
8956
+
"@npmcli/package-json",
8957
+
"@npmcli/promise-spawn",
8958
+
"@npmcli/redact",
8959
+
"@npmcli/run-script",
8960
+
"@sigstore/tuf",
8961
+
"abbrev",
8962
+
"archy",
8963
+
"cacache",
8964
+
"chalk",
8965
+
"ci-info",
8966
+
"cli-columns",
8967
+
"fastest-levenshtein",
8968
+
"fs-minipass",
8969
+
"glob",
8970
+
"graceful-fs",
8971
+
"hosted-git-info",
8972
+
"ini",
8973
+
"init-package-json",
8974
+
"is-cidr",
8975
+
"json-parse-even-better-errors",
8976
+
"libnpmaccess",
8977
+
"libnpmdiff",
8978
+
"libnpmexec",
8979
+
"libnpmfund",
8980
+
"libnpmorg",
8981
+
"libnpmpack",
8982
+
"libnpmpublish",
8983
+
"libnpmsearch",
8984
+
"libnpmteam",
8985
+
"libnpmversion",
8986
+
"make-fetch-happen",
8987
+
"minimatch",
8988
+
"minipass",
8989
+
"minipass-pipeline",
8990
+
"ms",
8991
+
"node-gyp",
8992
+
"nopt",
8993
+
"npm-audit-report",
8994
+
"npm-install-checks",
8995
+
"npm-package-arg",
8996
+
"npm-pick-manifest",
8997
+
"npm-profile",
8998
+
"npm-registry-fetch",
8999
+
"npm-user-validate",
9000
+
"p-map",
9001
+
"pacote",
9002
+
"parse-conflict-json",
9003
+
"proc-log",
9004
+
"qrcode-terminal",
9005
+
"read",
9006
+
"semver",
9007
+
"spdx-expression-parse",
9008
+
"ssri",
9009
+
"supports-color",
9010
+
"tar",
9011
+
"text-table",
9012
+
"tiny-relative-date",
9013
+
"treeverse",
9014
+
"validate-npm-package-name",
9015
+
"which"
9016
+
],
9017
+
"license": "Artistic-2.0",
9018
+
"workspaces": [
9019
+
"docs",
9020
+
"smoke-tests",
9021
+
"mock-globals",
9022
+
"mock-registry",
9023
+
"workspaces/*"
9024
+
],
9025
+
"dependencies": {
9026
+
"@isaacs/string-locale-compare": "^1.1.0",
9027
+
"@npmcli/arborist": "^9.1.6",
9028
+
"@npmcli/config": "^10.4.2",
9029
+
"@npmcli/fs": "^4.0.0",
9030
+
"@npmcli/map-workspaces": "^5.0.0",
9031
+
"@npmcli/package-json": "^7.0.1",
9032
+
"@npmcli/promise-spawn": "^8.0.3",
9033
+
"@npmcli/redact": "^3.2.2",
9034
+
"@npmcli/run-script": "^10.0.0",
9035
+
"@sigstore/tuf": "^4.0.0",
9036
+
"abbrev": "^3.0.1",
9037
+
"archy": "~1.0.0",
9038
+
"cacache": "^20.0.1",
9039
+
"chalk": "^5.6.2",
9040
+
"ci-info": "^4.3.1",
9041
+
"cli-columns": "^4.0.0",
9042
+
"fastest-levenshtein": "^1.0.16",
9043
+
"fs-minipass": "^3.0.3",
9044
+
"glob": "^11.0.3",
9045
+
"graceful-fs": "^4.2.11",
9046
+
"hosted-git-info": "^9.0.2",
9047
+
"ini": "^5.0.0",
9048
+
"init-package-json": "^8.2.2",
9049
+
"is-cidr": "^6.0.1",
9050
+
"json-parse-even-better-errors": "^4.0.0",
9051
+
"libnpmaccess": "^10.0.3",
9052
+
"libnpmdiff": "^8.0.9",
9053
+
"libnpmexec": "^10.1.8",
9054
+
"libnpmfund": "^7.0.9",
9055
+
"libnpmorg": "^8.0.1",
9056
+
"libnpmpack": "^9.0.9",
9057
+
"libnpmpublish": "^11.1.2",
9058
+
"libnpmsearch": "^9.0.1",
9059
+
"libnpmteam": "^8.0.2",
9060
+
"libnpmversion": "^8.0.2",
9061
+
"make-fetch-happen": "^15.0.2",
9062
+
"minimatch": "^10.0.3",
9063
+
"minipass": "^7.1.1",
9064
+
"minipass-pipeline": "^1.2.4",
9065
+
"ms": "^2.1.2",
9066
+
"node-gyp": "^11.4.2",
9067
+
"nopt": "^8.1.0",
9068
+
"npm-audit-report": "^6.0.0",
9069
+
"npm-install-checks": "^7.1.2",
9070
+
"npm-package-arg": "^13.0.1",
9071
+
"npm-pick-manifest": "^11.0.1",
9072
+
"npm-profile": "^12.0.0",
9073
+
"npm-registry-fetch": "^19.0.0",
9074
+
"npm-user-validate": "^3.0.0",
9075
+
"p-map": "^7.0.3",
9076
+
"pacote": "^21.0.3",
9077
+
"parse-conflict-json": "^4.0.0",
9078
+
"proc-log": "^5.0.0",
9079
+
"qrcode-terminal": "^0.12.0",
9080
+
"read": "^4.1.0",
9081
+
"semver": "^7.7.3",
9082
+
"spdx-expression-parse": "^4.0.0",
9083
+
"ssri": "^12.0.0",
9084
+
"supports-color": "^10.2.2",
9085
+
"tar": "^7.5.1",
9086
+
"text-table": "~0.2.0",
9087
+
"tiny-relative-date": "^2.0.2",
9088
+
"treeverse": "^3.0.0",
9089
+
"validate-npm-package-name": "^6.0.2",
9090
+
"which": "^5.0.0"
9091
+
},
9092
+
"bin": {
9093
+
"npm": "bin/npm-cli.js",
9094
+
"npx": "bin/npx-cli.js"
9095
+
},
9096
+
"engines": {
9097
+
"node": "^20.17.0 || >=22.9.0"
9098
+
}
9099
+
},
9100
+
"node_modules/npm/node_modules/@isaacs/balanced-match": {
9101
+
"version": "4.0.1",
9102
+
"inBundle": true,
9103
+
"license": "MIT",
9104
+
"engines": {
9105
+
"node": "20 || >=22"
9106
+
}
9107
+
},
9108
+
"node_modules/npm/node_modules/@isaacs/brace-expansion": {
9109
+
"version": "5.0.0",
9110
+
"inBundle": true,
9111
+
"license": "MIT",
9112
+
"dependencies": {
9113
+
"@isaacs/balanced-match": "^4.0.1"
9114
+
},
9115
+
"engines": {
9116
+
"node": "20 || >=22"
9117
+
}
9118
+
},
9119
+
"node_modules/npm/node_modules/@isaacs/cliui": {
9120
+
"version": "8.0.2",
9121
+
"inBundle": true,
9122
+
"license": "ISC",
9123
+
"dependencies": {
9124
+
"string-width": "^5.1.2",
9125
+
"string-width-cjs": "npm:string-width@^4.2.0",
9126
+
"strip-ansi": "^7.0.1",
9127
+
"strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
9128
+
"wrap-ansi": "^8.1.0",
9129
+
"wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
9130
+
},
9131
+
"engines": {
9132
+
"node": ">=12"
9133
+
}
9134
+
},
9135
+
"node_modules/npm/node_modules/@isaacs/cliui/node_modules/ansi-regex": {
9136
+
"version": "6.2.2",
9137
+
"inBundle": true,
9138
+
"license": "MIT",
9139
+
"engines": {
9140
+
"node": ">=12"
9141
+
},
9142
+
"funding": {
9143
+
"url": "https://github.com/chalk/ansi-regex?sponsor=1"
9144
+
}
9145
+
},
9146
+
"node_modules/npm/node_modules/@isaacs/cliui/node_modules/emoji-regex": {
9147
+
"version": "9.2.2",
9148
+
"inBundle": true,
9149
+
"license": "MIT"
9150
+
},
9151
+
"node_modules/npm/node_modules/@isaacs/cliui/node_modules/string-width": {
9152
+
"version": "5.1.2",
9153
+
"inBundle": true,
9154
+
"license": "MIT",
9155
+
"dependencies": {
9156
+
"eastasianwidth": "^0.2.0",
9157
+
"emoji-regex": "^9.2.2",
9158
+
"strip-ansi": "^7.0.1"
9159
+
},
9160
+
"engines": {
9161
+
"node": ">=12"
9162
+
},
9163
+
"funding": {
9164
+
"url": "https://github.com/sponsors/sindresorhus"
9165
+
}
9166
+
},
9167
+
"node_modules/npm/node_modules/@isaacs/cliui/node_modules/strip-ansi": {
9168
+
"version": "7.1.2",
9169
+
"inBundle": true,
9170
+
"license": "MIT",
9171
+
"dependencies": {
9172
+
"ansi-regex": "^6.0.1"
9173
+
},
9174
+
"engines": {
9175
+
"node": ">=12"
9176
+
},
9177
+
"funding": {
9178
+
"url": "https://github.com/chalk/strip-ansi?sponsor=1"
9179
+
}
9180
+
},
9181
+
"node_modules/npm/node_modules/@isaacs/fs-minipass": {
9182
+
"version": "4.0.1",
9183
+
"inBundle": true,
9184
+
"license": "ISC",
9185
+
"dependencies": {
9186
+
"minipass": "^7.0.4"
9187
+
},
9188
+
"engines": {
9189
+
"node": ">=18.0.0"
9190
+
}
9191
+
},
9192
+
"node_modules/npm/node_modules/@isaacs/string-locale-compare": {
9193
+
"version": "1.1.0",
9194
+
"inBundle": true,
9195
+
"license": "ISC"
9196
+
},
9197
+
"node_modules/npm/node_modules/@npmcli/agent": {
9198
+
"version": "4.0.0",
9199
+
"inBundle": true,
9200
+
"license": "ISC",
9201
+
"dependencies": {
9202
+
"agent-base": "^7.1.0",
9203
+
"http-proxy-agent": "^7.0.0",
9204
+
"https-proxy-agent": "^7.0.1",
9205
+
"lru-cache": "^11.2.1",
9206
+
"socks-proxy-agent": "^8.0.3"
9207
+
},
9208
+
"engines": {
9209
+
"node": "^20.17.0 || >=22.9.0"
9210
+
}
9211
+
},
9212
+
"node_modules/npm/node_modules/@npmcli/arborist": {
9213
+
"version": "9.1.6",
9214
+
"inBundle": true,
9215
+
"license": "ISC",
9216
+
"dependencies": {
9217
+
"@isaacs/string-locale-compare": "^1.1.0",
9218
+
"@npmcli/fs": "^4.0.0",
9219
+
"@npmcli/installed-package-contents": "^3.0.0",
9220
+
"@npmcli/map-workspaces": "^5.0.0",
9221
+
"@npmcli/metavuln-calculator": "^9.0.2",
9222
+
"@npmcli/name-from-folder": "^3.0.0",
9223
+
"@npmcli/node-gyp": "^4.0.0",
9224
+
"@npmcli/package-json": "^7.0.0",
9225
+
"@npmcli/query": "^4.0.0",
9226
+
"@npmcli/redact": "^3.0.0",
9227
+
"@npmcli/run-script": "^10.0.0",
9228
+
"bin-links": "^5.0.0",
9229
+
"cacache": "^20.0.1",
9230
+
"common-ancestor-path": "^1.0.1",
9231
+
"hosted-git-info": "^9.0.0",
9232
+
"json-stringify-nice": "^1.1.4",
9233
+
"lru-cache": "^11.2.1",
9234
+
"minimatch": "^10.0.3",
9235
+
"nopt": "^8.0.0",
9236
+
"npm-install-checks": "^7.1.0",
9237
+
"npm-package-arg": "^13.0.0",
9238
+
"npm-pick-manifest": "^11.0.1",
9239
+
"npm-registry-fetch": "^19.0.0",
9240
+
"pacote": "^21.0.2",
9241
+
"parse-conflict-json": "^4.0.0",
9242
+
"proc-log": "^5.0.0",
9243
+
"proggy": "^3.0.0",
9244
+
"promise-all-reject-late": "^1.0.0",
9245
+
"promise-call-limit": "^3.0.1",
9246
+
"semver": "^7.3.7",
9247
+
"ssri": "^12.0.0",
9248
+
"treeverse": "^3.0.0",
9249
+
"walk-up-path": "^4.0.0"
9250
+
},
9251
+
"bin": {
9252
+
"arborist": "bin/index.js"
9253
+
},
9254
+
"engines": {
9255
+
"node": "^20.17.0 || >=22.9.0"
9256
+
}
9257
+
},
9258
+
"node_modules/npm/node_modules/@npmcli/config": {
9259
+
"version": "10.4.2",
9260
+
"inBundle": true,
9261
+
"license": "ISC",
9262
+
"dependencies": {
9263
+
"@npmcli/map-workspaces": "^5.0.0",
9264
+
"@npmcli/package-json": "^7.0.0",
9265
+
"ci-info": "^4.0.0",
9266
+
"ini": "^5.0.0",
9267
+
"nopt": "^8.1.0",
9268
+
"proc-log": "^5.0.0",
9269
+
"semver": "^7.3.5",
9270
+
"walk-up-path": "^4.0.0"
9271
+
},
9272
+
"engines": {
9273
+
"node": "^20.17.0 || >=22.9.0"
9274
+
}
9275
+
},
9276
+
"node_modules/npm/node_modules/@npmcli/fs": {
9277
+
"version": "4.0.0",
9278
+
"inBundle": true,
9279
+
"license": "ISC",
9280
+
"dependencies": {
9281
+
"semver": "^7.3.5"
9282
+
},
9283
+
"engines": {
9284
+
"node": "^18.17.0 || >=20.5.0"
9285
+
}
9286
+
},
9287
+
"node_modules/npm/node_modules/@npmcli/git": {
9288
+
"version": "7.0.0",
9289
+
"inBundle": true,
9290
+
"license": "ISC",
9291
+
"dependencies": {
9292
+
"@npmcli/promise-spawn": "^8.0.0",
9293
+
"ini": "^5.0.0",
9294
+
"lru-cache": "^11.2.1",
9295
+
"npm-pick-manifest": "^11.0.1",
9296
+
"proc-log": "^5.0.0",
9297
+
"promise-retry": "^2.0.1",
9298
+
"semver": "^7.3.5",
9299
+
"which": "^5.0.0"
9300
+
},
9301
+
"engines": {
9302
+
"node": "^20.17.0 || >=22.9.0"
9303
+
}
9304
+
},
9305
+
"node_modules/npm/node_modules/@npmcli/installed-package-contents": {
9306
+
"version": "3.0.0",
9307
+
"inBundle": true,
9308
+
"license": "ISC",
9309
+
"dependencies": {
9310
+
"npm-bundled": "^4.0.0",
9311
+
"npm-normalize-package-bin": "^4.0.0"
9312
+
},
9313
+
"bin": {
9314
+
"installed-package-contents": "bin/index.js"
9315
+
},
9316
+
"engines": {
9317
+
"node": "^18.17.0 || >=20.5.0"
9318
+
}
9319
+
},
9320
+
"node_modules/npm/node_modules/@npmcli/map-workspaces": {
9321
+
"version": "5.0.0",
9322
+
"inBundle": true,
9323
+
"license": "ISC",
9324
+
"dependencies": {
9325
+
"@npmcli/name-from-folder": "^3.0.0",
9326
+
"@npmcli/package-json": "^7.0.0",
9327
+
"glob": "^11.0.3",
9328
+
"minimatch": "^10.0.3"
9329
+
},
9330
+
"engines": {
9331
+
"node": "^20.17.0 || >=22.9.0"
9332
+
}
9333
+
},
9334
+
"node_modules/npm/node_modules/@npmcli/metavuln-calculator": {
9335
+
"version": "9.0.2",
9336
+
"inBundle": true,
9337
+
"license": "ISC",
9338
+
"dependencies": {
9339
+
"cacache": "^20.0.0",
9340
+
"json-parse-even-better-errors": "^4.0.0",
9341
+
"pacote": "^21.0.0",
9342
+
"proc-log": "^5.0.0",
9343
+
"semver": "^7.3.5"
9344
+
},
9345
+
"engines": {
9346
+
"node": "^20.17.0 || >=22.9.0"
9347
+
}
9348
+
},
9349
+
"node_modules/npm/node_modules/@npmcli/name-from-folder": {
9350
+
"version": "3.0.0",
9351
+
"inBundle": true,
9352
+
"license": "ISC",
9353
+
"engines": {
9354
+
"node": "^18.17.0 || >=20.5.0"
9355
+
}
9356
+
},
9357
+
"node_modules/npm/node_modules/@npmcli/node-gyp": {
9358
+
"version": "4.0.0",
9359
+
"inBundle": true,
9360
+
"license": "ISC",
9361
+
"engines": {
9362
+
"node": "^18.17.0 || >=20.5.0"
9363
+
}
9364
+
},
9365
+
"node_modules/npm/node_modules/@npmcli/package-json": {
9366
+
"version": "7.0.1",
9367
+
"inBundle": true,
9368
+
"license": "ISC",
9369
+
"dependencies": {
9370
+
"@npmcli/git": "^7.0.0",
9371
+
"glob": "^11.0.3",
9372
+
"hosted-git-info": "^9.0.0",
9373
+
"json-parse-even-better-errors": "^4.0.0",
9374
+
"proc-log": "^5.0.0",
9375
+
"semver": "^7.5.3",
9376
+
"validate-npm-package-license": "^3.0.4"
9377
+
},
9378
+
"engines": {
9379
+
"node": "^20.17.0 || >=22.9.0"
9380
+
}
9381
+
},
9382
+
"node_modules/npm/node_modules/@npmcli/promise-spawn": {
9383
+
"version": "8.0.3",
9384
+
"inBundle": true,
9385
+
"license": "ISC",
9386
+
"dependencies": {
9387
+
"which": "^5.0.0"
9388
+
},
9389
+
"engines": {
9390
+
"node": "^18.17.0 || >=20.5.0"
9391
+
}
9392
+
},
9393
+
"node_modules/npm/node_modules/@npmcli/query": {
9394
+
"version": "4.0.1",
9395
+
"inBundle": true,
9396
+
"license": "ISC",
9397
+
"dependencies": {
9398
+
"postcss-selector-parser": "^7.0.0"
9399
+
},
9400
+
"engines": {
9401
+
"node": "^18.17.0 || >=20.5.0"
9402
+
}
9403
+
},
9404
+
"node_modules/npm/node_modules/@npmcli/redact": {
9405
+
"version": "3.2.2",
9406
+
"inBundle": true,
9407
+
"license": "ISC",
9408
+
"engines": {
9409
+
"node": "^18.17.0 || >=20.5.0"
9410
+
}
9411
+
},
9412
+
"node_modules/npm/node_modules/@npmcli/run-script": {
9413
+
"version": "10.0.0",
9414
+
"inBundle": true,
9415
+
"license": "ISC",
9416
+
"dependencies": {
9417
+
"@npmcli/node-gyp": "^4.0.0",
9418
+
"@npmcli/package-json": "^7.0.0",
9419
+
"@npmcli/promise-spawn": "^8.0.0",
9420
+
"node-gyp": "^11.0.0",
9421
+
"proc-log": "^5.0.0",
9422
+
"which": "^5.0.0"
9423
+
},
9424
+
"engines": {
9425
+
"node": "^20.17.0 || >=22.9.0"
9426
+
}
9427
+
},
9428
+
"node_modules/npm/node_modules/@pkgjs/parseargs": {
9429
+
"version": "0.11.0",
9430
+
"inBundle": true,
9431
+
"license": "MIT",
9432
+
"optional": true,
9433
+
"engines": {
9434
+
"node": ">=14"
9435
+
}
9436
+
},
9437
+
"node_modules/npm/node_modules/@sigstore/bundle": {
9438
+
"version": "4.0.0",
9439
+
"inBundle": true,
9440
+
"license": "Apache-2.0",
9441
+
"dependencies": {
9442
+
"@sigstore/protobuf-specs": "^0.5.0"
9443
+
},
9444
+
"engines": {
9445
+
"node": "^20.17.0 || >=22.9.0"
9446
+
}
9447
+
},
9448
+
"node_modules/npm/node_modules/@sigstore/core": {
9449
+
"version": "3.0.0",
9450
+
"inBundle": true,
9451
+
"license": "Apache-2.0",
9452
+
"engines": {
9453
+
"node": "^20.17.0 || >=22.9.0"
9454
+
}
9455
+
},
9456
+
"node_modules/npm/node_modules/@sigstore/protobuf-specs": {
9457
+
"version": "0.5.0",
9458
+
"inBundle": true,
9459
+
"license": "Apache-2.0",
9460
+
"engines": {
9461
+
"node": "^18.17.0 || >=20.5.0"
9462
+
}
9463
+
},
9464
+
"node_modules/npm/node_modules/@sigstore/sign": {
9465
+
"version": "4.0.1",
9466
+
"inBundle": true,
9467
+
"license": "Apache-2.0",
9468
+
"dependencies": {
9469
+
"@sigstore/bundle": "^4.0.0",
9470
+
"@sigstore/core": "^3.0.0",
9471
+
"@sigstore/protobuf-specs": "^0.5.0",
9472
+
"make-fetch-happen": "^15.0.2",
9473
+
"proc-log": "^5.0.0",
9474
+
"promise-retry": "^2.0.1"
9475
+
},
9476
+
"engines": {
9477
+
"node": "^20.17.0 || >=22.9.0"
9478
+
}
9479
+
},
9480
+
"node_modules/npm/node_modules/@sigstore/tuf": {
9481
+
"version": "4.0.0",
9482
+
"inBundle": true,
9483
+
"license": "Apache-2.0",
9484
+
"dependencies": {
9485
+
"@sigstore/protobuf-specs": "^0.5.0",
9486
+
"tuf-js": "^4.0.0"
9487
+
},
9488
+
"engines": {
9489
+
"node": "^20.17.0 || >=22.9.0"
9490
+
}
9491
+
},
9492
+
"node_modules/npm/node_modules/@sigstore/verify": {
9493
+
"version": "3.0.0",
9494
+
"inBundle": true,
9495
+
"license": "Apache-2.0",
9496
+
"dependencies": {
9497
+
"@sigstore/bundle": "^4.0.0",
9498
+
"@sigstore/core": "^3.0.0",
9499
+
"@sigstore/protobuf-specs": "^0.5.0"
9500
+
},
9501
+
"engines": {
9502
+
"node": "^20.17.0 || >=22.9.0"
9503
+
}
9504
+
},
9505
+
"node_modules/npm/node_modules/@tufjs/canonical-json": {
9506
+
"version": "2.0.0",
9507
+
"inBundle": true,
9508
+
"license": "MIT",
9509
+
"engines": {
9510
+
"node": "^16.14.0 || >=18.0.0"
9511
+
}
9512
+
},
9513
+
"node_modules/npm/node_modules/@tufjs/models": {
9514
+
"version": "4.0.0",
9515
+
"inBundle": true,
9516
+
"license": "MIT",
9517
+
"dependencies": {
9518
+
"@tufjs/canonical-json": "2.0.0",
9519
+
"minimatch": "^9.0.5"
9520
+
},
9521
+
"engines": {
9522
+
"node": "^20.17.0 || >=22.9.0"
9523
+
}
9524
+
},
9525
+
"node_modules/npm/node_modules/@tufjs/models/node_modules/minimatch": {
9526
+
"version": "9.0.5",
9527
+
"inBundle": true,
9528
+
"license": "ISC",
9529
+
"dependencies": {
9530
+
"brace-expansion": "^2.0.1"
9531
+
},
9532
+
"engines": {
9533
+
"node": ">=16 || 14 >=14.17"
9534
+
},
9535
+
"funding": {
9536
+
"url": "https://github.com/sponsors/isaacs"
9537
+
}
9538
+
},
9539
+
"node_modules/npm/node_modules/abbrev": {
9540
+
"version": "3.0.1",
9541
+
"inBundle": true,
9542
+
"license": "ISC",
9543
+
"engines": {
9544
+
"node": "^18.17.0 || >=20.5.0"
9545
+
}
9546
+
},
9547
+
"node_modules/npm/node_modules/agent-base": {
9548
+
"version": "7.1.4",
9549
+
"inBundle": true,
9550
+
"license": "MIT",
9551
+
"engines": {
9552
+
"node": ">= 14"
9553
+
}
9554
+
},
9555
+
"node_modules/npm/node_modules/ansi-regex": {
9556
+
"version": "5.0.1",
9557
+
"inBundle": true,
9558
+
"license": "MIT",
9559
+
"engines": {
9560
+
"node": ">=8"
9561
+
}
9562
+
},
9563
+
"node_modules/npm/node_modules/ansi-styles": {
9564
+
"version": "6.2.3",
9565
+
"inBundle": true,
9566
+
"license": "MIT",
9567
+
"engines": {
9568
+
"node": ">=12"
9569
+
},
9570
+
"funding": {
9571
+
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
9572
+
}
9573
+
},
9574
+
"node_modules/npm/node_modules/aproba": {
9575
+
"version": "2.1.0",
9576
+
"inBundle": true,
9577
+
"license": "ISC"
9578
+
},
9579
+
"node_modules/npm/node_modules/archy": {
9580
+
"version": "1.0.0",
9581
+
"inBundle": true,
9582
+
"license": "MIT"
9583
+
},
9584
+
"node_modules/npm/node_modules/balanced-match": {
9585
+
"version": "1.0.2",
9586
+
"inBundle": true,
9587
+
"license": "MIT"
9588
+
},
9589
+
"node_modules/npm/node_modules/bin-links": {
9590
+
"version": "5.0.0",
9591
+
"inBundle": true,
9592
+
"license": "ISC",
9593
+
"dependencies": {
9594
+
"cmd-shim": "^7.0.0",
9595
+
"npm-normalize-package-bin": "^4.0.0",
9596
+
"proc-log": "^5.0.0",
9597
+
"read-cmd-shim": "^5.0.0",
9598
+
"write-file-atomic": "^6.0.0"
9599
+
},
9600
+
"engines": {
9601
+
"node": "^18.17.0 || >=20.5.0"
9602
+
}
9603
+
},
9604
+
"node_modules/npm/node_modules/binary-extensions": {
9605
+
"version": "3.1.0",
9606
+
"inBundle": true,
9607
+
"license": "MIT",
9608
+
"engines": {
9609
+
"node": ">=18.20"
9610
+
},
9611
+
"funding": {
9612
+
"url": "https://github.com/sponsors/sindresorhus"
9613
+
}
9614
+
},
9615
+
"node_modules/npm/node_modules/brace-expansion": {
9616
+
"version": "2.0.2",
9617
+
"inBundle": true,
9618
+
"license": "MIT",
9619
+
"dependencies": {
9620
+
"balanced-match": "^1.0.0"
9621
+
}
9622
+
},
9623
+
"node_modules/npm/node_modules/cacache": {
9624
+
"version": "20.0.1",
9625
+
"inBundle": true,
9626
+
"license": "ISC",
9627
+
"dependencies": {
9628
+
"@npmcli/fs": "^4.0.0",
9629
+
"fs-minipass": "^3.0.0",
9630
+
"glob": "^11.0.3",
9631
+
"lru-cache": "^11.1.0",
9632
+
"minipass": "^7.0.3",
9633
+
"minipass-collect": "^2.0.1",
9634
+
"minipass-flush": "^1.0.5",
9635
+
"minipass-pipeline": "^1.2.4",
9636
+
"p-map": "^7.0.2",
9637
+
"ssri": "^12.0.0",
9638
+
"unique-filename": "^4.0.0"
9639
+
},
9640
+
"engines": {
9641
+
"node": "^20.17.0 || >=22.9.0"
9642
+
}
9643
+
},
9644
+
"node_modules/npm/node_modules/chalk": {
9645
+
"version": "5.6.2",
9646
+
"inBundle": true,
9647
+
"license": "MIT",
9648
+
"engines": {
9649
+
"node": "^12.17.0 || ^14.13 || >=16.0.0"
9650
+
},
9651
+
"funding": {
9652
+
"url": "https://github.com/chalk/chalk?sponsor=1"
9653
+
}
9654
+
},
9655
+
"node_modules/npm/node_modules/chownr": {
9656
+
"version": "3.0.0",
9657
+
"inBundle": true,
9658
+
"license": "BlueOak-1.0.0",
9659
+
"engines": {
9660
+
"node": ">=18"
9661
+
}
9662
+
},
9663
+
"node_modules/npm/node_modules/ci-info": {
9664
+
"version": "4.3.1",
9665
+
"funding": [
9666
+
{
9667
+
"type": "github",
9668
+
"url": "https://github.com/sponsors/sibiraj-s"
9669
+
}
9670
+
],
9671
+
"inBundle": true,
9672
+
"license": "MIT",
9673
+
"engines": {
9674
+
"node": ">=8"
9675
+
}
9676
+
},
9677
+
"node_modules/npm/node_modules/cidr-regex": {
9678
+
"version": "5.0.1",
9679
+
"inBundle": true,
9680
+
"license": "BSD-2-Clause",
9681
+
"dependencies": {
9682
+
"ip-regex": "5.0.0"
9683
+
},
9684
+
"engines": {
9685
+
"node": ">=20"
9686
+
}
9687
+
},
9688
+
"node_modules/npm/node_modules/cli-columns": {
9689
+
"version": "4.0.0",
9690
+
"inBundle": true,
9691
+
"license": "MIT",
9692
+
"dependencies": {
9693
+
"string-width": "^4.2.3",
9694
+
"strip-ansi": "^6.0.1"
9695
+
},
9696
+
"engines": {
9697
+
"node": ">= 10"
9698
+
}
9699
+
},
9700
+
"node_modules/npm/node_modules/cmd-shim": {
9701
+
"version": "7.0.0",
9702
+
"inBundle": true,
9703
+
"license": "ISC",
9704
+
"engines": {
9705
+
"node": "^18.17.0 || >=20.5.0"
9706
+
}
9707
+
},
9708
+
"node_modules/npm/node_modules/color-convert": {
9709
+
"version": "2.0.1",
9710
+
"inBundle": true,
9711
+
"license": "MIT",
9712
+
"dependencies": {
9713
+
"color-name": "~1.1.4"
9714
+
},
9715
+
"engines": {
9716
+
"node": ">=7.0.0"
9717
+
}
9718
+
},
9719
+
"node_modules/npm/node_modules/color-name": {
9720
+
"version": "1.1.4",
9721
+
"inBundle": true,
9722
+
"license": "MIT"
9723
+
},
9724
+
"node_modules/npm/node_modules/common-ancestor-path": {
9725
+
"version": "1.0.1",
9726
+
"inBundle": true,
9727
+
"license": "ISC"
9728
+
},
9729
+
"node_modules/npm/node_modules/cross-spawn": {
9730
+
"version": "7.0.6",
9731
+
"inBundle": true,
9732
+
"license": "MIT",
9733
+
"dependencies": {
9734
+
"path-key": "^3.1.0",
9735
+
"shebang-command": "^2.0.0",
9736
+
"which": "^2.0.1"
9737
+
},
9738
+
"engines": {
9739
+
"node": ">= 8"
9740
+
}
9741
+
},
9742
+
"node_modules/npm/node_modules/cross-spawn/node_modules/isexe": {
9743
+
"version": "2.0.0",
9744
+
"inBundle": true,
9745
+
"license": "ISC"
9746
+
},
9747
+
"node_modules/npm/node_modules/cross-spawn/node_modules/which": {
9748
+
"version": "2.0.2",
9749
+
"inBundle": true,
9750
+
"license": "ISC",
9751
+
"dependencies": {
9752
+
"isexe": "^2.0.0"
9753
+
},
9754
+
"bin": {
9755
+
"node-which": "bin/node-which"
9756
+
},
9757
+
"engines": {
9758
+
"node": ">= 8"
9759
+
}
9760
+
},
9761
+
"node_modules/npm/node_modules/cssesc": {
9762
+
"version": "3.0.0",
9763
+
"inBundle": true,
9764
+
"license": "MIT",
9765
+
"bin": {
9766
+
"cssesc": "bin/cssesc"
9767
+
},
9768
+
"engines": {
9769
+
"node": ">=4"
9770
+
}
9771
+
},
9772
+
"node_modules/npm/node_modules/debug": {
9773
+
"version": "4.4.3",
9774
+
"inBundle": true,
9775
+
"license": "MIT",
9776
+
"dependencies": {
9777
+
"ms": "^2.1.3"
9778
+
},
9779
+
"engines": {
9780
+
"node": ">=6.0"
9781
+
},
9782
+
"peerDependenciesMeta": {
9783
+
"supports-color": {
9784
+
"optional": true
9785
+
}
9786
+
}
9787
+
},
9788
+
"node_modules/npm/node_modules/diff": {
9789
+
"version": "8.0.2",
9790
+
"inBundle": true,
9791
+
"license": "BSD-3-Clause",
9792
+
"engines": {
9793
+
"node": ">=0.3.1"
9794
+
}
9795
+
},
9796
+
"node_modules/npm/node_modules/eastasianwidth": {
9797
+
"version": "0.2.0",
9798
+
"inBundle": true,
9799
+
"license": "MIT"
9800
+
},
9801
+
"node_modules/npm/node_modules/emoji-regex": {
9802
+
"version": "8.0.0",
9803
+
"inBundle": true,
9804
+
"license": "MIT"
9805
+
},
9806
+
"node_modules/npm/node_modules/encoding": {
9807
+
"version": "0.1.13",
9808
+
"inBundle": true,
9809
+
"license": "MIT",
9810
+
"optional": true,
9811
+
"dependencies": {
9812
+
"iconv-lite": "^0.6.2"
9813
+
}
9814
+
},
9815
+
"node_modules/npm/node_modules/env-paths": {
9816
+
"version": "2.2.1",
9817
+
"inBundle": true,
9818
+
"license": "MIT",
9819
+
"engines": {
9820
+
"node": ">=6"
9821
+
}
9822
+
},
9823
+
"node_modules/npm/node_modules/err-code": {
9824
+
"version": "2.0.3",
9825
+
"inBundle": true,
9826
+
"license": "MIT"
9827
+
},
9828
+
"node_modules/npm/node_modules/exponential-backoff": {
9829
+
"version": "3.1.2",
9830
+
"inBundle": true,
9831
+
"license": "Apache-2.0"
9832
+
},
9833
+
"node_modules/npm/node_modules/fastest-levenshtein": {
9834
+
"version": "1.0.16",
9835
+
"inBundle": true,
9836
+
"license": "MIT",
9837
+
"engines": {
9838
+
"node": ">= 4.9.1"
9839
+
}
9840
+
},
9841
+
"node_modules/npm/node_modules/foreground-child": {
9842
+
"version": "3.3.1",
9843
+
"inBundle": true,
9844
+
"license": "ISC",
9845
+
"dependencies": {
9846
+
"cross-spawn": "^7.0.6",
9847
+
"signal-exit": "^4.0.1"
9848
+
},
9849
+
"engines": {
9850
+
"node": ">=14"
9851
+
},
9852
+
"funding": {
9853
+
"url": "https://github.com/sponsors/isaacs"
9854
+
}
9855
+
},
9856
+
"node_modules/npm/node_modules/fs-minipass": {
9857
+
"version": "3.0.3",
9858
+
"inBundle": true,
9859
+
"license": "ISC",
9860
+
"dependencies": {
9861
+
"minipass": "^7.0.3"
9862
+
},
9863
+
"engines": {
9864
+
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
9865
+
}
9866
+
},
9867
+
"node_modules/npm/node_modules/glob": {
9868
+
"version": "11.0.3",
9869
+
"inBundle": true,
9870
+
"license": "ISC",
9871
+
"dependencies": {
9872
+
"foreground-child": "^3.3.1",
9873
+
"jackspeak": "^4.1.1",
9874
+
"minimatch": "^10.0.3",
9875
+
"minipass": "^7.1.2",
9876
+
"package-json-from-dist": "^1.0.0",
9877
+
"path-scurry": "^2.0.0"
9878
+
},
9879
+
"bin": {
9880
+
"glob": "dist/esm/bin.mjs"
9881
+
},
9882
+
"engines": {
9883
+
"node": "20 || >=22"
9884
+
},
9885
+
"funding": {
9886
+
"url": "https://github.com/sponsors/isaacs"
9887
+
}
9888
+
},
9889
+
"node_modules/npm/node_modules/graceful-fs": {
9890
+
"version": "4.2.11",
9891
+
"inBundle": true,
9892
+
"license": "ISC"
9893
+
},
9894
+
"node_modules/npm/node_modules/hosted-git-info": {
9895
+
"version": "9.0.2",
9896
+
"inBundle": true,
9897
+
"license": "ISC",
9898
+
"dependencies": {
9899
+
"lru-cache": "^11.1.0"
9900
+
},
9901
+
"engines": {
9902
+
"node": "^20.17.0 || >=22.9.0"
9903
+
}
9904
+
},
9905
+
"node_modules/npm/node_modules/http-cache-semantics": {
9906
+
"version": "4.2.0",
9907
+
"inBundle": true,
9908
+
"license": "BSD-2-Clause"
9909
+
},
9910
+
"node_modules/npm/node_modules/http-proxy-agent": {
9911
+
"version": "7.0.2",
9912
+
"inBundle": true,
9913
+
"license": "MIT",
9914
+
"dependencies": {
9915
+
"agent-base": "^7.1.0",
9916
+
"debug": "^4.3.4"
9917
+
},
9918
+
"engines": {
9919
+
"node": ">= 14"
9920
+
}
9921
+
},
9922
+
"node_modules/npm/node_modules/https-proxy-agent": {
9923
+
"version": "7.0.6",
9924
+
"inBundle": true,
9925
+
"license": "MIT",
9926
+
"dependencies": {
9927
+
"agent-base": "^7.1.2",
9928
+
"debug": "4"
9929
+
},
9930
+
"engines": {
9931
+
"node": ">= 14"
9932
+
}
9933
+
},
9934
+
"node_modules/npm/node_modules/iconv-lite": {
9935
+
"version": "0.6.3",
9936
+
"inBundle": true,
9937
+
"license": "MIT",
9938
+
"optional": true,
9939
+
"dependencies": {
9940
+
"safer-buffer": ">= 2.1.2 < 3.0.0"
9941
+
},
9942
+
"engines": {
9943
+
"node": ">=0.10.0"
9944
+
}
9945
+
},
9946
+
"node_modules/npm/node_modules/ignore-walk": {
9947
+
"version": "8.0.0",
9948
+
"inBundle": true,
9949
+
"license": "ISC",
9950
+
"dependencies": {
9951
+
"minimatch": "^10.0.3"
9952
+
},
9953
+
"engines": {
9954
+
"node": "^20.17.0 || >=22.9.0"
9955
+
}
9956
+
},
9957
+
"node_modules/npm/node_modules/imurmurhash": {
9958
+
"version": "0.1.4",
9959
+
"inBundle": true,
9960
+
"license": "MIT",
9961
+
"engines": {
9962
+
"node": ">=0.8.19"
9963
+
}
9964
+
},
9965
+
"node_modules/npm/node_modules/ini": {
9966
+
"version": "5.0.0",
9967
+
"inBundle": true,
9968
+
"license": "ISC",
9969
+
"engines": {
9970
+
"node": "^18.17.0 || >=20.5.0"
9971
+
}
9972
+
},
9973
+
"node_modules/npm/node_modules/init-package-json": {
9974
+
"version": "8.2.2",
9975
+
"inBundle": true,
9976
+
"license": "ISC",
9977
+
"dependencies": {
9978
+
"@npmcli/package-json": "^7.0.0",
9979
+
"npm-package-arg": "^13.0.0",
9980
+
"promzard": "^2.0.0",
9981
+
"read": "^4.0.0",
9982
+
"semver": "^7.7.2",
9983
+
"validate-npm-package-license": "^3.0.4",
9984
+
"validate-npm-package-name": "^6.0.2"
9985
+
},
9986
+
"engines": {
9987
+
"node": "^20.17.0 || >=22.9.0"
9988
+
}
9989
+
},
9990
+
"node_modules/npm/node_modules/ip-address": {
9991
+
"version": "10.0.1",
9992
+
"inBundle": true,
9993
+
"license": "MIT",
9994
+
"engines": {
9995
+
"node": ">= 12"
9996
+
}
9997
+
},
9998
+
"node_modules/npm/node_modules/ip-regex": {
9999
+
"version": "5.0.0",
10000
+
"inBundle": true,
10001
+
"license": "MIT",
10002
+
"engines": {
10003
+
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
10004
+
},
10005
+
"funding": {
10006
+
"url": "https://github.com/sponsors/sindresorhus"
10007
+
}
10008
+
},
10009
+
"node_modules/npm/node_modules/is-cidr": {
10010
+
"version": "6.0.1",
10011
+
"inBundle": true,
10012
+
"license": "BSD-2-Clause",
10013
+
"dependencies": {
10014
+
"cidr-regex": "5.0.1"
10015
+
},
10016
+
"engines": {
10017
+
"node": ">=20"
10018
+
}
10019
+
},
10020
+
"node_modules/npm/node_modules/is-fullwidth-code-point": {
10021
+
"version": "3.0.0",
10022
+
"inBundle": true,
10023
+
"license": "MIT",
10024
+
"engines": {
10025
+
"node": ">=8"
10026
+
}
10027
+
},
10028
+
"node_modules/npm/node_modules/isexe": {
10029
+
"version": "3.1.1",
10030
+
"inBundle": true,
10031
+
"license": "ISC",
10032
+
"engines": {
10033
+
"node": ">=16"
10034
+
}
10035
+
},
10036
+
"node_modules/npm/node_modules/jackspeak": {
10037
+
"version": "4.1.1",
10038
+
"inBundle": true,
10039
+
"license": "BlueOak-1.0.0",
10040
+
"dependencies": {
10041
+
"@isaacs/cliui": "^8.0.2"
10042
+
},
10043
+
"engines": {
10044
+
"node": "20 || >=22"
10045
+
},
10046
+
"funding": {
10047
+
"url": "https://github.com/sponsors/isaacs"
10048
+
}
10049
+
},
10050
+
"node_modules/npm/node_modules/json-parse-even-better-errors": {
10051
+
"version": "4.0.0",
10052
+
"inBundle": true,
10053
+
"license": "MIT",
10054
+
"engines": {
10055
+
"node": "^18.17.0 || >=20.5.0"
10056
+
}
10057
+
},
10058
+
"node_modules/npm/node_modules/json-stringify-nice": {
10059
+
"version": "1.1.4",
10060
+
"inBundle": true,
10061
+
"license": "ISC",
10062
+
"funding": {
10063
+
"url": "https://github.com/sponsors/isaacs"
10064
+
}
10065
+
},
10066
+
"node_modules/npm/node_modules/jsonparse": {
10067
+
"version": "1.3.1",
10068
+
"engines": [
10069
+
"node >= 0.2.0"
10070
+
],
10071
+
"inBundle": true,
10072
+
"license": "MIT"
10073
+
},
10074
+
"node_modules/npm/node_modules/just-diff": {
10075
+
"version": "6.0.2",
10076
+
"inBundle": true,
10077
+
"license": "MIT"
10078
+
},
10079
+
"node_modules/npm/node_modules/just-diff-apply": {
10080
+
"version": "5.5.0",
10081
+
"inBundle": true,
10082
+
"license": "MIT"
10083
+
},
10084
+
"node_modules/npm/node_modules/libnpmaccess": {
10085
+
"version": "10.0.3",
10086
+
"inBundle": true,
10087
+
"license": "ISC",
10088
+
"dependencies": {
10089
+
"npm-package-arg": "^13.0.0",
10090
+
"npm-registry-fetch": "^19.0.0"
10091
+
},
10092
+
"engines": {
10093
+
"node": "^20.17.0 || >=22.9.0"
10094
+
}
10095
+
},
10096
+
"node_modules/npm/node_modules/libnpmdiff": {
10097
+
"version": "8.0.9",
10098
+
"inBundle": true,
10099
+
"license": "ISC",
10100
+
"dependencies": {
10101
+
"@npmcli/arborist": "^9.1.6",
10102
+
"@npmcli/installed-package-contents": "^3.0.0",
10103
+
"binary-extensions": "^3.0.0",
10104
+
"diff": "^8.0.2",
10105
+
"minimatch": "^10.0.3",
10106
+
"npm-package-arg": "^13.0.0",
10107
+
"pacote": "^21.0.2",
10108
+
"tar": "^7.5.1"
10109
+
},
10110
+
"engines": {
10111
+
"node": "^20.17.0 || >=22.9.0"
10112
+
}
10113
+
},
10114
+
"node_modules/npm/node_modules/libnpmexec": {
10115
+
"version": "10.1.8",
10116
+
"inBundle": true,
10117
+
"license": "ISC",
10118
+
"dependencies": {
10119
+
"@npmcli/arborist": "^9.1.6",
10120
+
"@npmcli/package-json": "^7.0.0",
10121
+
"@npmcli/run-script": "^10.0.0",
10122
+
"ci-info": "^4.0.0",
10123
+
"npm-package-arg": "^13.0.0",
10124
+
"pacote": "^21.0.2",
10125
+
"proc-log": "^5.0.0",
10126
+
"promise-retry": "^2.0.1",
10127
+
"read": "^4.0.0",
10128
+
"semver": "^7.3.7",
10129
+
"signal-exit": "^4.1.0",
10130
+
"walk-up-path": "^4.0.0"
10131
+
},
10132
+
"engines": {
10133
+
"node": "^20.17.0 || >=22.9.0"
10134
+
}
10135
+
},
10136
+
"node_modules/npm/node_modules/libnpmfund": {
10137
+
"version": "7.0.9",
10138
+
"inBundle": true,
10139
+
"license": "ISC",
10140
+
"dependencies": {
10141
+
"@npmcli/arborist": "^9.1.6"
10142
+
},
10143
+
"engines": {
10144
+
"node": "^20.17.0 || >=22.9.0"
10145
+
}
10146
+
},
10147
+
"node_modules/npm/node_modules/libnpmorg": {
10148
+
"version": "8.0.1",
10149
+
"inBundle": true,
10150
+
"license": "ISC",
10151
+
"dependencies": {
10152
+
"aproba": "^2.0.0",
10153
+
"npm-registry-fetch": "^19.0.0"
10154
+
},
10155
+
"engines": {
10156
+
"node": "^20.17.0 || >=22.9.0"
10157
+
}
10158
+
},
10159
+
"node_modules/npm/node_modules/libnpmpack": {
10160
+
"version": "9.0.9",
10161
+
"inBundle": true,
10162
+
"license": "ISC",
10163
+
"dependencies": {
10164
+
"@npmcli/arborist": "^9.1.6",
10165
+
"@npmcli/run-script": "^10.0.0",
10166
+
"npm-package-arg": "^13.0.0",
10167
+
"pacote": "^21.0.2"
10168
+
},
10169
+
"engines": {
10170
+
"node": "^20.17.0 || >=22.9.0"
10171
+
}
10172
+
},
10173
+
"node_modules/npm/node_modules/libnpmpublish": {
10174
+
"version": "11.1.2",
10175
+
"inBundle": true,
10176
+
"license": "ISC",
10177
+
"dependencies": {
10178
+
"@npmcli/package-json": "^7.0.0",
10179
+
"ci-info": "^4.0.0",
10180
+
"npm-package-arg": "^13.0.0",
10181
+
"npm-registry-fetch": "^19.0.0",
10182
+
"proc-log": "^5.0.0",
10183
+
"semver": "^7.3.7",
10184
+
"sigstore": "^4.0.0",
10185
+
"ssri": "^12.0.0"
10186
+
},
10187
+
"engines": {
10188
+
"node": "^20.17.0 || >=22.9.0"
10189
+
}
10190
+
},
10191
+
"node_modules/npm/node_modules/libnpmsearch": {
10192
+
"version": "9.0.1",
10193
+
"inBundle": true,
10194
+
"license": "ISC",
10195
+
"dependencies": {
10196
+
"npm-registry-fetch": "^19.0.0"
10197
+
},
10198
+
"engines": {
10199
+
"node": "^20.17.0 || >=22.9.0"
10200
+
}
10201
+
},
10202
+
"node_modules/npm/node_modules/libnpmteam": {
10203
+
"version": "8.0.2",
10204
+
"inBundle": true,
10205
+
"license": "ISC",
10206
+
"dependencies": {
10207
+
"aproba": "^2.0.0",
10208
+
"npm-registry-fetch": "^19.0.0"
10209
+
},
10210
+
"engines": {
10211
+
"node": "^20.17.0 || >=22.9.0"
10212
+
}
10213
+
},
10214
+
"node_modules/npm/node_modules/libnpmversion": {
10215
+
"version": "8.0.2",
10216
+
"inBundle": true,
10217
+
"license": "ISC",
10218
+
"dependencies": {
10219
+
"@npmcli/git": "^7.0.0",
10220
+
"@npmcli/run-script": "^10.0.0",
10221
+
"json-parse-even-better-errors": "^4.0.0",
10222
+
"proc-log": "^5.0.0",
10223
+
"semver": "^7.3.7"
10224
+
},
10225
+
"engines": {
10226
+
"node": "^20.17.0 || >=22.9.0"
10227
+
}
10228
+
},
10229
+
"node_modules/npm/node_modules/lru-cache": {
10230
+
"version": "11.2.2",
10231
+
"inBundle": true,
10232
+
"license": "ISC",
10233
+
"engines": {
10234
+
"node": "20 || >=22"
10235
+
}
10236
+
},
10237
+
"node_modules/npm/node_modules/make-fetch-happen": {
10238
+
"version": "15.0.2",
10239
+
"inBundle": true,
10240
+
"license": "ISC",
10241
+
"dependencies": {
10242
+
"@npmcli/agent": "^4.0.0",
10243
+
"cacache": "^20.0.1",
10244
+
"http-cache-semantics": "^4.1.1",
10245
+
"minipass": "^7.0.2",
10246
+
"minipass-fetch": "^4.0.0",
10247
+
"minipass-flush": "^1.0.5",
10248
+
"minipass-pipeline": "^1.2.4",
10249
+
"negotiator": "^1.0.0",
10250
+
"proc-log": "^5.0.0",
10251
+
"promise-retry": "^2.0.1",
10252
+
"ssri": "^12.0.0"
10253
+
},
10254
+
"engines": {
10255
+
"node": "^20.17.0 || >=22.9.0"
10256
+
}
10257
+
},
10258
+
"node_modules/npm/node_modules/minimatch": {
10259
+
"version": "10.0.3",
10260
+
"inBundle": true,
10261
+
"license": "ISC",
10262
+
"dependencies": {
10263
+
"@isaacs/brace-expansion": "^5.0.0"
10264
+
},
10265
+
"engines": {
10266
+
"node": "20 || >=22"
10267
+
},
10268
+
"funding": {
10269
+
"url": "https://github.com/sponsors/isaacs"
10270
+
}
10271
+
},
10272
+
"node_modules/npm/node_modules/minipass": {
10273
+
"version": "7.1.2",
10274
+
"inBundle": true,
10275
+
"license": "ISC",
10276
+
"engines": {
10277
+
"node": ">=16 || 14 >=14.17"
10278
+
}
10279
+
},
10280
+
"node_modules/npm/node_modules/minipass-collect": {
10281
+
"version": "2.0.1",
10282
+
"inBundle": true,
10283
+
"license": "ISC",
10284
+
"dependencies": {
10285
+
"minipass": "^7.0.3"
10286
+
},
10287
+
"engines": {
10288
+
"node": ">=16 || 14 >=14.17"
10289
+
}
10290
+
},
10291
+
"node_modules/npm/node_modules/minipass-fetch": {
10292
+
"version": "4.0.1",
10293
+
"inBundle": true,
10294
+
"license": "MIT",
10295
+
"dependencies": {
10296
+
"minipass": "^7.0.3",
10297
+
"minipass-sized": "^1.0.3",
10298
+
"minizlib": "^3.0.1"
10299
+
},
10300
+
"engines": {
10301
+
"node": "^18.17.0 || >=20.5.0"
10302
+
},
10303
+
"optionalDependencies": {
10304
+
"encoding": "^0.1.13"
10305
+
}
10306
+
},
10307
+
"node_modules/npm/node_modules/minipass-flush": {
10308
+
"version": "1.0.5",
10309
+
"inBundle": true,
10310
+
"license": "ISC",
10311
+
"dependencies": {
10312
+
"minipass": "^3.0.0"
10313
+
},
10314
+
"engines": {
10315
+
"node": ">= 8"
10316
+
}
10317
+
},
10318
+
"node_modules/npm/node_modules/minipass-flush/node_modules/minipass": {
10319
+
"version": "3.3.6",
10320
+
"inBundle": true,
10321
+
"license": "ISC",
10322
+
"dependencies": {
10323
+
"yallist": "^4.0.0"
10324
+
},
10325
+
"engines": {
10326
+
"node": ">=8"
10327
+
}
10328
+
},
10329
+
"node_modules/npm/node_modules/minipass-pipeline": {
10330
+
"version": "1.2.4",
10331
+
"inBundle": true,
10332
+
"license": "ISC",
10333
+
"dependencies": {
10334
+
"minipass": "^3.0.0"
10335
+
},
10336
+
"engines": {
10337
+
"node": ">=8"
10338
+
}
10339
+
},
10340
+
"node_modules/npm/node_modules/minipass-pipeline/node_modules/minipass": {
10341
+
"version": "3.3.6",
10342
+
"inBundle": true,
10343
+
"license": "ISC",
10344
+
"dependencies": {
10345
+
"yallist": "^4.0.0"
10346
+
},
10347
+
"engines": {
10348
+
"node": ">=8"
10349
+
}
10350
+
},
10351
+
"node_modules/npm/node_modules/minipass-sized": {
10352
+
"version": "1.0.3",
10353
+
"inBundle": true,
10354
+
"license": "ISC",
10355
+
"dependencies": {
10356
+
"minipass": "^3.0.0"
10357
+
},
10358
+
"engines": {
10359
+
"node": ">=8"
10360
+
}
10361
+
},
10362
+
"node_modules/npm/node_modules/minipass-sized/node_modules/minipass": {
10363
+
"version": "3.3.6",
10364
+
"inBundle": true,
10365
+
"license": "ISC",
10366
+
"dependencies": {
10367
+
"yallist": "^4.0.0"
10368
+
},
10369
+
"engines": {
10370
+
"node": ">=8"
10371
+
}
10372
+
},
10373
+
"node_modules/npm/node_modules/minizlib": {
10374
+
"version": "3.1.0",
10375
+
"inBundle": true,
10376
+
"license": "MIT",
10377
+
"dependencies": {
10378
+
"minipass": "^7.1.2"
10379
+
},
10380
+
"engines": {
10381
+
"node": ">= 18"
10382
+
}
10383
+
},
10384
+
"node_modules/npm/node_modules/ms": {
10385
+
"version": "2.1.3",
10386
+
"inBundle": true,
10387
+
"license": "MIT"
10388
+
},
10389
+
"node_modules/npm/node_modules/mute-stream": {
10390
+
"version": "2.0.0",
10391
+
"inBundle": true,
10392
+
"license": "ISC",
10393
+
"engines": {
10394
+
"node": "^18.17.0 || >=20.5.0"
10395
+
}
10396
+
},
10397
+
"node_modules/npm/node_modules/negotiator": {
10398
+
"version": "1.0.0",
10399
+
"inBundle": true,
10400
+
"license": "MIT",
10401
+
"engines": {
10402
+
"node": ">= 0.6"
10403
+
}
10404
+
},
10405
+
"node_modules/npm/node_modules/node-gyp": {
10406
+
"version": "11.4.2",
10407
+
"inBundle": true,
10408
+
"license": "MIT",
10409
+
"dependencies": {
10410
+
"env-paths": "^2.2.0",
10411
+
"exponential-backoff": "^3.1.1",
10412
+
"graceful-fs": "^4.2.6",
10413
+
"make-fetch-happen": "^14.0.3",
10414
+
"nopt": "^8.0.0",
10415
+
"proc-log": "^5.0.0",
10416
+
"semver": "^7.3.5",
10417
+
"tar": "^7.4.3",
10418
+
"tinyglobby": "^0.2.12",
10419
+
"which": "^5.0.0"
10420
+
},
10421
+
"bin": {
10422
+
"node-gyp": "bin/node-gyp.js"
10423
+
},
10424
+
"engines": {
10425
+
"node": "^18.17.0 || >=20.5.0"
10426
+
}
10427
+
},
10428
+
"node_modules/npm/node_modules/node-gyp/node_modules/@npmcli/agent": {
10429
+
"version": "3.0.0",
10430
+
"inBundle": true,
10431
+
"license": "ISC",
10432
+
"dependencies": {
10433
+
"agent-base": "^7.1.0",
10434
+
"http-proxy-agent": "^7.0.0",
10435
+
"https-proxy-agent": "^7.0.1",
10436
+
"lru-cache": "^10.0.1",
10437
+
"socks-proxy-agent": "^8.0.3"
10438
+
},
10439
+
"engines": {
10440
+
"node": "^18.17.0 || >=20.5.0"
10441
+
}
10442
+
},
10443
+
"node_modules/npm/node_modules/node-gyp/node_modules/cacache": {
10444
+
"version": "19.0.1",
10445
+
"inBundle": true,
10446
+
"license": "ISC",
10447
+
"dependencies": {
10448
+
"@npmcli/fs": "^4.0.0",
10449
+
"fs-minipass": "^3.0.0",
10450
+
"glob": "^10.2.2",
10451
+
"lru-cache": "^10.0.1",
10452
+
"minipass": "^7.0.3",
10453
+
"minipass-collect": "^2.0.1",
10454
+
"minipass-flush": "^1.0.5",
10455
+
"minipass-pipeline": "^1.2.4",
10456
+
"p-map": "^7.0.2",
10457
+
"ssri": "^12.0.0",
10458
+
"tar": "^7.4.3",
10459
+
"unique-filename": "^4.0.0"
10460
+
},
10461
+
"engines": {
10462
+
"node": "^18.17.0 || >=20.5.0"
10463
+
}
10464
+
},
10465
+
"node_modules/npm/node_modules/node-gyp/node_modules/glob": {
10466
+
"version": "10.4.5",
10467
+
"inBundle": true,
10468
+
"license": "ISC",
10469
+
"dependencies": {
10470
+
"foreground-child": "^3.1.0",
10471
+
"jackspeak": "^3.1.2",
10472
+
"minimatch": "^9.0.4",
10473
+
"minipass": "^7.1.2",
10474
+
"package-json-from-dist": "^1.0.0",
10475
+
"path-scurry": "^1.11.1"
10476
+
},
10477
+
"bin": {
10478
+
"glob": "dist/esm/bin.mjs"
10479
+
},
10480
+
"funding": {
10481
+
"url": "https://github.com/sponsors/isaacs"
10482
+
}
10483
+
},
10484
+
"node_modules/npm/node_modules/node-gyp/node_modules/jackspeak": {
10485
+
"version": "3.4.3",
10486
+
"inBundle": true,
10487
+
"license": "BlueOak-1.0.0",
10488
+
"dependencies": {
10489
+
"@isaacs/cliui": "^8.0.2"
10490
+
},
10491
+
"funding": {
10492
+
"url": "https://github.com/sponsors/isaacs"
10493
+
},
10494
+
"optionalDependencies": {
10495
+
"@pkgjs/parseargs": "^0.11.0"
10496
+
}
10497
+
},
10498
+
"node_modules/npm/node_modules/node-gyp/node_modules/lru-cache": {
10499
+
"version": "10.4.3",
10500
+
"inBundle": true,
10501
+
"license": "ISC"
10502
+
},
10503
+
"node_modules/npm/node_modules/node-gyp/node_modules/make-fetch-happen": {
10504
+
"version": "14.0.3",
10505
+
"inBundle": true,
10506
+
"license": "ISC",
10507
+
"dependencies": {
10508
+
"@npmcli/agent": "^3.0.0",
10509
+
"cacache": "^19.0.1",
10510
+
"http-cache-semantics": "^4.1.1",
10511
+
"minipass": "^7.0.2",
10512
+
"minipass-fetch": "^4.0.0",
10513
+
"minipass-flush": "^1.0.5",
10514
+
"minipass-pipeline": "^1.2.4",
10515
+
"negotiator": "^1.0.0",
10516
+
"proc-log": "^5.0.0",
10517
+
"promise-retry": "^2.0.1",
10518
+
"ssri": "^12.0.0"
10519
+
},
10520
+
"engines": {
10521
+
"node": "^18.17.0 || >=20.5.0"
10522
+
}
10523
+
},
10524
+
"node_modules/npm/node_modules/node-gyp/node_modules/minimatch": {
10525
+
"version": "9.0.5",
10526
+
"inBundle": true,
10527
+
"license": "ISC",
10528
+
"dependencies": {
10529
+
"brace-expansion": "^2.0.1"
10530
+
},
10531
+
"engines": {
10532
+
"node": ">=16 || 14 >=14.17"
10533
+
},
10534
+
"funding": {
10535
+
"url": "https://github.com/sponsors/isaacs"
10536
+
}
10537
+
},
10538
+
"node_modules/npm/node_modules/node-gyp/node_modules/path-scurry": {
10539
+
"version": "1.11.1",
10540
+
"inBundle": true,
10541
+
"license": "BlueOak-1.0.0",
10542
+
"dependencies": {
10543
+
"lru-cache": "^10.2.0",
10544
+
"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
10545
+
},
10546
+
"engines": {
10547
+
"node": ">=16 || 14 >=14.18"
10548
+
},
10549
+
"funding": {
10550
+
"url": "https://github.com/sponsors/isaacs"
10551
+
}
10552
+
},
10553
+
"node_modules/npm/node_modules/nopt": {
10554
+
"version": "8.1.0",
10555
+
"inBundle": true,
10556
+
"license": "ISC",
10557
+
"dependencies": {
10558
+
"abbrev": "^3.0.0"
10559
+
},
10560
+
"bin": {
10561
+
"nopt": "bin/nopt.js"
10562
+
},
10563
+
"engines": {
10564
+
"node": "^18.17.0 || >=20.5.0"
10565
+
}
10566
+
},
10567
+
"node_modules/npm/node_modules/npm-audit-report": {
10568
+
"version": "6.0.0",
10569
+
"inBundle": true,
10570
+
"license": "ISC",
10571
+
"engines": {
10572
+
"node": "^18.17.0 || >=20.5.0"
10573
+
}
10574
+
},
10575
+
"node_modules/npm/node_modules/npm-bundled": {
10576
+
"version": "4.0.0",
10577
+
"inBundle": true,
10578
+
"license": "ISC",
10579
+
"dependencies": {
10580
+
"npm-normalize-package-bin": "^4.0.0"
10581
+
},
10582
+
"engines": {
10583
+
"node": "^18.17.0 || >=20.5.0"
10584
+
}
10585
+
},
10586
+
"node_modules/npm/node_modules/npm-install-checks": {
10587
+
"version": "7.1.2",
10588
+
"inBundle": true,
10589
+
"license": "BSD-2-Clause",
10590
+
"dependencies": {
10591
+
"semver": "^7.1.1"
10592
+
},
10593
+
"engines": {
10594
+
"node": "^18.17.0 || >=20.5.0"
10595
+
}
10596
+
},
10597
+
"node_modules/npm/node_modules/npm-normalize-package-bin": {
10598
+
"version": "4.0.0",
10599
+
"inBundle": true,
10600
+
"license": "ISC",
10601
+
"engines": {
10602
+
"node": "^18.17.0 || >=20.5.0"
10603
+
}
10604
+
},
10605
+
"node_modules/npm/node_modules/npm-package-arg": {
10606
+
"version": "13.0.1",
10607
+
"inBundle": true,
10608
+
"license": "ISC",
10609
+
"dependencies": {
10610
+
"hosted-git-info": "^9.0.0",
10611
+
"proc-log": "^5.0.0",
10612
+
"semver": "^7.3.5",
10613
+
"validate-npm-package-name": "^6.0.0"
10614
+
},
10615
+
"engines": {
10616
+
"node": "^20.17.0 || >=22.9.0"
10617
+
}
10618
+
},
10619
+
"node_modules/npm/node_modules/npm-packlist": {
10620
+
"version": "10.0.2",
10621
+
"inBundle": true,
10622
+
"license": "ISC",
10623
+
"dependencies": {
10624
+
"ignore-walk": "^8.0.0",
10625
+
"proc-log": "^5.0.0"
10626
+
},
10627
+
"engines": {
10628
+
"node": "^20.17.0 || >=22.9.0"
10629
+
}
10630
+
},
10631
+
"node_modules/npm/node_modules/npm-pick-manifest": {
10632
+
"version": "11.0.1",
10633
+
"inBundle": true,
10634
+
"license": "ISC",
10635
+
"dependencies": {
10636
+
"npm-install-checks": "^7.1.0",
10637
+
"npm-normalize-package-bin": "^4.0.0",
10638
+
"npm-package-arg": "^13.0.0",
10639
+
"semver": "^7.3.5"
10640
+
},
10641
+
"engines": {
10642
+
"node": "^20.17.0 || >=22.9.0"
10643
+
}
10644
+
},
10645
+
"node_modules/npm/node_modules/npm-profile": {
10646
+
"version": "12.0.0",
10647
+
"inBundle": true,
10648
+
"license": "ISC",
10649
+
"dependencies": {
10650
+
"npm-registry-fetch": "^19.0.0",
10651
+
"proc-log": "^5.0.0"
10652
+
},
10653
+
"engines": {
10654
+
"node": "^20.17.0 || >=22.9.0"
10655
+
}
10656
+
},
10657
+
"node_modules/npm/node_modules/npm-registry-fetch": {
10658
+
"version": "19.0.0",
10659
+
"inBundle": true,
10660
+
"license": "ISC",
10661
+
"dependencies": {
10662
+
"@npmcli/redact": "^3.0.0",
10663
+
"jsonparse": "^1.3.1",
10664
+
"make-fetch-happen": "^15.0.0",
10665
+
"minipass": "^7.0.2",
10666
+
"minipass-fetch": "^4.0.0",
10667
+
"minizlib": "^3.0.1",
10668
+
"npm-package-arg": "^13.0.0",
10669
+
"proc-log": "^5.0.0"
10670
+
},
10671
+
"engines": {
10672
+
"node": "^20.17.0 || >=22.9.0"
10673
+
}
10674
+
},
10675
+
"node_modules/npm/node_modules/npm-user-validate": {
10676
+
"version": "3.0.0",
10677
+
"inBundle": true,
10678
+
"license": "BSD-2-Clause",
10679
+
"engines": {
10680
+
"node": "^18.17.0 || >=20.5.0"
10681
+
}
10682
+
},
10683
+
"node_modules/npm/node_modules/p-map": {
10684
+
"version": "7.0.3",
10685
+
"inBundle": true,
10686
+
"license": "MIT",
10687
+
"engines": {
10688
+
"node": ">=18"
10689
+
},
10690
+
"funding": {
10691
+
"url": "https://github.com/sponsors/sindresorhus"
10692
+
}
10693
+
},
10694
+
"node_modules/npm/node_modules/package-json-from-dist": {
10695
+
"version": "1.0.1",
10696
+
"inBundle": true,
10697
+
"license": "BlueOak-1.0.0"
10698
+
},
10699
+
"node_modules/npm/node_modules/pacote": {
10700
+
"version": "21.0.3",
10701
+
"inBundle": true,
10702
+
"license": "ISC",
10703
+
"dependencies": {
10704
+
"@npmcli/git": "^7.0.0",
10705
+
"@npmcli/installed-package-contents": "^3.0.0",
10706
+
"@npmcli/package-json": "^7.0.0",
10707
+
"@npmcli/promise-spawn": "^8.0.0",
10708
+
"@npmcli/run-script": "^10.0.0",
10709
+
"cacache": "^20.0.0",
10710
+
"fs-minipass": "^3.0.0",
10711
+
"minipass": "^7.0.2",
10712
+
"npm-package-arg": "^13.0.0",
10713
+
"npm-packlist": "^10.0.1",
10714
+
"npm-pick-manifest": "^11.0.1",
10715
+
"npm-registry-fetch": "^19.0.0",
10716
+
"proc-log": "^5.0.0",
10717
+
"promise-retry": "^2.0.1",
10718
+
"sigstore": "^4.0.0",
10719
+
"ssri": "^12.0.0",
10720
+
"tar": "^7.4.3"
10721
+
},
10722
+
"bin": {
10723
+
"pacote": "bin/index.js"
10724
+
},
10725
+
"engines": {
10726
+
"node": "^20.17.0 || >=22.9.0"
10727
+
}
10728
+
},
10729
+
"node_modules/npm/node_modules/parse-conflict-json": {
10730
+
"version": "4.0.0",
10731
+
"inBundle": true,
10732
+
"license": "ISC",
10733
+
"dependencies": {
10734
+
"json-parse-even-better-errors": "^4.0.0",
10735
+
"just-diff": "^6.0.0",
10736
+
"just-diff-apply": "^5.2.0"
10737
+
},
10738
+
"engines": {
10739
+
"node": "^18.17.0 || >=20.5.0"
10740
+
}
10741
+
},
10742
+
"node_modules/npm/node_modules/path-key": {
10743
+
"version": "3.1.1",
10744
+
"inBundle": true,
10745
+
"license": "MIT",
10746
+
"engines": {
10747
+
"node": ">=8"
10748
+
}
10749
+
},
10750
+
"node_modules/npm/node_modules/path-scurry": {
10751
+
"version": "2.0.0",
10752
+
"inBundle": true,
10753
+
"license": "BlueOak-1.0.0",
10754
+
"dependencies": {
10755
+
"lru-cache": "^11.0.0",
10756
+
"minipass": "^7.1.2"
10757
+
},
10758
+
"engines": {
10759
+
"node": "20 || >=22"
10760
+
},
10761
+
"funding": {
10762
+
"url": "https://github.com/sponsors/isaacs"
10763
+
}
10764
+
},
10765
+
"node_modules/npm/node_modules/postcss-selector-parser": {
10766
+
"version": "7.1.0",
10767
+
"inBundle": true,
10768
+
"license": "MIT",
10769
+
"dependencies": {
10770
+
"cssesc": "^3.0.0",
10771
+
"util-deprecate": "^1.0.2"
10772
+
},
10773
+
"engines": {
10774
+
"node": ">=4"
10775
+
}
10776
+
},
10777
+
"node_modules/npm/node_modules/proc-log": {
10778
+
"version": "5.0.0",
10779
+
"inBundle": true,
10780
+
"license": "ISC",
10781
+
"engines": {
10782
+
"node": "^18.17.0 || >=20.5.0"
10783
+
}
10784
+
},
10785
+
"node_modules/npm/node_modules/proggy": {
10786
+
"version": "3.0.0",
10787
+
"inBundle": true,
10788
+
"license": "ISC",
10789
+
"engines": {
10790
+
"node": "^18.17.0 || >=20.5.0"
10791
+
}
10792
+
},
10793
+
"node_modules/npm/node_modules/promise-all-reject-late": {
10794
+
"version": "1.0.1",
10795
+
"inBundle": true,
10796
+
"license": "ISC",
10797
+
"funding": {
10798
+
"url": "https://github.com/sponsors/isaacs"
10799
+
}
10800
+
},
10801
+
"node_modules/npm/node_modules/promise-call-limit": {
10802
+
"version": "3.0.2",
10803
+
"inBundle": true,
10804
+
"license": "ISC",
10805
+
"funding": {
10806
+
"url": "https://github.com/sponsors/isaacs"
10807
+
}
10808
+
},
10809
+
"node_modules/npm/node_modules/promise-retry": {
10810
+
"version": "2.0.1",
10811
+
"inBundle": true,
10812
+
"license": "MIT",
10813
+
"dependencies": {
10814
+
"err-code": "^2.0.2",
10815
+
"retry": "^0.12.0"
10816
+
},
10817
+
"engines": {
10818
+
"node": ">=10"
10819
+
}
10820
+
},
10821
+
"node_modules/npm/node_modules/promzard": {
10822
+
"version": "2.0.0",
10823
+
"inBundle": true,
10824
+
"license": "ISC",
10825
+
"dependencies": {
10826
+
"read": "^4.0.0"
10827
+
},
10828
+
"engines": {
10829
+
"node": "^18.17.0 || >=20.5.0"
10830
+
}
10831
+
},
10832
+
"node_modules/npm/node_modules/qrcode-terminal": {
10833
+
"version": "0.12.0",
10834
+
"inBundle": true,
10835
+
"bin": {
10836
+
"qrcode-terminal": "bin/qrcode-terminal.js"
10837
+
}
10838
+
},
10839
+
"node_modules/npm/node_modules/read": {
10840
+
"version": "4.1.0",
10841
+
"inBundle": true,
10842
+
"license": "ISC",
10843
+
"dependencies": {
10844
+
"mute-stream": "^2.0.0"
10845
+
},
10846
+
"engines": {
10847
+
"node": "^18.17.0 || >=20.5.0"
10848
+
}
10849
+
},
10850
+
"node_modules/npm/node_modules/read-cmd-shim": {
10851
+
"version": "5.0.0",
10852
+
"inBundle": true,
10853
+
"license": "ISC",
10854
+
"engines": {
10855
+
"node": "^18.17.0 || >=20.5.0"
10856
+
}
10857
+
},
10858
+
"node_modules/npm/node_modules/retry": {
10859
+
"version": "0.12.0",
10860
+
"inBundle": true,
10861
+
"license": "MIT",
10862
+
"engines": {
10863
+
"node": ">= 4"
10864
+
}
10865
+
},
10866
+
"node_modules/npm/node_modules/safer-buffer": {
10867
+
"version": "2.1.2",
10868
+
"inBundle": true,
10869
+
"license": "MIT",
10870
+
"optional": true
10871
+
},
10872
+
"node_modules/npm/node_modules/semver": {
10873
+
"version": "7.7.3",
10874
+
"inBundle": true,
10875
+
"license": "ISC",
10876
+
"bin": {
10877
+
"semver": "bin/semver.js"
10878
+
},
10879
+
"engines": {
10880
+
"node": ">=10"
10881
+
}
10882
+
},
10883
+
"node_modules/npm/node_modules/shebang-command": {
10884
+
"version": "2.0.0",
10885
+
"inBundle": true,
10886
+
"license": "MIT",
10887
+
"dependencies": {
10888
+
"shebang-regex": "^3.0.0"
10889
+
},
10890
+
"engines": {
10891
+
"node": ">=8"
10892
+
}
10893
+
},
10894
+
"node_modules/npm/node_modules/shebang-regex": {
10895
+
"version": "3.0.0",
10896
+
"inBundle": true,
10897
+
"license": "MIT",
10898
+
"engines": {
10899
+
"node": ">=8"
10900
+
}
10901
+
},
10902
+
"node_modules/npm/node_modules/signal-exit": {
10903
+
"version": "4.1.0",
10904
+
"inBundle": true,
10905
+
"license": "ISC",
10906
+
"engines": {
10907
+
"node": ">=14"
10908
+
},
10909
+
"funding": {
10910
+
"url": "https://github.com/sponsors/isaacs"
10911
+
}
10912
+
},
10913
+
"node_modules/npm/node_modules/sigstore": {
10914
+
"version": "4.0.0",
10915
+
"inBundle": true,
10916
+
"license": "Apache-2.0",
10917
+
"dependencies": {
10918
+
"@sigstore/bundle": "^4.0.0",
10919
+
"@sigstore/core": "^3.0.0",
10920
+
"@sigstore/protobuf-specs": "^0.5.0",
10921
+
"@sigstore/sign": "^4.0.0",
10922
+
"@sigstore/tuf": "^4.0.0",
10923
+
"@sigstore/verify": "^3.0.0"
10924
+
},
10925
+
"engines": {
10926
+
"node": "^20.17.0 || >=22.9.0"
10927
+
}
10928
+
},
10929
+
"node_modules/npm/node_modules/smart-buffer": {
10930
+
"version": "4.2.0",
10931
+
"inBundle": true,
10932
+
"license": "MIT",
10933
+
"engines": {
10934
+
"node": ">= 6.0.0",
10935
+
"npm": ">= 3.0.0"
10936
+
}
10937
+
},
10938
+
"node_modules/npm/node_modules/socks": {
10939
+
"version": "2.8.7",
10940
+
"inBundle": true,
10941
+
"license": "MIT",
10942
+
"dependencies": {
10943
+
"ip-address": "^10.0.1",
10944
+
"smart-buffer": "^4.2.0"
10945
+
},
10946
+
"engines": {
10947
+
"node": ">= 10.0.0",
10948
+
"npm": ">= 3.0.0"
10949
+
}
10950
+
},
10951
+
"node_modules/npm/node_modules/socks-proxy-agent": {
10952
+
"version": "8.0.5",
10953
+
"inBundle": true,
10954
+
"license": "MIT",
10955
+
"dependencies": {
10956
+
"agent-base": "^7.1.2",
10957
+
"debug": "^4.3.4",
10958
+
"socks": "^2.8.3"
10959
+
},
10960
+
"engines": {
10961
+
"node": ">= 14"
10962
+
}
10963
+
},
10964
+
"node_modules/npm/node_modules/spdx-correct": {
10965
+
"version": "3.2.0",
10966
+
"inBundle": true,
10967
+
"license": "Apache-2.0",
10968
+
"dependencies": {
10969
+
"spdx-expression-parse": "^3.0.0",
10970
+
"spdx-license-ids": "^3.0.0"
10971
+
}
10972
+
},
10973
+
"node_modules/npm/node_modules/spdx-correct/node_modules/spdx-expression-parse": {
10974
+
"version": "3.0.1",
10975
+
"inBundle": true,
10976
+
"license": "MIT",
10977
+
"dependencies": {
10978
+
"spdx-exceptions": "^2.1.0",
10979
+
"spdx-license-ids": "^3.0.0"
10980
+
}
10981
+
},
10982
+
"node_modules/npm/node_modules/spdx-exceptions": {
10983
+
"version": "2.5.0",
10984
+
"inBundle": true,
10985
+
"license": "CC-BY-3.0"
10986
+
},
10987
+
"node_modules/npm/node_modules/spdx-expression-parse": {
10988
+
"version": "4.0.0",
10989
+
"inBundle": true,
10990
+
"license": "MIT",
10991
+
"dependencies": {
10992
+
"spdx-exceptions": "^2.1.0",
10993
+
"spdx-license-ids": "^3.0.0"
10994
+
}
10995
+
},
10996
+
"node_modules/npm/node_modules/spdx-license-ids": {
10997
+
"version": "3.0.22",
10998
+
"inBundle": true,
10999
+
"license": "CC0-1.0"
11000
+
},
11001
+
"node_modules/npm/node_modules/ssri": {
11002
+
"version": "12.0.0",
11003
+
"inBundle": true,
11004
+
"license": "ISC",
11005
+
"dependencies": {
11006
+
"minipass": "^7.0.3"
11007
+
},
11008
+
"engines": {
11009
+
"node": "^18.17.0 || >=20.5.0"
11010
+
}
11011
+
},
11012
+
"node_modules/npm/node_modules/string-width": {
11013
+
"version": "4.2.3",
11014
+
"inBundle": true,
11015
+
"license": "MIT",
11016
+
"dependencies": {
11017
+
"emoji-regex": "^8.0.0",
11018
+
"is-fullwidth-code-point": "^3.0.0",
11019
+
"strip-ansi": "^6.0.1"
11020
+
},
11021
+
"engines": {
11022
+
"node": ">=8"
11023
+
}
11024
+
},
11025
+
"node_modules/npm/node_modules/string-width-cjs": {
11026
+
"name": "string-width",
11027
+
"version": "4.2.3",
11028
+
"inBundle": true,
11029
+
"license": "MIT",
11030
+
"dependencies": {
11031
+
"emoji-regex": "^8.0.0",
11032
+
"is-fullwidth-code-point": "^3.0.0",
11033
+
"strip-ansi": "^6.0.1"
11034
+
},
11035
+
"engines": {
11036
+
"node": ">=8"
11037
+
}
11038
+
},
11039
+
"node_modules/npm/node_modules/strip-ansi": {
11040
+
"version": "6.0.1",
11041
+
"inBundle": true,
11042
+
"license": "MIT",
11043
+
"dependencies": {
11044
+
"ansi-regex": "^5.0.1"
11045
+
},
11046
+
"engines": {
11047
+
"node": ">=8"
11048
+
}
11049
+
},
11050
+
"node_modules/npm/node_modules/strip-ansi-cjs": {
11051
+
"name": "strip-ansi",
11052
+
"version": "6.0.1",
11053
+
"inBundle": true,
11054
+
"license": "MIT",
11055
+
"dependencies": {
11056
+
"ansi-regex": "^5.0.1"
11057
+
},
11058
+
"engines": {
11059
+
"node": ">=8"
11060
+
}
11061
+
},
11062
+
"node_modules/npm/node_modules/supports-color": {
11063
+
"version": "10.2.2",
11064
+
"inBundle": true,
11065
+
"license": "MIT",
11066
+
"engines": {
11067
+
"node": ">=18"
11068
+
},
11069
+
"funding": {
11070
+
"url": "https://github.com/chalk/supports-color?sponsor=1"
11071
+
}
11072
+
},
11073
+
"node_modules/npm/node_modules/tar": {
11074
+
"version": "7.5.1",
11075
+
"inBundle": true,
11076
+
"license": "ISC",
11077
+
"dependencies": {
11078
+
"@isaacs/fs-minipass": "^4.0.0",
11079
+
"chownr": "^3.0.0",
11080
+
"minipass": "^7.1.2",
11081
+
"minizlib": "^3.1.0",
11082
+
"yallist": "^5.0.0"
11083
+
},
11084
+
"engines": {
11085
+
"node": ">=18"
11086
+
}
11087
+
},
11088
+
"node_modules/npm/node_modules/tar/node_modules/yallist": {
11089
+
"version": "5.0.0",
11090
+
"inBundle": true,
11091
+
"license": "BlueOak-1.0.0",
11092
+
"engines": {
11093
+
"node": ">=18"
11094
+
}
11095
+
},
11096
+
"node_modules/npm/node_modules/text-table": {
11097
+
"version": "0.2.0",
11098
+
"inBundle": true,
11099
+
"license": "MIT"
11100
+
},
11101
+
"node_modules/npm/node_modules/tiny-relative-date": {
11102
+
"version": "2.0.2",
11103
+
"inBundle": true,
11104
+
"license": "MIT"
11105
+
},
11106
+
"node_modules/npm/node_modules/tinyglobby": {
11107
+
"version": "0.2.15",
11108
+
"inBundle": true,
11109
+
"license": "MIT",
11110
+
"dependencies": {
11111
+
"fdir": "^6.5.0",
11112
+
"picomatch": "^4.0.3"
11113
+
},
11114
+
"engines": {
11115
+
"node": ">=12.0.0"
11116
+
},
11117
+
"funding": {
11118
+
"url": "https://github.com/sponsors/SuperchupuDev"
11119
+
}
11120
+
},
11121
+
"node_modules/npm/node_modules/tinyglobby/node_modules/fdir": {
11122
+
"version": "6.5.0",
11123
+
"inBundle": true,
11124
+
"license": "MIT",
11125
+
"engines": {
11126
+
"node": ">=12.0.0"
11127
+
},
11128
+
"peerDependencies": {
11129
+
"picomatch": "^3 || ^4"
11130
+
},
11131
+
"peerDependenciesMeta": {
11132
+
"picomatch": {
11133
+
"optional": true
11134
+
}
11135
+
}
11136
+
},
11137
+
"node_modules/npm/node_modules/tinyglobby/node_modules/picomatch": {
11138
+
"version": "4.0.3",
11139
+
"inBundle": true,
11140
+
"license": "MIT",
11141
+
"engines": {
11142
+
"node": ">=12"
11143
+
},
11144
+
"funding": {
11145
+
"url": "https://github.com/sponsors/jonschlinkert"
11146
+
}
11147
+
},
11148
+
"node_modules/npm/node_modules/treeverse": {
11149
+
"version": "3.0.0",
11150
+
"inBundle": true,
11151
+
"license": "ISC",
11152
+
"engines": {
11153
+
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
11154
+
}
11155
+
},
11156
+
"node_modules/npm/node_modules/tuf-js": {
11157
+
"version": "4.0.0",
11158
+
"inBundle": true,
11159
+
"license": "MIT",
11160
+
"dependencies": {
11161
+
"@tufjs/models": "4.0.0",
11162
+
"debug": "^4.4.1",
11163
+
"make-fetch-happen": "^15.0.0"
11164
+
},
11165
+
"engines": {
11166
+
"node": "^20.17.0 || >=22.9.0"
11167
+
}
11168
+
},
11169
+
"node_modules/npm/node_modules/unique-filename": {
11170
+
"version": "4.0.0",
11171
+
"inBundle": true,
11172
+
"license": "ISC",
11173
+
"dependencies": {
11174
+
"unique-slug": "^5.0.0"
11175
+
},
11176
+
"engines": {
11177
+
"node": "^18.17.0 || >=20.5.0"
11178
+
}
11179
+
},
11180
+
"node_modules/npm/node_modules/unique-slug": {
11181
+
"version": "5.0.0",
11182
+
"inBundle": true,
11183
+
"license": "ISC",
11184
+
"dependencies": {
11185
+
"imurmurhash": "^0.1.4"
11186
+
},
11187
+
"engines": {
11188
+
"node": "^18.17.0 || >=20.5.0"
11189
+
}
11190
+
},
11191
+
"node_modules/npm/node_modules/util-deprecate": {
11192
+
"version": "1.0.2",
11193
+
"inBundle": true,
11194
+
"license": "MIT"
11195
+
},
11196
+
"node_modules/npm/node_modules/validate-npm-package-license": {
11197
+
"version": "3.0.4",
11198
+
"inBundle": true,
11199
+
"license": "Apache-2.0",
11200
+
"dependencies": {
11201
+
"spdx-correct": "^3.0.0",
11202
+
"spdx-expression-parse": "^3.0.0"
11203
+
}
11204
+
},
11205
+
"node_modules/npm/node_modules/validate-npm-package-license/node_modules/spdx-expression-parse": {
11206
+
"version": "3.0.1",
11207
+
"inBundle": true,
11208
+
"license": "MIT",
11209
+
"dependencies": {
11210
+
"spdx-exceptions": "^2.1.0",
11211
+
"spdx-license-ids": "^3.0.0"
11212
+
}
11213
+
},
11214
+
"node_modules/npm/node_modules/validate-npm-package-name": {
11215
+
"version": "6.0.2",
11216
+
"inBundle": true,
11217
+
"license": "ISC",
11218
+
"engines": {
11219
+
"node": "^18.17.0 || >=20.5.0"
11220
+
}
11221
+
},
11222
+
"node_modules/npm/node_modules/walk-up-path": {
11223
+
"version": "4.0.0",
11224
+
"inBundle": true,
11225
+
"license": "ISC",
11226
+
"engines": {
11227
+
"node": "20 || >=22"
11228
+
}
11229
+
},
11230
+
"node_modules/npm/node_modules/which": {
11231
+
"version": "5.0.0",
11232
+
"inBundle": true,
11233
+
"license": "ISC",
11234
+
"dependencies": {
11235
+
"isexe": "^3.1.1"
11236
+
},
11237
+
"bin": {
11238
+
"node-which": "bin/which.js"
11239
+
},
11240
+
"engines": {
11241
+
"node": "^18.17.0 || >=20.5.0"
11242
+
}
11243
+
},
11244
+
"node_modules/npm/node_modules/wrap-ansi": {
11245
+
"version": "8.1.0",
11246
+
"inBundle": true,
11247
+
"license": "MIT",
11248
+
"dependencies": {
11249
+
"ansi-styles": "^6.1.0",
11250
+
"string-width": "^5.0.1",
11251
+
"strip-ansi": "^7.0.1"
11252
+
},
11253
+
"engines": {
11254
+
"node": ">=12"
11255
+
},
11256
+
"funding": {
11257
+
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
11258
+
}
11259
+
},
11260
+
"node_modules/npm/node_modules/wrap-ansi-cjs": {
11261
+
"name": "wrap-ansi",
11262
+
"version": "7.0.0",
11263
+
"inBundle": true,
11264
+
"license": "MIT",
11265
+
"dependencies": {
11266
+
"ansi-styles": "^4.0.0",
11267
+
"string-width": "^4.1.0",
11268
+
"strip-ansi": "^6.0.0"
11269
+
},
11270
+
"engines": {
11271
+
"node": ">=10"
11272
+
},
11273
+
"funding": {
11274
+
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
11275
+
}
11276
+
},
11277
+
"node_modules/npm/node_modules/wrap-ansi-cjs/node_modules/ansi-styles": {
11278
+
"version": "4.3.0",
11279
+
"inBundle": true,
11280
+
"license": "MIT",
11281
+
"dependencies": {
11282
+
"color-convert": "^2.0.1"
11283
+
},
11284
+
"engines": {
11285
+
"node": ">=8"
11286
+
},
11287
+
"funding": {
11288
+
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
11289
+
}
11290
+
},
11291
+
"node_modules/npm/node_modules/wrap-ansi/node_modules/ansi-regex": {
11292
+
"version": "6.2.2",
11293
+
"inBundle": true,
11294
+
"license": "MIT",
11295
+
"engines": {
11296
+
"node": ">=12"
11297
+
},
11298
+
"funding": {
11299
+
"url": "https://github.com/chalk/ansi-regex?sponsor=1"
11300
+
}
11301
+
},
11302
+
"node_modules/npm/node_modules/wrap-ansi/node_modules/emoji-regex": {
11303
+
"version": "9.2.2",
11304
+
"inBundle": true,
11305
+
"license": "MIT"
11306
+
},
11307
+
"node_modules/npm/node_modules/wrap-ansi/node_modules/string-width": {
11308
+
"version": "5.1.2",
11309
+
"inBundle": true,
11310
+
"license": "MIT",
11311
+
"dependencies": {
11312
+
"eastasianwidth": "^0.2.0",
11313
+
"emoji-regex": "^9.2.2",
11314
+
"strip-ansi": "^7.0.1"
11315
+
},
11316
+
"engines": {
11317
+
"node": ">=12"
11318
+
},
11319
+
"funding": {
11320
+
"url": "https://github.com/sponsors/sindresorhus"
11321
+
}
11322
+
},
11323
+
"node_modules/npm/node_modules/wrap-ansi/node_modules/strip-ansi": {
11324
+
"version": "7.1.2",
11325
+
"inBundle": true,
11326
+
"license": "MIT",
11327
+
"dependencies": {
11328
+
"ansi-regex": "^6.0.1"
11329
+
},
11330
+
"engines": {
11331
+
"node": ">=12"
11332
+
},
11333
+
"funding": {
11334
+
"url": "https://github.com/chalk/strip-ansi?sponsor=1"
11335
+
}
11336
+
},
11337
+
"node_modules/npm/node_modules/write-file-atomic": {
11338
+
"version": "6.0.0",
11339
+
"inBundle": true,
11340
+
"license": "ISC",
11341
+
"dependencies": {
11342
+
"imurmurhash": "^0.1.4",
11343
+
"signal-exit": "^4.0.1"
11344
+
},
11345
+
"engines": {
11346
+
"node": "^18.17.0 || >=20.5.0"
11347
+
}
11348
+
},
11349
+
"node_modules/npm/node_modules/yallist": {
11350
+
"version": "4.0.0",
11351
+
"inBundle": true,
11352
+
"license": "ISC"
11353
+
},
3830
11354
"node_modules/nwsapi": {
3831
11355
"version": "2.2.21",
3832
11356
"resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.21.tgz",
···
3843
11367
"node": ">=0.10.0"
3844
11368
}
3845
11369
},
11370
+
"node_modules/object-inspect": {
11371
+
"version": "1.13.4",
11372
+
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
11373
+
"integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
11374
+
"dev": true,
11375
+
"license": "MIT",
11376
+
"engines": {
11377
+
"node": ">= 0.4"
11378
+
},
11379
+
"funding": {
11380
+
"url": "https://github.com/sponsors/ljharb"
11381
+
}
11382
+
},
11383
+
"node_modules/object-keys": {
11384
+
"version": "1.1.1",
11385
+
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
11386
+
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
11387
+
"dev": true,
11388
+
"license": "MIT",
11389
+
"engines": {
11390
+
"node": ">= 0.4"
11391
+
}
11392
+
},
11393
+
"node_modules/object.assign": {
11394
+
"version": "4.1.7",
11395
+
"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz",
11396
+
"integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==",
11397
+
"dev": true,
11398
+
"license": "MIT",
11399
+
"dependencies": {
11400
+
"call-bind": "^1.0.8",
11401
+
"call-bound": "^1.0.3",
11402
+
"define-properties": "^1.2.1",
11403
+
"es-object-atoms": "^1.0.0",
11404
+
"has-symbols": "^1.1.0",
11405
+
"object-keys": "^1.1.1"
11406
+
},
11407
+
"engines": {
11408
+
"node": ">= 0.4"
11409
+
},
11410
+
"funding": {
11411
+
"url": "https://github.com/sponsors/ljharb"
11412
+
}
11413
+
},
11414
+
"node_modules/object.entries": {
11415
+
"version": "1.1.9",
11416
+
"resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz",
11417
+
"integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==",
11418
+
"dev": true,
11419
+
"license": "MIT",
11420
+
"dependencies": {
11421
+
"call-bind": "^1.0.8",
11422
+
"call-bound": "^1.0.4",
11423
+
"define-properties": "^1.2.1",
11424
+
"es-object-atoms": "^1.1.1"
11425
+
},
11426
+
"engines": {
11427
+
"node": ">= 0.4"
11428
+
}
11429
+
},
11430
+
"node_modules/object.fromentries": {
11431
+
"version": "2.0.8",
11432
+
"resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz",
11433
+
"integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==",
11434
+
"dev": true,
11435
+
"license": "MIT",
11436
+
"dependencies": {
11437
+
"call-bind": "^1.0.7",
11438
+
"define-properties": "^1.2.1",
11439
+
"es-abstract": "^1.23.2",
11440
+
"es-object-atoms": "^1.0.0"
11441
+
},
11442
+
"engines": {
11443
+
"node": ">= 0.4"
11444
+
},
11445
+
"funding": {
11446
+
"url": "https://github.com/sponsors/ljharb"
11447
+
}
11448
+
},
11449
+
"node_modules/object.values": {
11450
+
"version": "1.2.1",
11451
+
"resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz",
11452
+
"integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==",
11453
+
"dev": true,
11454
+
"license": "MIT",
11455
+
"dependencies": {
11456
+
"call-bind": "^1.0.8",
11457
+
"call-bound": "^1.0.3",
11458
+
"define-properties": "^1.2.1",
11459
+
"es-object-atoms": "^1.0.0"
11460
+
},
11461
+
"engines": {
11462
+
"node": ">= 0.4"
11463
+
},
11464
+
"funding": {
11465
+
"url": "https://github.com/sponsors/ljharb"
11466
+
}
11467
+
},
11468
+
"node_modules/optionator": {
11469
+
"version": "0.9.4",
11470
+
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
11471
+
"integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
11472
+
"dev": true,
11473
+
"license": "MIT",
11474
+
"peer": true,
11475
+
"dependencies": {
11476
+
"deep-is": "^0.1.3",
11477
+
"fast-levenshtein": "^2.0.6",
11478
+
"levn": "^0.4.1",
11479
+
"prelude-ls": "^1.2.1",
11480
+
"type-check": "^0.4.0",
11481
+
"word-wrap": "^1.2.5"
11482
+
},
11483
+
"engines": {
11484
+
"node": ">= 0.8.0"
11485
+
}
11486
+
},
11487
+
"node_modules/own-keys": {
11488
+
"version": "1.0.1",
11489
+
"resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz",
11490
+
"integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==",
11491
+
"dev": true,
11492
+
"license": "MIT",
11493
+
"dependencies": {
11494
+
"get-intrinsic": "^1.2.6",
11495
+
"object-keys": "^1.1.1",
11496
+
"safe-push-apply": "^1.0.0"
11497
+
},
11498
+
"engines": {
11499
+
"node": ">= 0.4"
11500
+
},
11501
+
"funding": {
11502
+
"url": "https://github.com/sponsors/ljharb"
11503
+
}
11504
+
},
11505
+
"node_modules/p-limit": {
11506
+
"version": "3.1.0",
11507
+
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
11508
+
"integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
11509
+
"dev": true,
11510
+
"license": "MIT",
11511
+
"peer": true,
11512
+
"dependencies": {
11513
+
"yocto-queue": "^0.1.0"
11514
+
},
11515
+
"engines": {
11516
+
"node": ">=10"
11517
+
},
11518
+
"funding": {
11519
+
"url": "https://github.com/sponsors/sindresorhus"
11520
+
}
11521
+
},
11522
+
"node_modules/p-locate": {
11523
+
"version": "5.0.0",
11524
+
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
11525
+
"integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
11526
+
"dev": true,
11527
+
"license": "MIT",
11528
+
"peer": true,
11529
+
"dependencies": {
11530
+
"p-limit": "^3.0.2"
11531
+
},
11532
+
"engines": {
11533
+
"node": ">=10"
11534
+
},
11535
+
"funding": {
11536
+
"url": "https://github.com/sponsors/sindresorhus"
11537
+
}
11538
+
},
11539
+
"node_modules/package-manager-detector": {
11540
+
"version": "1.4.1",
11541
+
"resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.4.1.tgz",
11542
+
"integrity": "sha512-dSMiVLBEA4XaNJ0PRb4N5cV/SEP4BWrWZKBmfF+OUm2pQTiZ6DDkKeWaltwu3JRhLoy59ayIkJ00cx9K9CaYTg==",
11543
+
"dev": true,
11544
+
"license": "MIT"
11545
+
},
11546
+
"node_modules/parent-module": {
11547
+
"version": "1.0.1",
11548
+
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
11549
+
"integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
11550
+
"dev": true,
11551
+
"license": "MIT",
11552
+
"dependencies": {
11553
+
"callsites": "^3.0.0"
11554
+
},
11555
+
"engines": {
11556
+
"node": ">=6"
11557
+
}
11558
+
},
11559
+
"node_modules/parse-json": {
11560
+
"version": "5.2.0",
11561
+
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
11562
+
"integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
11563
+
"dev": true,
11564
+
"license": "MIT",
11565
+
"dependencies": {
11566
+
"@babel/code-frame": "^7.0.0",
11567
+
"error-ex": "^1.3.1",
11568
+
"json-parse-even-better-errors": "^2.3.0",
11569
+
"lines-and-columns": "^1.1.6"
11570
+
},
11571
+
"engines": {
11572
+
"node": ">=8"
11573
+
},
11574
+
"funding": {
11575
+
"url": "https://github.com/sponsors/sindresorhus"
11576
+
}
11577
+
},
3846
11578
"node_modules/parse5": {
3847
11579
"version": "7.3.0",
3848
11580
"resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz",
···
3862
11594
"integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==",
3863
11595
"license": "MIT"
3864
11596
},
11597
+
"node_modules/path-exists": {
11598
+
"version": "4.0.0",
11599
+
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
11600
+
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
11601
+
"dev": true,
11602
+
"license": "MIT",
11603
+
"peer": true,
11604
+
"engines": {
11605
+
"node": ">=8"
11606
+
}
11607
+
},
11608
+
"node_modules/path-key": {
11609
+
"version": "3.1.1",
11610
+
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
11611
+
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
11612
+
"dev": true,
11613
+
"license": "MIT",
11614
+
"peer": true,
11615
+
"engines": {
11616
+
"node": ">=8"
11617
+
}
11618
+
},
11619
+
"node_modules/path-parse": {
11620
+
"version": "1.0.7",
11621
+
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
11622
+
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
11623
+
"dev": true,
11624
+
"license": "MIT"
11625
+
},
11626
+
"node_modules/path-type": {
11627
+
"version": "4.0.0",
11628
+
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
11629
+
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
11630
+
"dev": true,
11631
+
"license": "MIT",
11632
+
"engines": {
11633
+
"node": ">=8"
11634
+
}
11635
+
},
3865
11636
"node_modules/pathe": {
3866
11637
"version": "2.0.3",
3867
11638
"resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
···
3897
11668
"url": "https://github.com/sponsors/jonschlinkert"
3898
11669
}
3899
11670
},
11671
+
"node_modules/pkg-types": {
11672
+
"version": "2.3.0",
11673
+
"resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz",
11674
+
"integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==",
11675
+
"dev": true,
11676
+
"license": "MIT",
11677
+
"dependencies": {
11678
+
"confbox": "^0.2.2",
11679
+
"exsolve": "^1.0.7",
11680
+
"pathe": "^2.0.3"
11681
+
}
11682
+
},
3900
11683
"node_modules/player.style": {
3901
11684
"version": "0.1.10",
3902
11685
"resolved": "https://registry.npmjs.org/player.style/-/player.style-0.1.10.tgz",
···
3913
11696
"media-chrome": "~4.11.0"
3914
11697
}
3915
11698
},
11699
+
"node_modules/possible-typed-array-names": {
11700
+
"version": "1.1.0",
11701
+
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
11702
+
"integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==",
11703
+
"dev": true,
11704
+
"license": "MIT",
11705
+
"engines": {
11706
+
"node": ">= 0.4"
11707
+
}
11708
+
},
3916
11709
"node_modules/postcss": {
3917
11710
"version": "8.5.6",
3918
11711
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
···
3939
11732
},
3940
11733
"engines": {
3941
11734
"node": "^10 || ^12 || >=14"
11735
+
}
11736
+
},
11737
+
"node_modules/prelude-ls": {
11738
+
"version": "1.2.1",
11739
+
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
11740
+
"integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
11741
+
"dev": true,
11742
+
"license": "MIT",
11743
+
"peer": true,
11744
+
"engines": {
11745
+
"node": ">= 0.8.0"
3942
11746
}
3943
11747
},
3944
11748
"node_modules/prettier": {
···
3998
11802
"node": ">=6"
3999
11803
}
4000
11804
},
11805
+
"node_modules/quansync": {
11806
+
"version": "0.2.11",
11807
+
"resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz",
11808
+
"integrity": "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==",
11809
+
"dev": true,
11810
+
"funding": [
11811
+
{
11812
+
"type": "individual",
11813
+
"url": "https://github.com/sponsors/antfu"
11814
+
},
11815
+
{
11816
+
"type": "individual",
11817
+
"url": "https://github.com/sponsors/sxzz"
11818
+
}
11819
+
],
11820
+
"license": "MIT"
11821
+
},
11822
+
"node_modules/queue-microtask": {
11823
+
"version": "1.2.3",
11824
+
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
11825
+
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
11826
+
"dev": true,
11827
+
"funding": [
11828
+
{
11829
+
"type": "github",
11830
+
"url": "https://github.com/sponsors/feross"
11831
+
},
11832
+
{
11833
+
"type": "patreon",
11834
+
"url": "https://www.patreon.com/feross"
11835
+
},
11836
+
{
11837
+
"type": "consulting",
11838
+
"url": "https://feross.org/support"
11839
+
}
11840
+
],
11841
+
"license": "MIT"
11842
+
},
11843
+
"node_modules/radix-ui": {
11844
+
"version": "1.4.3",
11845
+
"resolved": "https://registry.npmjs.org/radix-ui/-/radix-ui-1.4.3.tgz",
11846
+
"integrity": "sha512-aWizCQiyeAenIdUbqEpXgRA1ya65P13NKn/W8rWkcN0OPkRDxdBVLWnIEDsS2RpwCK2nobI7oMUSmexzTDyAmA==",
11847
+
"dependencies": {
11848
+
"@radix-ui/primitive": "1.1.3",
11849
+
"@radix-ui/react-accessible-icon": "1.1.7",
11850
+
"@radix-ui/react-accordion": "1.2.12",
11851
+
"@radix-ui/react-alert-dialog": "1.1.15",
11852
+
"@radix-ui/react-arrow": "1.1.7",
11853
+
"@radix-ui/react-aspect-ratio": "1.1.7",
11854
+
"@radix-ui/react-avatar": "1.1.10",
11855
+
"@radix-ui/react-checkbox": "1.3.3",
11856
+
"@radix-ui/react-collapsible": "1.1.12",
11857
+
"@radix-ui/react-collection": "1.1.7",
11858
+
"@radix-ui/react-compose-refs": "1.1.2",
11859
+
"@radix-ui/react-context": "1.1.2",
11860
+
"@radix-ui/react-context-menu": "2.2.16",
11861
+
"@radix-ui/react-dialog": "1.1.15",
11862
+
"@radix-ui/react-direction": "1.1.1",
11863
+
"@radix-ui/react-dismissable-layer": "1.1.11",
11864
+
"@radix-ui/react-dropdown-menu": "2.1.16",
11865
+
"@radix-ui/react-focus-guards": "1.1.3",
11866
+
"@radix-ui/react-focus-scope": "1.1.7",
11867
+
"@radix-ui/react-form": "0.1.8",
11868
+
"@radix-ui/react-hover-card": "1.1.15",
11869
+
"@radix-ui/react-label": "2.1.7",
11870
+
"@radix-ui/react-menu": "2.1.16",
11871
+
"@radix-ui/react-menubar": "1.1.16",
11872
+
"@radix-ui/react-navigation-menu": "1.2.14",
11873
+
"@radix-ui/react-one-time-password-field": "0.1.8",
11874
+
"@radix-ui/react-password-toggle-field": "0.1.3",
11875
+
"@radix-ui/react-popover": "1.1.15",
11876
+
"@radix-ui/react-popper": "1.2.8",
11877
+
"@radix-ui/react-portal": "1.1.9",
11878
+
"@radix-ui/react-presence": "1.1.5",
11879
+
"@radix-ui/react-primitive": "2.1.3",
11880
+
"@radix-ui/react-progress": "1.1.7",
11881
+
"@radix-ui/react-radio-group": "1.3.8",
11882
+
"@radix-ui/react-roving-focus": "1.1.11",
11883
+
"@radix-ui/react-scroll-area": "1.2.10",
11884
+
"@radix-ui/react-select": "2.2.6",
11885
+
"@radix-ui/react-separator": "1.1.7",
11886
+
"@radix-ui/react-slider": "1.3.6",
11887
+
"@radix-ui/react-slot": "1.2.3",
11888
+
"@radix-ui/react-switch": "1.2.6",
11889
+
"@radix-ui/react-tabs": "1.1.13",
11890
+
"@radix-ui/react-toast": "1.2.15",
11891
+
"@radix-ui/react-toggle": "1.1.10",
11892
+
"@radix-ui/react-toggle-group": "1.1.11",
11893
+
"@radix-ui/react-toolbar": "1.1.11",
11894
+
"@radix-ui/react-tooltip": "1.2.8",
11895
+
"@radix-ui/react-use-callback-ref": "1.1.1",
11896
+
"@radix-ui/react-use-controllable-state": "1.2.2",
11897
+
"@radix-ui/react-use-effect-event": "0.0.2",
11898
+
"@radix-ui/react-use-escape-keydown": "1.1.1",
11899
+
"@radix-ui/react-use-is-hydrated": "0.1.0",
11900
+
"@radix-ui/react-use-layout-effect": "1.1.1",
11901
+
"@radix-ui/react-use-size": "1.1.1",
11902
+
"@radix-ui/react-visually-hidden": "1.2.3"
11903
+
},
11904
+
"peerDependencies": {
11905
+
"@types/react": "*",
11906
+
"@types/react-dom": "*",
11907
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
11908
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
11909
+
},
11910
+
"peerDependenciesMeta": {
11911
+
"@types/react": {
11912
+
"optional": true
11913
+
},
11914
+
"@types/react-dom": {
11915
+
"optional": true
11916
+
}
11917
+
}
11918
+
},
4001
11919
"node_modules/react": {
4002
11920
"version": "19.1.1",
4003
11921
"resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz",
···
4059
11977
"node": ">=0.10.0"
4060
11978
}
4061
11979
},
11980
+
"node_modules/react-remove-scroll": {
11981
+
"version": "2.7.1",
11982
+
"resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.1.tgz",
11983
+
"integrity": "sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==",
11984
+
"dependencies": {
11985
+
"react-remove-scroll-bar": "^2.3.7",
11986
+
"react-style-singleton": "^2.2.3",
11987
+
"tslib": "^2.1.0",
11988
+
"use-callback-ref": "^1.3.3",
11989
+
"use-sidecar": "^1.1.3"
11990
+
},
11991
+
"engines": {
11992
+
"node": ">=10"
11993
+
},
11994
+
"peerDependencies": {
11995
+
"@types/react": "*",
11996
+
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
11997
+
},
11998
+
"peerDependenciesMeta": {
11999
+
"@types/react": {
12000
+
"optional": true
12001
+
}
12002
+
}
12003
+
},
12004
+
"node_modules/react-remove-scroll-bar": {
12005
+
"version": "2.3.8",
12006
+
"resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz",
12007
+
"integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==",
12008
+
"dependencies": {
12009
+
"react-style-singleton": "^2.2.2",
12010
+
"tslib": "^2.0.0"
12011
+
},
12012
+
"engines": {
12013
+
"node": ">=10"
12014
+
},
12015
+
"peerDependencies": {
12016
+
"@types/react": "*",
12017
+
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
12018
+
},
12019
+
"peerDependenciesMeta": {
12020
+
"@types/react": {
12021
+
"optional": true
12022
+
}
12023
+
}
12024
+
},
12025
+
"node_modules/react-style-singleton": {
12026
+
"version": "2.2.3",
12027
+
"resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz",
12028
+
"integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==",
12029
+
"dependencies": {
12030
+
"get-nonce": "^1.0.0",
12031
+
"tslib": "^2.0.0"
12032
+
},
12033
+
"engines": {
12034
+
"node": ">=10"
12035
+
},
12036
+
"peerDependencies": {
12037
+
"@types/react": "*",
12038
+
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
12039
+
},
12040
+
"peerDependenciesMeta": {
12041
+
"@types/react": {
12042
+
"optional": true
12043
+
}
12044
+
}
12045
+
},
4062
12046
"node_modules/readdirp": {
4063
12047
"version": "3.6.0",
4064
12048
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
···
4096
12080
"node": ">=0.10.0"
4097
12081
}
4098
12082
},
12083
+
"node_modules/reflect.getprototypeof": {
12084
+
"version": "1.0.10",
12085
+
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
12086
+
"integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==",
12087
+
"dev": true,
12088
+
"license": "MIT",
12089
+
"dependencies": {
12090
+
"call-bind": "^1.0.8",
12091
+
"define-properties": "^1.2.1",
12092
+
"es-abstract": "^1.23.9",
12093
+
"es-errors": "^1.3.0",
12094
+
"es-object-atoms": "^1.0.0",
12095
+
"get-intrinsic": "^1.2.7",
12096
+
"get-proto": "^1.0.1",
12097
+
"which-builtin-type": "^1.2.1"
12098
+
},
12099
+
"engines": {
12100
+
"node": ">= 0.4"
12101
+
},
12102
+
"funding": {
12103
+
"url": "https://github.com/sponsors/ljharb"
12104
+
}
12105
+
},
12106
+
"node_modules/regexp.prototype.flags": {
12107
+
"version": "1.5.4",
12108
+
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz",
12109
+
"integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==",
12110
+
"dev": true,
12111
+
"license": "MIT",
12112
+
"dependencies": {
12113
+
"call-bind": "^1.0.8",
12114
+
"define-properties": "^1.2.1",
12115
+
"es-errors": "^1.3.0",
12116
+
"get-proto": "^1.0.1",
12117
+
"gopd": "^1.2.0",
12118
+
"set-function-name": "^2.0.2"
12119
+
},
12120
+
"engines": {
12121
+
"node": ">= 0.4"
12122
+
},
12123
+
"funding": {
12124
+
"url": "https://github.com/sponsors/ljharb"
12125
+
}
12126
+
},
12127
+
"node_modules/resolve": {
12128
+
"version": "2.0.0-next.5",
12129
+
"resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz",
12130
+
"integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==",
12131
+
"dev": true,
12132
+
"license": "MIT",
12133
+
"dependencies": {
12134
+
"is-core-module": "^2.13.0",
12135
+
"path-parse": "^1.0.7",
12136
+
"supports-preserve-symlinks-flag": "^1.0.0"
12137
+
},
12138
+
"bin": {
12139
+
"resolve": "bin/resolve"
12140
+
},
12141
+
"funding": {
12142
+
"url": "https://github.com/sponsors/ljharb"
12143
+
}
12144
+
},
12145
+
"node_modules/resolve-from": {
12146
+
"version": "4.0.0",
12147
+
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
12148
+
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
12149
+
"dev": true,
12150
+
"license": "MIT",
12151
+
"engines": {
12152
+
"node": ">=4"
12153
+
}
12154
+
},
4099
12155
"node_modules/resolve-pkg-maps": {
4100
12156
"version": "1.0.0",
4101
12157
"resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
···
4103
12159
"license": "MIT",
4104
12160
"funding": {
4105
12161
"url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
12162
+
}
12163
+
},
12164
+
"node_modules/reusify": {
12165
+
"version": "1.1.0",
12166
+
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
12167
+
"integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
12168
+
"dev": true,
12169
+
"license": "MIT",
12170
+
"engines": {
12171
+
"iojs": ">=1.0.0",
12172
+
"node": ">=0.10.0"
4106
12173
}
4107
12174
},
4108
12175
"node_modules/rollup": {
···
4151
12218
"dev": true,
4152
12219
"license": "MIT"
4153
12220
},
12221
+
"node_modules/run-parallel": {
12222
+
"version": "1.2.0",
12223
+
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
12224
+
"integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
12225
+
"dev": true,
12226
+
"funding": [
12227
+
{
12228
+
"type": "github",
12229
+
"url": "https://github.com/sponsors/feross"
12230
+
},
12231
+
{
12232
+
"type": "patreon",
12233
+
"url": "https://www.patreon.com/feross"
12234
+
},
12235
+
{
12236
+
"type": "consulting",
12237
+
"url": "https://feross.org/support"
12238
+
}
12239
+
],
12240
+
"license": "MIT",
12241
+
"dependencies": {
12242
+
"queue-microtask": "^1.2.2"
12243
+
}
12244
+
},
12245
+
"node_modules/safe-array-concat": {
12246
+
"version": "1.1.3",
12247
+
"resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz",
12248
+
"integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==",
12249
+
"dev": true,
12250
+
"license": "MIT",
12251
+
"dependencies": {
12252
+
"call-bind": "^1.0.8",
12253
+
"call-bound": "^1.0.2",
12254
+
"get-intrinsic": "^1.2.6",
12255
+
"has-symbols": "^1.1.0",
12256
+
"isarray": "^2.0.5"
12257
+
},
12258
+
"engines": {
12259
+
"node": ">=0.4"
12260
+
},
12261
+
"funding": {
12262
+
"url": "https://github.com/sponsors/ljharb"
12263
+
}
12264
+
},
12265
+
"node_modules/safe-push-apply": {
12266
+
"version": "1.0.0",
12267
+
"resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz",
12268
+
"integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==",
12269
+
"dev": true,
12270
+
"license": "MIT",
12271
+
"dependencies": {
12272
+
"es-errors": "^1.3.0",
12273
+
"isarray": "^2.0.5"
12274
+
},
12275
+
"engines": {
12276
+
"node": ">= 0.4"
12277
+
},
12278
+
"funding": {
12279
+
"url": "https://github.com/sponsors/ljharb"
12280
+
}
12281
+
},
12282
+
"node_modules/safe-regex-test": {
12283
+
"version": "1.1.0",
12284
+
"resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz",
12285
+
"integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==",
12286
+
"dev": true,
12287
+
"license": "MIT",
12288
+
"dependencies": {
12289
+
"call-bound": "^1.0.2",
12290
+
"es-errors": "^1.3.0",
12291
+
"is-regex": "^1.2.1"
12292
+
},
12293
+
"engines": {
12294
+
"node": ">= 0.4"
12295
+
},
12296
+
"funding": {
12297
+
"url": "https://github.com/sponsors/ljharb"
12298
+
}
12299
+
},
4154
12300
"node_modules/safer-buffer": {
4155
12301
"version": "2.1.2",
4156
12302
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
···
4183
12329
"integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==",
4184
12330
"license": "MIT"
4185
12331
},
12332
+
"node_modules/scule": {
12333
+
"version": "1.3.0",
12334
+
"resolved": "https://registry.npmjs.org/scule/-/scule-1.3.0.tgz",
12335
+
"integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==",
12336
+
"dev": true,
12337
+
"license": "MIT"
12338
+
},
4186
12339
"node_modules/semver": {
4187
12340
"version": "6.3.1",
4188
12341
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
···
4213
12366
"seroval": "^1.0"
4214
12367
}
4215
12368
},
12369
+
"node_modules/set-function-length": {
12370
+
"version": "1.2.2",
12371
+
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
12372
+
"integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
12373
+
"dev": true,
12374
+
"license": "MIT",
12375
+
"dependencies": {
12376
+
"define-data-property": "^1.1.4",
12377
+
"es-errors": "^1.3.0",
12378
+
"function-bind": "^1.1.2",
12379
+
"get-intrinsic": "^1.2.4",
12380
+
"gopd": "^1.0.1",
12381
+
"has-property-descriptors": "^1.0.2"
12382
+
},
12383
+
"engines": {
12384
+
"node": ">= 0.4"
12385
+
}
12386
+
},
12387
+
"node_modules/set-function-name": {
12388
+
"version": "2.0.2",
12389
+
"resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz",
12390
+
"integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
12391
+
"dev": true,
12392
+
"license": "MIT",
12393
+
"dependencies": {
12394
+
"define-data-property": "^1.1.4",
12395
+
"es-errors": "^1.3.0",
12396
+
"functions-have-names": "^1.2.3",
12397
+
"has-property-descriptors": "^1.0.2"
12398
+
},
12399
+
"engines": {
12400
+
"node": ">= 0.4"
12401
+
}
12402
+
},
12403
+
"node_modules/set-proto": {
12404
+
"version": "1.0.0",
12405
+
"resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz",
12406
+
"integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==",
12407
+
"dev": true,
12408
+
"license": "MIT",
12409
+
"dependencies": {
12410
+
"dunder-proto": "^1.0.1",
12411
+
"es-errors": "^1.3.0",
12412
+
"es-object-atoms": "^1.0.0"
12413
+
},
12414
+
"engines": {
12415
+
"node": ">= 0.4"
12416
+
}
12417
+
},
12418
+
"node_modules/shebang-command": {
12419
+
"version": "2.0.0",
12420
+
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
12421
+
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
12422
+
"dev": true,
12423
+
"license": "MIT",
12424
+
"peer": true,
12425
+
"dependencies": {
12426
+
"shebang-regex": "^3.0.0"
12427
+
},
12428
+
"engines": {
12429
+
"node": ">=8"
12430
+
}
12431
+
},
12432
+
"node_modules/shebang-regex": {
12433
+
"version": "3.0.0",
12434
+
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
12435
+
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
12436
+
"dev": true,
12437
+
"license": "MIT",
12438
+
"peer": true,
12439
+
"engines": {
12440
+
"node": ">=8"
12441
+
}
12442
+
},
12443
+
"node_modules/side-channel": {
12444
+
"version": "1.1.0",
12445
+
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
12446
+
"integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
12447
+
"dev": true,
12448
+
"license": "MIT",
12449
+
"dependencies": {
12450
+
"es-errors": "^1.3.0",
12451
+
"object-inspect": "^1.13.3",
12452
+
"side-channel-list": "^1.0.0",
12453
+
"side-channel-map": "^1.0.1",
12454
+
"side-channel-weakmap": "^1.0.2"
12455
+
},
12456
+
"engines": {
12457
+
"node": ">= 0.4"
12458
+
},
12459
+
"funding": {
12460
+
"url": "https://github.com/sponsors/ljharb"
12461
+
}
12462
+
},
12463
+
"node_modules/side-channel-list": {
12464
+
"version": "1.0.0",
12465
+
"resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
12466
+
"integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
12467
+
"dev": true,
12468
+
"license": "MIT",
12469
+
"dependencies": {
12470
+
"es-errors": "^1.3.0",
12471
+
"object-inspect": "^1.13.3"
12472
+
},
12473
+
"engines": {
12474
+
"node": ">= 0.4"
12475
+
},
12476
+
"funding": {
12477
+
"url": "https://github.com/sponsors/ljharb"
12478
+
}
12479
+
},
12480
+
"node_modules/side-channel-map": {
12481
+
"version": "1.0.1",
12482
+
"resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
12483
+
"integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
12484
+
"dev": true,
12485
+
"license": "MIT",
12486
+
"dependencies": {
12487
+
"call-bound": "^1.0.2",
12488
+
"es-errors": "^1.3.0",
12489
+
"get-intrinsic": "^1.2.5",
12490
+
"object-inspect": "^1.13.3"
12491
+
},
12492
+
"engines": {
12493
+
"node": ">= 0.4"
12494
+
},
12495
+
"funding": {
12496
+
"url": "https://github.com/sponsors/ljharb"
12497
+
}
12498
+
},
12499
+
"node_modules/side-channel-weakmap": {
12500
+
"version": "1.0.2",
12501
+
"resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
12502
+
"integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
12503
+
"dev": true,
12504
+
"license": "MIT",
12505
+
"dependencies": {
12506
+
"call-bound": "^1.0.2",
12507
+
"es-errors": "^1.3.0",
12508
+
"get-intrinsic": "^1.2.5",
12509
+
"object-inspect": "^1.13.3",
12510
+
"side-channel-map": "^1.0.1"
12511
+
},
12512
+
"engines": {
12513
+
"node": ">= 0.4"
12514
+
},
12515
+
"funding": {
12516
+
"url": "https://github.com/sponsors/ljharb"
12517
+
}
12518
+
},
4216
12519
"node_modules/siginfo": {
4217
12520
"version": "2.0.0",
4218
12521
"resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz",
···
4220
12523
"dev": true,
4221
12524
"license": "ISC"
4222
12525
},
12526
+
"node_modules/snake-case": {
12527
+
"version": "3.0.4",
12528
+
"resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz",
12529
+
"integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==",
12530
+
"dev": true,
12531
+
"license": "MIT",
12532
+
"dependencies": {
12533
+
"dot-case": "^3.0.4",
12534
+
"tslib": "^2.0.3"
12535
+
}
12536
+
},
4223
12537
"node_modules/solid-js": {
4224
12538
"version": "1.9.9",
4225
12539
"resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.9.9.tgz",
···
4269
12583
"dev": true,
4270
12584
"license": "MIT"
4271
12585
},
12586
+
"node_modules/stop-iteration-iterator": {
12587
+
"version": "1.1.0",
12588
+
"resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz",
12589
+
"integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==",
12590
+
"dev": true,
12591
+
"license": "MIT",
12592
+
"dependencies": {
12593
+
"es-errors": "^1.3.0",
12594
+
"internal-slot": "^1.1.0"
12595
+
},
12596
+
"engines": {
12597
+
"node": ">= 0.4"
12598
+
}
12599
+
},
12600
+
"node_modules/string-ts": {
12601
+
"version": "2.2.1",
12602
+
"resolved": "https://registry.npmjs.org/string-ts/-/string-ts-2.2.1.tgz",
12603
+
"integrity": "sha512-Q2u0gko67PLLhbte5HmPfdOjNvUKbKQM+mCNQae6jE91DmoFHY6HH9GcdqCeNx87DZ2KKjiFxmA0R/42OneGWw==",
12604
+
"dev": true,
12605
+
"license": "MIT"
12606
+
},
12607
+
"node_modules/string.prototype.matchall": {
12608
+
"version": "4.0.12",
12609
+
"resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz",
12610
+
"integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==",
12611
+
"dev": true,
12612
+
"license": "MIT",
12613
+
"dependencies": {
12614
+
"call-bind": "^1.0.8",
12615
+
"call-bound": "^1.0.3",
12616
+
"define-properties": "^1.2.1",
12617
+
"es-abstract": "^1.23.6",
12618
+
"es-errors": "^1.3.0",
12619
+
"es-object-atoms": "^1.0.0",
12620
+
"get-intrinsic": "^1.2.6",
12621
+
"gopd": "^1.2.0",
12622
+
"has-symbols": "^1.1.0",
12623
+
"internal-slot": "^1.1.0",
12624
+
"regexp.prototype.flags": "^1.5.3",
12625
+
"set-function-name": "^2.0.2",
12626
+
"side-channel": "^1.1.0"
12627
+
},
12628
+
"engines": {
12629
+
"node": ">= 0.4"
12630
+
},
12631
+
"funding": {
12632
+
"url": "https://github.com/sponsors/ljharb"
12633
+
}
12634
+
},
12635
+
"node_modules/string.prototype.repeat": {
12636
+
"version": "1.0.0",
12637
+
"resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz",
12638
+
"integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==",
12639
+
"dev": true,
12640
+
"license": "MIT",
12641
+
"dependencies": {
12642
+
"define-properties": "^1.1.3",
12643
+
"es-abstract": "^1.17.5"
12644
+
}
12645
+
},
12646
+
"node_modules/string.prototype.trim": {
12647
+
"version": "1.2.10",
12648
+
"resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz",
12649
+
"integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==",
12650
+
"dev": true,
12651
+
"license": "MIT",
12652
+
"dependencies": {
12653
+
"call-bind": "^1.0.8",
12654
+
"call-bound": "^1.0.2",
12655
+
"define-data-property": "^1.1.4",
12656
+
"define-properties": "^1.2.1",
12657
+
"es-abstract": "^1.23.5",
12658
+
"es-object-atoms": "^1.0.0",
12659
+
"has-property-descriptors": "^1.0.2"
12660
+
},
12661
+
"engines": {
12662
+
"node": ">= 0.4"
12663
+
},
12664
+
"funding": {
12665
+
"url": "https://github.com/sponsors/ljharb"
12666
+
}
12667
+
},
12668
+
"node_modules/string.prototype.trimend": {
12669
+
"version": "1.0.9",
12670
+
"resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz",
12671
+
"integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==",
12672
+
"dev": true,
12673
+
"license": "MIT",
12674
+
"dependencies": {
12675
+
"call-bind": "^1.0.8",
12676
+
"call-bound": "^1.0.2",
12677
+
"define-properties": "^1.2.1",
12678
+
"es-object-atoms": "^1.0.0"
12679
+
},
12680
+
"engines": {
12681
+
"node": ">= 0.4"
12682
+
},
12683
+
"funding": {
12684
+
"url": "https://github.com/sponsors/ljharb"
12685
+
}
12686
+
},
12687
+
"node_modules/string.prototype.trimstart": {
12688
+
"version": "1.0.8",
12689
+
"resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz",
12690
+
"integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==",
12691
+
"dev": true,
12692
+
"license": "MIT",
12693
+
"dependencies": {
12694
+
"call-bind": "^1.0.7",
12695
+
"define-properties": "^1.2.1",
12696
+
"es-object-atoms": "^1.0.0"
12697
+
},
12698
+
"engines": {
12699
+
"node": ">= 0.4"
12700
+
},
12701
+
"funding": {
12702
+
"url": "https://github.com/sponsors/ljharb"
12703
+
}
12704
+
},
12705
+
"node_modules/strip-json-comments": {
12706
+
"version": "3.1.1",
12707
+
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
12708
+
"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
12709
+
"dev": true,
12710
+
"license": "MIT",
12711
+
"peer": true,
12712
+
"engines": {
12713
+
"node": ">=8"
12714
+
},
12715
+
"funding": {
12716
+
"url": "https://github.com/sponsors/sindresorhus"
12717
+
}
12718
+
},
4272
12719
"node_modules/strip-literal": {
4273
-
"version": "3.0.0",
4274
-
"resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.0.0.tgz",
4275
-
"integrity": "sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==",
12720
+
"version": "3.1.0",
12721
+
"resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz",
12722
+
"integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==",
4276
12723
"dev": true,
4277
12724
"license": "MIT",
4278
12725
"dependencies": {
···
4295
12742
"integrity": "sha512-9pP/CVNp4NF2MNlRzLwQkjiTgKKe9WYXrLh9+8QokWmMxz+zt2mf1utkWLco26IuA3AfVcTb//qtlTIjY3VHxA==",
4296
12743
"license": "MIT"
4297
12744
},
12745
+
"node_modules/supports-color": {
12746
+
"version": "7.2.0",
12747
+
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
12748
+
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
12749
+
"dev": true,
12750
+
"license": "MIT",
12751
+
"peer": true,
12752
+
"dependencies": {
12753
+
"has-flag": "^4.0.0"
12754
+
},
12755
+
"engines": {
12756
+
"node": ">=8"
12757
+
}
12758
+
},
12759
+
"node_modules/supports-preserve-symlinks-flag": {
12760
+
"version": "1.0.0",
12761
+
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
12762
+
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
12763
+
"dev": true,
12764
+
"license": "MIT",
12765
+
"engines": {
12766
+
"node": ">= 0.4"
12767
+
},
12768
+
"funding": {
12769
+
"url": "https://github.com/sponsors/ljharb"
12770
+
}
12771
+
},
12772
+
"node_modules/svg-parser": {
12773
+
"version": "2.0.4",
12774
+
"resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz",
12775
+
"integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==",
12776
+
"dev": true,
12777
+
"license": "MIT"
12778
+
},
4298
12779
"node_modules/symbol-tree": {
4299
12780
"version": "3.2.4",
4300
12781
"resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
···
4307
12788
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.12.tgz",
4308
12789
"integrity": "sha512-DzFtxOi+7NsFf7DBtI3BJsynR+0Yp6etH+nRPTbpWnS2pZBaSksv/JGctNwSWzbFjp0vxSqknaUylseZqMDGrA==",
4309
12790
"license": "MIT"
12791
+
},
12792
+
"node_modules/tanstack-router-keepalive": {
12793
+
"version": "1.0.0",
12794
+
"resolved": "https://registry.npmjs.org/tanstack-router-keepalive/-/tanstack-router-keepalive-1.0.0.tgz",
12795
+
"integrity": "sha512-SxMl9sgIZGjB4OZvGXufTz14ygmZi+eAbrhz3sjmXYZzhSQOekx5LYi9TvKcMXVu8fQR6W/itF5hdglqD6WB/w==",
12796
+
"license": "MIT",
12797
+
"dependencies": {
12798
+
"eventemitter3": "^5.0.1",
12799
+
"lodash.clonedeep": "^4.5.0"
12800
+
}
4310
12801
},
4311
12802
"node_modules/tapable": {
4312
12803
"version": "2.2.3",
···
4380
12871
"license": "MIT"
4381
12872
},
4382
12873
"node_modules/tinyglobby": {
4383
-
"version": "0.2.14",
4384
-
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz",
4385
-
"integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==",
12874
+
"version": "0.2.15",
12875
+
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
12876
+
"integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
4386
12877
"license": "MIT",
4387
12878
"dependencies": {
4388
-
"fdir": "^6.4.4",
4389
-
"picomatch": "^4.0.2"
12879
+
"fdir": "^6.5.0",
12880
+
"picomatch": "^4.0.3"
4390
12881
},
4391
12882
"engines": {
4392
12883
"node": ">=12.0.0"
···
4521
13012
"node": ">=18"
4522
13013
}
4523
13014
},
13015
+
"node_modules/ts-api-utils": {
13016
+
"version": "2.1.0",
13017
+
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz",
13018
+
"integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==",
13019
+
"dev": true,
13020
+
"license": "MIT",
13021
+
"engines": {
13022
+
"node": ">=18.12"
13023
+
},
13024
+
"peerDependencies": {
13025
+
"typescript": ">=4.8.4"
13026
+
}
13027
+
},
13028
+
"node_modules/ts-declaration-location": {
13029
+
"version": "1.0.7",
13030
+
"resolved": "https://registry.npmjs.org/ts-declaration-location/-/ts-declaration-location-1.0.7.tgz",
13031
+
"integrity": "sha512-EDyGAwH1gO0Ausm9gV6T2nUvBgXT5kGoCMJPllOaooZ+4VvJiKBdZE7wK18N1deEowhcUptS+5GXZK8U/fvpwA==",
13032
+
"dev": true,
13033
+
"funding": [
13034
+
{
13035
+
"type": "ko-fi",
13036
+
"url": "https://ko-fi.com/rebeccastevens"
13037
+
},
13038
+
{
13039
+
"type": "tidelift",
13040
+
"url": "https://tidelift.com/funding/github/npm/ts-declaration-location"
13041
+
}
13042
+
],
13043
+
"license": "BSD-3-Clause",
13044
+
"dependencies": {
13045
+
"picomatch": "^4.0.2"
13046
+
},
13047
+
"peerDependencies": {
13048
+
"typescript": ">=4.0.0"
13049
+
}
13050
+
},
13051
+
"node_modules/ts-declaration-location/node_modules/picomatch": {
13052
+
"version": "4.0.3",
13053
+
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
13054
+
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
13055
+
"dev": true,
13056
+
"license": "MIT",
13057
+
"engines": {
13058
+
"node": ">=12"
13059
+
},
13060
+
"funding": {
13061
+
"url": "https://github.com/sponsors/jonschlinkert"
13062
+
}
13063
+
},
13064
+
"node_modules/ts-pattern": {
13065
+
"version": "5.8.0",
13066
+
"resolved": "https://registry.npmjs.org/ts-pattern/-/ts-pattern-5.8.0.tgz",
13067
+
"integrity": "sha512-kIjN2qmWiHnhgr5DAkAafF9fwb0T5OhMVSWrm8XEdTFnX6+wfXwYOFjeF86UZ54vduqiR7BfqScFmXSzSaH8oA==",
13068
+
"dev": true,
13069
+
"license": "MIT"
13070
+
},
4524
13071
"node_modules/tslib": {
4525
13072
"version": "2.8.1",
4526
13073
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
···
4552
13099
"integrity": "sha512-SDpZ4f7sZmwHF6XG5PF0KWuP18pH/kNG04MhTcpqJby7Lk/D3TS/lCYd+RSg0rIAAVi1LDgSIo1yJs9kmHlhgw==",
4553
13100
"license": "MIT"
4554
13101
},
13102
+
"node_modules/type-check": {
13103
+
"version": "0.4.0",
13104
+
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
13105
+
"integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
13106
+
"dev": true,
13107
+
"license": "MIT",
13108
+
"peer": true,
13109
+
"dependencies": {
13110
+
"prelude-ls": "^1.2.1"
13111
+
},
13112
+
"engines": {
13113
+
"node": ">= 0.8.0"
13114
+
}
13115
+
},
13116
+
"node_modules/typed-array-buffer": {
13117
+
"version": "1.0.3",
13118
+
"resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz",
13119
+
"integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==",
13120
+
"dev": true,
13121
+
"license": "MIT",
13122
+
"dependencies": {
13123
+
"call-bound": "^1.0.3",
13124
+
"es-errors": "^1.3.0",
13125
+
"is-typed-array": "^1.1.14"
13126
+
},
13127
+
"engines": {
13128
+
"node": ">= 0.4"
13129
+
}
13130
+
},
13131
+
"node_modules/typed-array-byte-length": {
13132
+
"version": "1.0.3",
13133
+
"resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz",
13134
+
"integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==",
13135
+
"dev": true,
13136
+
"license": "MIT",
13137
+
"dependencies": {
13138
+
"call-bind": "^1.0.8",
13139
+
"for-each": "^0.3.3",
13140
+
"gopd": "^1.2.0",
13141
+
"has-proto": "^1.2.0",
13142
+
"is-typed-array": "^1.1.14"
13143
+
},
13144
+
"engines": {
13145
+
"node": ">= 0.4"
13146
+
},
13147
+
"funding": {
13148
+
"url": "https://github.com/sponsors/ljharb"
13149
+
}
13150
+
},
13151
+
"node_modules/typed-array-byte-offset": {
13152
+
"version": "1.0.4",
13153
+
"resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz",
13154
+
"integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==",
13155
+
"dev": true,
13156
+
"license": "MIT",
13157
+
"dependencies": {
13158
+
"available-typed-arrays": "^1.0.7",
13159
+
"call-bind": "^1.0.8",
13160
+
"for-each": "^0.3.3",
13161
+
"gopd": "^1.2.0",
13162
+
"has-proto": "^1.2.0",
13163
+
"is-typed-array": "^1.1.15",
13164
+
"reflect.getprototypeof": "^1.0.9"
13165
+
},
13166
+
"engines": {
13167
+
"node": ">= 0.4"
13168
+
},
13169
+
"funding": {
13170
+
"url": "https://github.com/sponsors/ljharb"
13171
+
}
13172
+
},
13173
+
"node_modules/typed-array-length": {
13174
+
"version": "1.0.7",
13175
+
"resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz",
13176
+
"integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==",
13177
+
"dev": true,
13178
+
"license": "MIT",
13179
+
"dependencies": {
13180
+
"call-bind": "^1.0.7",
13181
+
"for-each": "^0.3.3",
13182
+
"gopd": "^1.0.1",
13183
+
"is-typed-array": "^1.1.13",
13184
+
"possible-typed-array-names": "^1.0.0",
13185
+
"reflect.getprototypeof": "^1.0.6"
13186
+
},
13187
+
"engines": {
13188
+
"node": ">= 0.4"
13189
+
},
13190
+
"funding": {
13191
+
"url": "https://github.com/sponsors/ljharb"
13192
+
}
13193
+
},
4555
13194
"node_modules/typescript": {
4556
-
"version": "5.9.2",
4557
-
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz",
4558
-
"integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
13195
+
"version": "5.9.3",
13196
+
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
13197
+
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
4559
13198
"dev": true,
4560
13199
"license": "Apache-2.0",
4561
13200
"bin": {
···
4566
13205
"node": ">=14.17"
4567
13206
}
4568
13207
},
13208
+
"node_modules/typescript-eslint": {
13209
+
"version": "8.46.1",
13210
+
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.46.1.tgz",
13211
+
"integrity": "sha512-VHgijW803JafdSsDO8I761r3SHrgk4T00IdyQ+/UsthtgPRsBWQLqoSxOolxTpxRKi1kGXK0bSz4CoAc9ObqJA==",
13212
+
"dev": true,
13213
+
"license": "MIT",
13214
+
"dependencies": {
13215
+
"@typescript-eslint/eslint-plugin": "8.46.1",
13216
+
"@typescript-eslint/parser": "8.46.1",
13217
+
"@typescript-eslint/typescript-estree": "8.46.1",
13218
+
"@typescript-eslint/utils": "8.46.1"
13219
+
},
13220
+
"engines": {
13221
+
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
13222
+
},
13223
+
"funding": {
13224
+
"type": "opencollective",
13225
+
"url": "https://opencollective.com/typescript-eslint"
13226
+
},
13227
+
"peerDependencies": {
13228
+
"eslint": "^8.57.0 || ^9.0.0",
13229
+
"typescript": ">=4.8.4 <6.0.0"
13230
+
}
13231
+
},
4569
13232
"node_modules/ua-parser-js": {
4570
13233
"version": "1.0.41",
4571
13234
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.41.tgz",
···
4592
13255
"node": "*"
4593
13256
}
4594
13257
},
13258
+
"node_modules/ufo": {
13259
+
"version": "1.6.1",
13260
+
"resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.1.tgz",
13261
+
"integrity": "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==",
13262
+
"dev": true,
13263
+
"license": "MIT"
13264
+
},
4595
13265
"node_modules/uint8arrays": {
4596
13266
"version": "3.0.0",
4597
13267
"resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.0.0.tgz",
···
4601
13271
"multiformats": "^9.4.2"
4602
13272
}
4603
13273
},
13274
+
"node_modules/unbox-primitive": {
13275
+
"version": "1.1.0",
13276
+
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz",
13277
+
"integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==",
13278
+
"dev": true,
13279
+
"license": "MIT",
13280
+
"dependencies": {
13281
+
"call-bound": "^1.0.3",
13282
+
"has-bigints": "^1.0.2",
13283
+
"has-symbols": "^1.1.0",
13284
+
"which-boxed-primitive": "^1.1.1"
13285
+
},
13286
+
"engines": {
13287
+
"node": ">= 0.4"
13288
+
},
13289
+
"funding": {
13290
+
"url": "https://github.com/sponsors/ljharb"
13291
+
}
13292
+
},
4604
13293
"node_modules/undici-types": {
4605
13294
"version": "7.10.0",
4606
13295
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz",
···
4608
13297
"devOptional": true,
4609
13298
"license": "MIT"
4610
13299
},
13300
+
"node_modules/unimport": {
13301
+
"version": "5.5.0",
13302
+
"resolved": "https://registry.npmjs.org/unimport/-/unimport-5.5.0.tgz",
13303
+
"integrity": "sha512-/JpWMG9s1nBSlXJAQ8EREFTFy3oy6USFd8T6AoBaw1q2GGcF4R9yp3ofg32UODZlYEO5VD0EWE1RpI9XDWyPYg==",
13304
+
"dev": true,
13305
+
"license": "MIT",
13306
+
"dependencies": {
13307
+
"acorn": "^8.15.0",
13308
+
"escape-string-regexp": "^5.0.0",
13309
+
"estree-walker": "^3.0.3",
13310
+
"local-pkg": "^1.1.2",
13311
+
"magic-string": "^0.30.19",
13312
+
"mlly": "^1.8.0",
13313
+
"pathe": "^2.0.3",
13314
+
"picomatch": "^4.0.3",
13315
+
"pkg-types": "^2.3.0",
13316
+
"scule": "^1.3.0",
13317
+
"strip-literal": "^3.1.0",
13318
+
"tinyglobby": "^0.2.15",
13319
+
"unplugin": "^2.3.10",
13320
+
"unplugin-utils": "^0.3.0"
13321
+
},
13322
+
"engines": {
13323
+
"node": ">=18.12.0"
13324
+
}
13325
+
},
13326
+
"node_modules/unimport/node_modules/escape-string-regexp": {
13327
+
"version": "5.0.0",
13328
+
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
13329
+
"integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==",
13330
+
"dev": true,
13331
+
"license": "MIT",
13332
+
"engines": {
13333
+
"node": ">=12"
13334
+
},
13335
+
"funding": {
13336
+
"url": "https://github.com/sponsors/sindresorhus"
13337
+
}
13338
+
},
13339
+
"node_modules/unimport/node_modules/picomatch": {
13340
+
"version": "4.0.3",
13341
+
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
13342
+
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
13343
+
"dev": true,
13344
+
"license": "MIT",
13345
+
"engines": {
13346
+
"node": ">=12"
13347
+
},
13348
+
"funding": {
13349
+
"url": "https://github.com/sponsors/jonschlinkert"
13350
+
}
13351
+
},
4611
13352
"node_modules/unplugin": {
4612
-
"version": "2.3.9",
4613
-
"resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.9.tgz",
4614
-
"integrity": "sha512-2dcbZq6aprwXTkzptq3k5qm5B8cvpjG9ynPd5fyM2wDJuuF7PeUK64Sxf0d+X1ZyDOeGydbNzMqBSIVlH8GIfA==",
13353
+
"version": "2.3.10",
13354
+
"resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.10.tgz",
13355
+
"integrity": "sha512-6NCPkv1ClwH+/BGE9QeoTIl09nuiAt0gS28nn1PvYXsGKRwM2TCbFA2QiilmehPDTXIe684k4rZI1yl3A1PCUw==",
4615
13356
"license": "MIT",
4616
13357
"dependencies": {
4617
13358
"@jridgewell/remapping": "^2.3.5",
···
4623
13364
"node": ">=18.12.0"
4624
13365
}
4625
13366
},
13367
+
"node_modules/unplugin-auto-import": {
13368
+
"version": "20.2.0",
13369
+
"resolved": "https://registry.npmjs.org/unplugin-auto-import/-/unplugin-auto-import-20.2.0.tgz",
13370
+
"integrity": "sha512-vfBI/SvD9hJqYNinipVOAj5n8dS8DJXFlCKFR5iLDp2SaQwsfdnfLXgZ+34Kd3YY3YEY9omk8XQg0bwos3Q8ug==",
13371
+
"dev": true,
13372
+
"license": "MIT",
13373
+
"dependencies": {
13374
+
"local-pkg": "^1.1.2",
13375
+
"magic-string": "^0.30.19",
13376
+
"picomatch": "^4.0.3",
13377
+
"unimport": "^5.4.0",
13378
+
"unplugin": "^2.3.10",
13379
+
"unplugin-utils": "^0.3.0"
13380
+
},
13381
+
"engines": {
13382
+
"node": ">=14"
13383
+
},
13384
+
"funding": {
13385
+
"url": "https://github.com/sponsors/antfu"
13386
+
},
13387
+
"peerDependencies": {
13388
+
"@nuxt/kit": "^4.0.0",
13389
+
"@vueuse/core": "*"
13390
+
},
13391
+
"peerDependenciesMeta": {
13392
+
"@nuxt/kit": {
13393
+
"optional": true
13394
+
},
13395
+
"@vueuse/core": {
13396
+
"optional": true
13397
+
}
13398
+
}
13399
+
},
13400
+
"node_modules/unplugin-auto-import/node_modules/picomatch": {
13401
+
"version": "4.0.3",
13402
+
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
13403
+
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
13404
+
"dev": true,
13405
+
"license": "MIT",
13406
+
"engines": {
13407
+
"node": ">=12"
13408
+
},
13409
+
"funding": {
13410
+
"url": "https://github.com/sponsors/jonschlinkert"
13411
+
}
13412
+
},
13413
+
"node_modules/unplugin-icons": {
13414
+
"version": "22.4.2",
13415
+
"resolved": "https://registry.npmjs.org/unplugin-icons/-/unplugin-icons-22.4.2.tgz",
13416
+
"integrity": "sha512-Yv15405unO67Chme0Slk0JRA/H2AiAZLK5t7ebt8/ZpTDlBfM4d4En2qD3MX2rzOSkIteQ0syIm3q8MSofeoBA==",
13417
+
"dev": true,
13418
+
"license": "MIT",
13419
+
"dependencies": {
13420
+
"@antfu/install-pkg": "^1.1.0",
13421
+
"@iconify/utils": "^3.0.2",
13422
+
"debug": "^4.4.3",
13423
+
"local-pkg": "^1.1.2",
13424
+
"unplugin": "^2.3.10"
13425
+
},
13426
+
"funding": {
13427
+
"url": "https://github.com/sponsors/antfu"
13428
+
},
13429
+
"peerDependencies": {
13430
+
"@svgr/core": ">=7.0.0",
13431
+
"@svgx/core": "^1.0.1",
13432
+
"@vue/compiler-sfc": "^3.0.2 || ^2.7.0",
13433
+
"svelte": "^3.0.0 || ^4.0.0 || ^5.0.0",
13434
+
"vue-template-compiler": "^2.6.12",
13435
+
"vue-template-es2015-compiler": "^1.9.0"
13436
+
},
13437
+
"peerDependenciesMeta": {
13438
+
"@svgr/core": {
13439
+
"optional": true
13440
+
},
13441
+
"@svgx/core": {
13442
+
"optional": true
13443
+
},
13444
+
"@vue/compiler-sfc": {
13445
+
"optional": true
13446
+
},
13447
+
"svelte": {
13448
+
"optional": true
13449
+
},
13450
+
"vue-template-compiler": {
13451
+
"optional": true
13452
+
},
13453
+
"vue-template-es2015-compiler": {
13454
+
"optional": true
13455
+
}
13456
+
}
13457
+
},
13458
+
"node_modules/unplugin-utils": {
13459
+
"version": "0.3.1",
13460
+
"resolved": "https://registry.npmjs.org/unplugin-utils/-/unplugin-utils-0.3.1.tgz",
13461
+
"integrity": "sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog==",
13462
+
"dev": true,
13463
+
"license": "MIT",
13464
+
"dependencies": {
13465
+
"pathe": "^2.0.3",
13466
+
"picomatch": "^4.0.3"
13467
+
},
13468
+
"engines": {
13469
+
"node": ">=20.19.0"
13470
+
},
13471
+
"funding": {
13472
+
"url": "https://github.com/sponsors/sxzz"
13473
+
}
13474
+
},
13475
+
"node_modules/unplugin-utils/node_modules/picomatch": {
13476
+
"version": "4.0.3",
13477
+
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
13478
+
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
13479
+
"dev": true,
13480
+
"license": "MIT",
13481
+
"engines": {
13482
+
"node": ">=12"
13483
+
},
13484
+
"funding": {
13485
+
"url": "https://github.com/sponsors/jonschlinkert"
13486
+
}
13487
+
},
4626
13488
"node_modules/unplugin/node_modules/picomatch": {
4627
13489
"version": "4.0.3",
4628
13490
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
···
4663
13525
},
4664
13526
"peerDependencies": {
4665
13527
"browserslist": ">= 4.21.0"
13528
+
}
13529
+
},
13530
+
"node_modules/uri-js": {
13531
+
"version": "4.4.1",
13532
+
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
13533
+
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
13534
+
"dev": true,
13535
+
"license": "BSD-2-Clause",
13536
+
"peer": true,
13537
+
"dependencies": {
13538
+
"punycode": "^2.1.0"
13539
+
}
13540
+
},
13541
+
"node_modules/use-callback-ref": {
13542
+
"version": "1.3.3",
13543
+
"resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz",
13544
+
"integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==",
13545
+
"dependencies": {
13546
+
"tslib": "^2.0.0"
13547
+
},
13548
+
"engines": {
13549
+
"node": ">=10"
13550
+
},
13551
+
"peerDependencies": {
13552
+
"@types/react": "*",
13553
+
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
13554
+
},
13555
+
"peerDependenciesMeta": {
13556
+
"@types/react": {
13557
+
"optional": true
13558
+
}
13559
+
}
13560
+
},
13561
+
"node_modules/use-sidecar": {
13562
+
"version": "1.1.3",
13563
+
"resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz",
13564
+
"integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==",
13565
+
"dependencies": {
13566
+
"detect-node-es": "^1.1.0",
13567
+
"tslib": "^2.0.0"
13568
+
},
13569
+
"engines": {
13570
+
"node": ">=10"
13571
+
},
13572
+
"peerDependencies": {
13573
+
"@types/react": "*",
13574
+
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
13575
+
},
13576
+
"peerDependenciesMeta": {
13577
+
"@types/react": {
13578
+
"optional": true
13579
+
}
4666
13580
}
4667
13581
},
4668
13582
"node_modules/use-sync-external-store": {
···
4977
13891
"node": ">=18"
4978
13892
}
4979
13893
},
13894
+
"node_modules/which": {
13895
+
"version": "2.0.2",
13896
+
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
13897
+
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
13898
+
"dev": true,
13899
+
"license": "ISC",
13900
+
"peer": true,
13901
+
"dependencies": {
13902
+
"isexe": "^2.0.0"
13903
+
},
13904
+
"bin": {
13905
+
"node-which": "bin/node-which"
13906
+
},
13907
+
"engines": {
13908
+
"node": ">= 8"
13909
+
}
13910
+
},
13911
+
"node_modules/which-boxed-primitive": {
13912
+
"version": "1.1.1",
13913
+
"resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz",
13914
+
"integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==",
13915
+
"dev": true,
13916
+
"license": "MIT",
13917
+
"dependencies": {
13918
+
"is-bigint": "^1.1.0",
13919
+
"is-boolean-object": "^1.2.1",
13920
+
"is-number-object": "^1.1.1",
13921
+
"is-string": "^1.1.1",
13922
+
"is-symbol": "^1.1.1"
13923
+
},
13924
+
"engines": {
13925
+
"node": ">= 0.4"
13926
+
},
13927
+
"funding": {
13928
+
"url": "https://github.com/sponsors/ljharb"
13929
+
}
13930
+
},
13931
+
"node_modules/which-builtin-type": {
13932
+
"version": "1.2.1",
13933
+
"resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz",
13934
+
"integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==",
13935
+
"dev": true,
13936
+
"license": "MIT",
13937
+
"dependencies": {
13938
+
"call-bound": "^1.0.2",
13939
+
"function.prototype.name": "^1.1.6",
13940
+
"has-tostringtag": "^1.0.2",
13941
+
"is-async-function": "^2.0.0",
13942
+
"is-date-object": "^1.1.0",
13943
+
"is-finalizationregistry": "^1.1.0",
13944
+
"is-generator-function": "^1.0.10",
13945
+
"is-regex": "^1.2.1",
13946
+
"is-weakref": "^1.0.2",
13947
+
"isarray": "^2.0.5",
13948
+
"which-boxed-primitive": "^1.1.0",
13949
+
"which-collection": "^1.0.2",
13950
+
"which-typed-array": "^1.1.16"
13951
+
},
13952
+
"engines": {
13953
+
"node": ">= 0.4"
13954
+
},
13955
+
"funding": {
13956
+
"url": "https://github.com/sponsors/ljharb"
13957
+
}
13958
+
},
13959
+
"node_modules/which-collection": {
13960
+
"version": "1.0.2",
13961
+
"resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz",
13962
+
"integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==",
13963
+
"dev": true,
13964
+
"license": "MIT",
13965
+
"dependencies": {
13966
+
"is-map": "^2.0.3",
13967
+
"is-set": "^2.0.3",
13968
+
"is-weakmap": "^2.0.2",
13969
+
"is-weakset": "^2.0.3"
13970
+
},
13971
+
"engines": {
13972
+
"node": ">= 0.4"
13973
+
},
13974
+
"funding": {
13975
+
"url": "https://github.com/sponsors/ljharb"
13976
+
}
13977
+
},
13978
+
"node_modules/which-typed-array": {
13979
+
"version": "1.1.19",
13980
+
"resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz",
13981
+
"integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==",
13982
+
"dev": true,
13983
+
"license": "MIT",
13984
+
"dependencies": {
13985
+
"available-typed-arrays": "^1.0.7",
13986
+
"call-bind": "^1.0.8",
13987
+
"call-bound": "^1.0.4",
13988
+
"for-each": "^0.3.5",
13989
+
"get-proto": "^1.0.1",
13990
+
"gopd": "^1.2.0",
13991
+
"has-tostringtag": "^1.0.2"
13992
+
},
13993
+
"engines": {
13994
+
"node": ">= 0.4"
13995
+
},
13996
+
"funding": {
13997
+
"url": "https://github.com/sponsors/ljharb"
13998
+
}
13999
+
},
4980
14000
"node_modules/why-is-node-running": {
4981
14001
"version": "2.3.0",
4982
14002
"resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz",
···
5003
14023
"super-media-element": "~1.4.2"
5004
14024
}
5005
14025
},
14026
+
"node_modules/word-wrap": {
14027
+
"version": "1.2.5",
14028
+
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
14029
+
"integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
14030
+
"dev": true,
14031
+
"license": "MIT",
14032
+
"peer": true,
14033
+
"engines": {
14034
+
"node": ">=0.10.0"
14035
+
}
14036
+
},
5006
14037
"node_modules/ws": {
5007
14038
"version": "8.18.3",
5008
14039
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
···
5047
14078
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
5048
14079
"license": "ISC"
5049
14080
},
14081
+
"node_modules/yocto-queue": {
14082
+
"version": "0.1.0",
14083
+
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
14084
+
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
14085
+
"dev": true,
14086
+
"license": "MIT",
14087
+
"peer": true,
14088
+
"engines": {
14089
+
"node": ">=10"
14090
+
},
14091
+
"funding": {
14092
+
"url": "https://github.com/sponsors/sindresorhus"
14093
+
}
14094
+
},
5050
14095
"node_modules/youtube-video-element": {
5051
14096
"version": "1.6.2",
5052
14097
"resolved": "https://registry.npmjs.org/youtube-video-element/-/youtube-video-element-1.6.2.tgz",
···
5060
14105
"license": "MIT",
5061
14106
"funding": {
5062
14107
"url": "https://github.com/sponsors/colinhacks"
14108
+
}
14109
+
},
14110
+
"node_modules/zod-validation-error": {
14111
+
"version": "4.0.2",
14112
+
"resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz",
14113
+
"integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==",
14114
+
"dev": true,
14115
+
"license": "MIT",
14116
+
"engines": {
14117
+
"node": ">=18.0.0"
14118
+
},
14119
+
"peerDependencies": {
14120
+
"zod": "^3.25.0 || ^4.0.0"
5063
14121
}
5064
14122
}
5065
14123
}
+34
-3
package.json
+34
-3
package.json
···
3
3
"private": true,
4
4
"type": "module",
5
5
"scripts": {
6
-
"dev": "vite --port 3000",
7
-
"start": "vite --port 3000",
6
+
"dev": "vite --port 3768",
7
+
"start": "vite --port 3768",
8
8
"build": "vite build && tsc",
9
9
"serve": "vite preview",
10
10
"test": "vitest run"
11
11
},
12
12
"dependencies": {
13
13
"@atproto/api": "^0.16.6",
14
+
"@atproto/oauth-client-browser": "^0.3.33",
15
+
"@radix-ui/react-dialog": "^1.1.15",
16
+
"@radix-ui/react-dropdown-menu": "^2.1.16",
17
+
"@radix-ui/react-hover-card": "^1.1.15",
18
+
"@radix-ui/react-slider": "^1.3.6",
14
19
"@tailwindcss/vite": "^4.0.6",
20
+
"@tanstack/query-sync-storage-persister": "^5.85.6",
15
21
"@tanstack/react-devtools": "^0.2.2",
22
+
"@tanstack/react-query": "^5.85.6",
23
+
"@tanstack/react-query-persist-client": "^5.85.6",
16
24
"@tanstack/react-router": "^1.130.2",
17
25
"@tanstack/react-router-devtools": "^1.131.5",
18
26
"@tanstack/router-plugin": "^1.121.2",
27
+
"dompurify": "^3.3.0",
28
+
"i": "^0.3.7",
19
29
"idb-keyval": "^6.2.2",
30
+
"jotai": "^2.13.1",
31
+
"npm": "^11.6.2",
32
+
"radix-ui": "^1.4.3",
20
33
"react": "^19.0.0",
21
34
"react-dom": "^19.0.0",
22
35
"react-player": "^3.3.2",
23
-
"tailwindcss": "^4.0.6"
36
+
"tailwindcss": "^4.0.6",
37
+
"tanstack-router-keepalive": "^1.0.0"
24
38
},
25
39
"devDependencies": {
40
+
"@eslint-react/eslint-plugin": "^2.2.1",
41
+
"@iconify-icon/react": "^3.0.1",
42
+
"@iconify-json/material-symbols": "^1.2.42",
43
+
"@iconify-json/mdi": "^1.2.3",
44
+
"@iconify/json": "^2.2.396",
45
+
"@svgr/core": "^8.1.0",
46
+
"@svgr/plugin-jsx": "^8.1.0",
26
47
"@testing-library/dom": "^10.4.0",
27
48
"@testing-library/react": "^16.2.0",
28
49
"@types/node": "^24.3.0",
29
50
"@types/react": "^19.0.8",
30
51
"@types/react-dom": "^19.0.3",
52
+
"@typescript-eslint/eslint-plugin": "^8.46.1",
53
+
"@typescript-eslint/parser": "^8.46.1",
31
54
"@vitejs/plugin-react": "^4.3.4",
55
+
"babel-plugin-react-compiler": "^1.0.0",
56
+
"eslint-plugin-react": "^7.37.5",
57
+
"eslint-plugin-react-hooks": "^7.0.0",
58
+
"eslint-plugin-simple-import-sort": "^12.1.1",
59
+
"eslint-plugin-unused-imports": "^4.2.0",
32
60
"jsdom": "^26.0.0",
33
61
"prettier": "^3.6.2",
34
62
"typescript": "^5.7.2",
63
+
"typescript-eslint": "^8.46.1",
64
+
"unplugin-auto-import": "^20.2.0",
65
+
"unplugin-icons": "^22.4.2",
35
66
"vite": "^6.3.5",
36
67
"vitest": "^3.0.5",
37
68
"web-vitals": "^4.2.4"
+2
-2
public/manifest.json
+2
-2
public/manifest.json
public/screenshot.jpg
public/screenshot.jpg
This is a binary file and will not be displayed.
+22
src/auto-imports.d.ts
+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
+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
+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
+150
src/components/Import.tsx
···
1
+
import { AtUri } from "@atproto/api";
2
+
import { useNavigate, type UseNavigateResult } from "@tanstack/react-router";
3
+
import { useState } from "react";
4
+
5
+
/**
6
+
* Basically the best equivalent to Search that i can do
7
+
*/
8
+
export function Import() {
9
+
const [textInput, setTextInput] = useState<string | undefined>();
10
+
const navigate = useNavigate();
11
+
12
+
const handleEnter = () => {
13
+
if (!textInput) return;
14
+
handleImport({
15
+
text: textInput,
16
+
navigate,
17
+
});
18
+
};
19
+
20
+
return (
21
+
<div className="w-full relative">
22
+
<IconMaterialSymbolsSearch className="w-5 h-5 absolute left-4 top-1/2 -translate-y-1/2 text-gray-400 dark:text-gray-500" />
23
+
24
+
<input
25
+
type="text"
26
+
placeholder="Import..."
27
+
value={textInput}
28
+
onChange={(e) => setTextInput(e.target.value)}
29
+
onKeyDown={(e) => {
30
+
if (e.key === "Enter") handleEnter();
31
+
}}
32
+
className="w-full h-12 pl-12 pr-4 rounded-full bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-gray-200 placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-gray-400 dark:focus:ring-gray-500 box-border transition"
33
+
/>
34
+
</div>
35
+
);
36
+
}
37
+
38
+
function handleImport({
39
+
text,
40
+
navigate,
41
+
}: {
42
+
text: string;
43
+
navigate: UseNavigateResult<string>;
44
+
}) {
45
+
const trimmed = text.trim();
46
+
// parse text
47
+
/**
48
+
* text might be
49
+
* 1. bsky dot app url (reddwarf link segments might be uri encoded,)
50
+
* 2. aturi
51
+
* 3. plain handle
52
+
* 4. plain did
53
+
*/
54
+
55
+
// 1. Check if itโs a URL
56
+
try {
57
+
const url = new URL(text);
58
+
const knownHosts = [
59
+
"bsky.app",
60
+
"social.daniela.lol",
61
+
"deer.social",
62
+
"reddwarf.whey.party",
63
+
"reddwarf.app",
64
+
"main.bsky.dev",
65
+
"catsky.social",
66
+
"blacksky.community",
67
+
"red-dwarf-social-app.whey.party",
68
+
"zeppelin.social",
69
+
];
70
+
if (knownHosts.includes(url.hostname)) {
71
+
// parse path to get URI or handle
72
+
const path = decodeURIComponent(url.pathname.slice(1)); // remove leading /
73
+
console.log("BSky URL path:", path);
74
+
navigate({
75
+
to: `/${path}`,
76
+
});
77
+
return;
78
+
}
79
+
} catch {
80
+
// not a URL, continue
81
+
}
82
+
83
+
// 2. Check if text looks like an at-uri
84
+
try {
85
+
if (text.startsWith("at://")) {
86
+
console.log("AT URI detected:", text);
87
+
const aturi = new AtUri(text);
88
+
switch (aturi.collection) {
89
+
case "app.bsky.feed.post": {
90
+
navigate({
91
+
to: "/profile/$did/post/$rkey",
92
+
params: {
93
+
did: aturi.host,
94
+
rkey: aturi.rkey,
95
+
},
96
+
});
97
+
return;
98
+
}
99
+
case "app.bsky.actor.profile": {
100
+
navigate({
101
+
to: "/profile/$did",
102
+
params: {
103
+
did: aturi.host,
104
+
},
105
+
});
106
+
return;
107
+
}
108
+
// todo add more handlers as more routes are added. like feeds, lists, etc etc thanks!
109
+
default: {
110
+
// continue
111
+
}
112
+
}
113
+
}
114
+
} catch {
115
+
// continue
116
+
}
117
+
118
+
// 3. Plain handle (starts with @)
119
+
try {
120
+
if (text.startsWith("@")) {
121
+
const handle = text.slice(1);
122
+
console.log("Handle detected:", handle);
123
+
navigate({ to: "/profile/$did", params: { did: handle } });
124
+
return;
125
+
}
126
+
} catch {
127
+
// continue
128
+
}
129
+
130
+
// 4. Plain DID (starts with did:)
131
+
try {
132
+
if (text.startsWith("did:")) {
133
+
console.log("did detected:", text);
134
+
navigate({ to: "/profile/$did", params: { did: text } });
135
+
return;
136
+
}
137
+
} catch {
138
+
// continue
139
+
}
140
+
141
+
// if all else fails
142
+
143
+
// try {
144
+
// // probably a user?
145
+
// navigate({ to: "/profile/$did", params: { did: text } });
146
+
// return;
147
+
// } catch {
148
+
// // continue
149
+
// }
150
+
}
+168
src/components/InfiniteCustomFeed.tsx
+168
src/components/InfiniteCustomFeed.tsx
···
1
+
import { useQueryClient } from "@tanstack/react-query";
2
+
import * as React from "react";
3
+
4
+
//import { useInView } from "react-intersection-observer";
5
+
import { UniversalPostRendererATURILoader } from "~/components/UniversalPostRenderer";
6
+
import { useAuth } from "~/providers/UnifiedAuthProvider";
7
+
import {
8
+
useInfiniteQueryFeedSkeleton,
9
+
// useQueryArbitrary,
10
+
// useQueryIdentity,
11
+
} from "~/utils/useQuery";
12
+
13
+
interface InfiniteCustomFeedProps {
14
+
feedUri: string;
15
+
pdsUrl?: string;
16
+
feedServiceDid?: string;
17
+
}
18
+
19
+
export function InfiniteCustomFeed({
20
+
feedUri,
21
+
pdsUrl,
22
+
feedServiceDid,
23
+
}: InfiniteCustomFeedProps) {
24
+
const { agent } = useAuth();
25
+
const authed = !!agent?.did;
26
+
27
+
// const identityresultmaybe = useQueryIdentity(agent?.did);
28
+
// const identity = identityresultmaybe?.data;
29
+
// const feedGenGetRecordQuery = useQueryArbitrary(feedUri);
30
+
31
+
const {
32
+
data,
33
+
error,
34
+
isLoading,
35
+
isError,
36
+
hasNextPage,
37
+
fetchNextPage,
38
+
isFetchingNextPage,
39
+
refetch,
40
+
isRefetching,
41
+
queryKey,
42
+
} = useInfiniteQueryFeedSkeleton({
43
+
feedUri: feedUri,
44
+
agent: agent ?? undefined,
45
+
isAuthed: authed ?? false,
46
+
pdsUrl: pdsUrl,
47
+
feedServiceDid: feedServiceDid,
48
+
});
49
+
const queryClient = useQueryClient();
50
+
51
+
52
+
const handleRefresh = () => {
53
+
queryClient.removeQueries({queryKey: queryKey});
54
+
//queryClient.invalidateQueries(["infinite-feed", feedUri] as const);
55
+
refetch();
56
+
};
57
+
58
+
const allPosts = React.useMemo(() => {
59
+
const flattenedPosts = data?.pages.flatMap((page) => page?.feed) ?? [];
60
+
61
+
const seenUris = new Set<string>();
62
+
63
+
return flattenedPosts.filter((item) => {
64
+
if (!item?.post) return false;
65
+
66
+
if (seenUris.has(item.post)) {
67
+
return false;
68
+
}
69
+
70
+
seenUris.add(item.post);
71
+
72
+
return true;
73
+
});
74
+
}, [data]);
75
+
76
+
//const { ref, inView } = useInView();
77
+
78
+
// React.useEffect(() => {
79
+
// if (inView && hasNextPage && !isFetchingNextPage) {
80
+
// fetchNextPage();
81
+
// }
82
+
// }, [inView, hasNextPage, isFetchingNextPage, fetchNextPage]);
83
+
84
+
if (isLoading) {
85
+
return <div className="p-4 text-center text-gray-500">Loading feed...</div>;
86
+
}
87
+
88
+
if (isError) {
89
+
return (
90
+
<div className="p-4 text-center text-red-500">Error: {error.message}</div>
91
+
);
92
+
}
93
+
94
+
// const allPosts =
95
+
// data?.pages.flatMap((page) => {
96
+
// if (page) return page.feed;
97
+
// }) ?? [];
98
+
99
+
if (!allPosts || typeof allPosts !== "object" || allPosts.length === 0) {
100
+
return (
101
+
<div className="p-4 text-center text-gray-500">
102
+
No posts in this feed.
103
+
</div>
104
+
);
105
+
}
106
+
107
+
return (
108
+
<>
109
+
{allPosts.map((item, i) => {
110
+
if (item)
111
+
return (
112
+
<UniversalPostRendererATURILoader
113
+
key={item.post || i}
114
+
atUri={item.post}
115
+
feedviewpost={true}
116
+
repostedby={!!item.reason?.$type && (item.reason as any)?.repost}
117
+
/>
118
+
);
119
+
})}
120
+
{/* allPosts?: {allPosts ? "true" : "false"}
121
+
hasNextPage?: {hasNextPage ? "true" : "false"}
122
+
isFetchingNextPage?: {isFetchingNextPage ? "true" : "false"} */}
123
+
{isFetchingNextPage && (
124
+
<div className="p-4 text-center text-gray-500">Loading more...</div>
125
+
)}
126
+
{hasNextPage && !isFetchingNextPage && (
127
+
<button
128
+
onClick={() => fetchNextPage()}
129
+
className="w-[calc(100%-2rem)] mx-4 my-4 px-4 py-2 bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-gray-200 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-700 font-semibold"
130
+
>
131
+
Load More Posts
132
+
</button>
133
+
)}
134
+
{!hasNextPage && (
135
+
<div className="p-4 text-center text-gray-500">End of feed.</div>
136
+
)}
137
+
<button
138
+
onClick={handleRefresh}
139
+
disabled={isRefetching}
140
+
className="sticky lg:bottom-4 bottom-22 ml-4 w-[42px] h-[42px] z-10 bg-gray-200 dark:bg-gray-800 hover:bg-gray-300 dark:hover:bg-gray-700 text-gray-50 p-[9px] rounded-full shadow-lg transition-transform duration-200 ease-in-out hover:scale-110 disabled:dark:bg-gray-900 disabled:bg-gray-100 disabled:cursor-not-allowed"
141
+
aria-label="Refresh feed"
142
+
>
143
+
<RefreshIcon
144
+
className={`h-6 w-6 text-gray-600 dark:text-gray-400 ${isRefetching && "animate-spin"}`}
145
+
/>
146
+
</button>
147
+
</>
148
+
);
149
+
}
150
+
151
+
const RefreshIcon = (props: React.SVGProps<SVGSVGElement>) => (
152
+
<svg
153
+
xmlns="http://www.w3.org/2000/svg"
154
+
//width={360}
155
+
//height={360}
156
+
viewBox="0 0 24 24"
157
+
{...props}
158
+
>
159
+
<path
160
+
fill="none"
161
+
stroke="currentColor"
162
+
strokeLinecap="round"
163
+
strokeLinejoin="round"
164
+
strokeWidth={2}
165
+
d="M20 11A8.1 8.1 0 0 0 4.5 9M4 5v4h4m-4 4a8.1 8.1 0 0 0 15.5 2m.5 4v-4h-4"
166
+
></path>
167
+
</svg>
168
+
);
+326
-170
src/components/Login.tsx
+326
-170
src/components/Login.tsx
···
1
-
import React, { useEffect, useState, useRef } from "react";
2
-
import { useAuth } from "~/providers/PassAuthProvider";
1
+
// src/components/Login.tsx
2
+
import AtpAgent, { Agent } from "@atproto/api";
3
+
import { useAtom } from "jotai";
4
+
import React, { useEffect, useRef, useState } from "react";
3
5
4
-
interface LoginProps {
6
+
import { useAuth } from "~/providers/UnifiedAuthProvider";
7
+
import { imgCDNAtom } from "~/utils/atoms";
8
+
import { useQueryIdentity, useQueryProfile } from "~/utils/useQuery";
9
+
10
+
import { Button } from "./radix-m3-rd/Button";
11
+
12
+
// --- 1. The Main Component (Orchestrator with `compact` prop) ---
13
+
export default function Login({
14
+
compact = false,
15
+
popup = false,
16
+
}: {
5
17
compact?: boolean;
18
+
popup?: boolean;
19
+
}) {
20
+
const { status, agent, logout } = useAuth();
21
+
22
+
// Loading state can be styled differently based on the prop
23
+
if (status === "loading") {
24
+
return (
25
+
<div
26
+
className={
27
+
compact
28
+
? "flex items-center justify-center p-1"
29
+
: "p-6 bg-gray-100 dark:bg-gray-900 rounded-xl shadow border border-gray-200 dark:border-gray-800 mt-4 mx-4 flex justify-center items-center h-[280px]"
30
+
}
31
+
>
32
+
<span
33
+
className={`border-t-transparent rounded-full animate-spin ${
34
+
compact
35
+
? "w-5 h-5 border-2 border-gray-400"
36
+
: "w-8 h-8 border-4 border-gray-400"
37
+
}`}
38
+
/>
39
+
</div>
40
+
);
41
+
}
42
+
43
+
// --- LOGGED IN STATE ---
44
+
if (status === "signedIn") {
45
+
// Large view
46
+
if (!compact) {
47
+
return (
48
+
<div className="p-4 bg-gray-100 dark:bg-gray-900 rounded-xl border-gray-200 dark:border-gray-800 mt-4 mx-4">
49
+
<div className="flex flex-col items-center justify-center text-center">
50
+
<p className="text-lg font-semibold mb-4 text-gray-800 dark:text-gray-100">
51
+
You are logged in!
52
+
</p>
53
+
<ProfileThing agent={agent} large />
54
+
<Button
55
+
onClick={logout}
56
+
className="mt-4"
57
+
>
58
+
Log out
59
+
</Button>
60
+
</div>
61
+
</div>
62
+
);
63
+
}
64
+
// Compact view
65
+
return (
66
+
<div className="flex items-center gap-4">
67
+
<ProfileThing agent={agent} />
68
+
<button
69
+
onClick={logout}
70
+
className="text-sm bg-gray-600 hover:bg-gray-700 text-white rounded px-3 py-1 font-medium transition-colors"
71
+
>
72
+
Log out
73
+
</button>
74
+
</div>
75
+
);
76
+
}
77
+
78
+
// --- LOGGED OUT STATE ---
79
+
if (!compact) {
80
+
// Large view renders the form directly in the card
81
+
return (
82
+
<div className="p-4 bg-gray-100 dark:bg-gray-900 rounded-xl border-gray-200 dark:border-gray-800 mt-4 mx-4">
83
+
<UnifiedLoginForm />
84
+
</div>
85
+
);
86
+
}
87
+
88
+
// Compact view renders a button that toggles the form in a dropdown
89
+
return <CompactLoginButton popup={popup} />;
6
90
}
7
91
8
-
export default function Login({ compact = false }: LoginProps) {
9
-
const { loginStatus, login, logout, loading, authed } = useAuth();
10
-
const [user, setUser] = useState("");
11
-
const [password, setPassword] = useState("");
12
-
const [serviceURL, setServiceURL] = useState("bsky.social");
13
-
const [showLoginForm, setShowLoginForm] = useState(false);
92
+
// --- 2. The Reusable, Self-Contained Login Form Component ---
93
+
export function UnifiedLoginForm() {
94
+
const [mode, setMode] = useState<"oauth" | "password">("oauth");
95
+
96
+
return (
97
+
<div>
98
+
<div className="flex bg-gray-300 rounded-full dark:bg-gray-700 mb-4">
99
+
<TabButton
100
+
label="OAuth"
101
+
active={mode === "oauth"}
102
+
onClick={() => setMode("oauth")}
103
+
/>
104
+
<TabButton
105
+
label="Password"
106
+
active={mode === "password"}
107
+
onClick={() => setMode("password")}
108
+
/>
109
+
</div>
110
+
{mode === "oauth" ? <OAuthForm /> : <PasswordForm />}
111
+
</div>
112
+
);
113
+
}
114
+
115
+
// --- 3. Helper components for layouts, forms, and UI ---
116
+
117
+
// A new component to contain the logic for the compact dropdown
118
+
const CompactLoginButton = ({ popup }: { popup?: boolean }) => {
119
+
const [showForm, setShowForm] = useState(false);
14
120
const formRef = useRef<HTMLDivElement>(null);
15
121
16
122
useEffect(() => {
17
123
function handleClickOutside(event: MouseEvent) {
18
124
if (formRef.current && !formRef.current.contains(event.target as Node)) {
19
-
setShowLoginForm(false);
125
+
setShowForm(false);
20
126
}
21
127
}
22
-
23
-
if (showLoginForm) {
128
+
if (showForm) {
24
129
document.addEventListener("mousedown", handleClickOutside);
25
130
}
26
-
27
131
return () => {
28
132
document.removeEventListener("mousedown", handleClickOutside);
29
133
};
30
-
}, [showLoginForm]);
134
+
}, [showForm]);
31
135
32
-
if (loading) {
33
-
return (
34
-
<div className="flex items-center justify-center p-6 text-gray-500 dark:text-gray-400">
35
-
Loading...
36
-
</div>
37
-
);
38
-
}
136
+
return (
137
+
<div className="relative" ref={formRef}>
138
+
<button
139
+
onClick={() => setShowForm(!showForm)}
140
+
className="text-sm bg-gray-600 hover:bg-gray-700 text-white rounded-full px-3 py-1 font-medium transition-colors"
141
+
>
142
+
Log in
143
+
</button>
144
+
{showForm && (
145
+
<div
146
+
className={`absolute ${popup ? `bottom-[calc(100%)]` : `top-full`} right-0 mt-2 w-80 bg-white dark:bg-gray-900 rounded-lg shadow-lg border border-gray-200 dark:border-gray-700 p-4 z-50`}
147
+
>
148
+
<UnifiedLoginForm />
149
+
</div>
150
+
)}
151
+
</div>
152
+
);
153
+
};
39
154
40
-
if (compact) {
41
-
if (authed) {
42
-
return (
155
+
const TabButton = ({
156
+
label,
157
+
active,
158
+
onClick,
159
+
}: {
160
+
label: string;
161
+
active: boolean;
162
+
onClick: () => void;
163
+
}) => (
164
+
<button
165
+
onClick={onClick}
166
+
className={`px-4 py-2 text-sm font-medium transition-colors rounded-full flex-1 ${
167
+
active
168
+
? "text-gray-50 dark:text-gray-200 border-gray-500 bg-gray-400 dark:bg-gray-500"
169
+
: "text-gray-600 dark:text-gray-300 hover:text-gray-700 dark:hover:text-gray-200"
170
+
}`}
171
+
>
172
+
{label}
173
+
</button>
174
+
);
175
+
176
+
const OAuthForm = () => {
177
+
const { loginWithOAuth } = useAuth();
178
+
const [handle, setHandle] = useState("");
179
+
180
+
useEffect(() => {
181
+
const lastHandle = localStorage.getItem("lastHandle");
182
+
if (lastHandle) setHandle(lastHandle);
183
+
}, []);
184
+
185
+
const handleSubmit = (e: React.FormEvent) => {
186
+
e.preventDefault();
187
+
if (handle.trim()) {
188
+
localStorage.setItem("lastHandle", handle);
189
+
loginWithOAuth(handle);
190
+
}
191
+
};
192
+
return (
193
+
<form onSubmit={handleSubmit} className="flex flex-col gap-3">
194
+
<p className="text-xs text-gray-500 dark:text-gray-400">
195
+
Sign in with AT. Your password is never shared.
196
+
</p>
197
+
{/* <input
198
+
type="text"
199
+
placeholder="handle.bsky.social"
200
+
value={handle}
201
+
onChange={(e) => setHandle(e.target.value)}
202
+
className="px-3 py-2 rounded border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 text-sm focus:outline-none focus:ring-2 focus:ring-gray-500"
203
+
/> */}
204
+
<div className="flex flex-col gap-3">
205
+
<div className="m3input-field m3input-label m3input-border size-md flex-1">
206
+
<input
207
+
type="text"
208
+
placeholder=" "
209
+
value={handle}
210
+
onChange={(e) => setHandle(e.target.value)}
211
+
/>
212
+
<label>AT Handle</label>
213
+
</div>
43
214
<button
44
-
onClick={logout}
45
-
className="text-sm bg-gray-600 hover:bg-gray-700 text-white rounded px-3 py-1 font-medium transition-colors"
215
+
type="submit"
216
+
className="bg-gray-600 hover:bg-gray-700 text-white rounded-full px-4 py-2 font-medium text-sm transition-colors"
46
217
>
47
-
Log out
218
+
Log in
48
219
</button>
49
-
);
50
-
} else {
51
-
return (
52
-
<div className="relative" ref={formRef}>
53
-
<button
54
-
onClick={() => setShowLoginForm(!showLoginForm)}
55
-
className="text-sm bg-gray-600 hover:bg-gray-700 text-white rounded px-3 py-1 font-medium transition-colors"
56
-
>
57
-
Log in
58
-
</button>
59
-
{showLoginForm && (
60
-
<div className="absolute top-full right-0 mt-2 w-80 bg-white dark:bg-gray-900 rounded-lg shadow-lg border border-gray-200 dark:border-gray-700 p-4 z-50">
61
-
<form
62
-
onSubmit={(e) => {
63
-
e.preventDefault();
64
-
login(user, password, `https://${serviceURL}`);
65
-
setShowLoginForm(false);
66
-
}}
67
-
className="flex flex-col gap-3"
68
-
>
69
-
<p className="text-xs text-gray-500 dark:text-gray-400">
70
-
sorry for the temporary login,
71
-
<br />
72
-
oauth will come soon enough i swear
73
-
</p>
74
-
<input
75
-
type="text"
76
-
placeholder="Username"
77
-
value={user}
78
-
onChange={(e) => setUser(e.target.value)}
79
-
className="px-3 py-2 rounded border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
80
-
autoComplete="username"
81
-
/>
82
-
<input
83
-
type="password"
84
-
placeholder="Password"
85
-
value={password}
86
-
onChange={(e) => setPassword(e.target.value)}
87
-
className="px-3 py-2 rounded border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
88
-
autoComplete="current-password"
89
-
/>
90
-
<input
91
-
type="text"
92
-
placeholder="bsky.social"
93
-
value={serviceURL}
94
-
onChange={(e) => setServiceURL(e.target.value)}
95
-
className="px-3 py-2 rounded border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
96
-
/>
97
-
<button
98
-
type="submit"
99
-
className="bg-gray-600 hover:bg-gray-700 text-white rounded px-4 py-2 font-medium text-sm transition-colors"
100
-
>
101
-
Log in
102
-
</button>
103
-
</form>
104
-
</div>
105
-
)}
106
-
</div>
107
-
);
220
+
</div>
221
+
</form>
222
+
);
223
+
};
224
+
225
+
const PasswordForm = () => {
226
+
const { loginWithPassword } = useAuth();
227
+
const [user, setUser] = useState("");
228
+
const [password, setPassword] = useState("");
229
+
const [serviceURL, setServiceURL] = useState("bsky.social");
230
+
const [error, setError] = useState<string | null>(null);
231
+
232
+
useEffect(() => {
233
+
const lastHandle = localStorage.getItem("lastHandle");
234
+
if (lastHandle) setUser(lastHandle);
235
+
}, []);
236
+
237
+
const handleSubmit = async (e: React.FormEvent) => {
238
+
e.preventDefault();
239
+
setError(null);
240
+
try {
241
+
localStorage.setItem("lastHandle", user);
242
+
await loginWithPassword(user, password, `https://${serviceURL}`);
243
+
} catch (err) {
244
+
setError("Login failed. Check your handle and App Password.");
108
245
}
109
-
}
246
+
};
110
247
111
248
return (
112
-
<div className="p-6 bg-gray-100 dark:bg-gray-900 rounded-xl shadow border border-gray-200 dark:border-gray-800 mt-6 mx-4">
113
-
{authed ? (
114
-
<div className="flex flex-col items-center justify-center text-center">
115
-
<p className="text-lg font-semibold mb-6 text-gray-800 dark:text-gray-100">
116
-
You are logged in!
117
-
</p>
118
-
<button
119
-
onClick={logout}
120
-
className="bg-gray-600 hover:bg-gray-700 text-white rounded px-6 py-2 font-semibold text-base transition-colors"
121
-
>
122
-
Log out
123
-
</button>
124
-
</div>
125
-
) : (
126
-
<form
127
-
onSubmit={(e) => {
128
-
e.preventDefault();
129
-
login(user, password, `https://${serviceURL}`);
130
-
}}
131
-
className="flex flex-col gap-4"
132
-
>
133
-
<p className="text-sm text-gray-500 dark:text-gray-400 mb-2">
134
-
sorry for the temporary login,
135
-
<br />
136
-
oauth will come soon enough i swear
137
-
</p>
249
+
<form onSubmit={handleSubmit} className="flex flex-col gap-3">
250
+
<p className="text-xs text-red-500 dark:text-red-400">
251
+
Warning: Less secure. Use an App Password.
252
+
</p>
253
+
{/* <input
254
+
type="text"
255
+
placeholder="handle.bsky.social"
256
+
value={user}
257
+
onChange={(e) => setUser(e.target.value)}
258
+
className="px-3 py-2 rounded border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 text-sm focus:outline-none focus:ring-2 focus:ring-gray-500"
259
+
autoComplete="username"
260
+
/>
261
+
<input
262
+
type="password"
263
+
placeholder="App Password"
264
+
value={password}
265
+
onChange={(e) => setPassword(e.target.value)}
266
+
className="px-3 py-2 rounded border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 text-sm focus:outline-none focus:ring-2 focus:ring-gray-500"
267
+
autoComplete="current-password"
268
+
/>
269
+
<input
270
+
type="text"
271
+
placeholder="PDS (e.g., bsky.social)"
272
+
value={serviceURL}
273
+
onChange={(e) => setServiceURL(e.target.value)}
274
+
className="px-3 py-2 rounded border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 text-sm focus:outline-none focus:ring-2 focus:ring-gray-500"
275
+
/> */}
276
+
<div className="m3input-field m3input-label m3input-border size-md flex-1">
138
277
<input
139
278
type="text"
140
-
placeholder="Username"
279
+
placeholder=" "
141
280
value={user}
142
281
onChange={(e) => setUser(e.target.value)}
143
-
className="px-3 py-2 rounded border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 text-base focus:outline-none focus:ring-2 focus:ring-blue-500"
144
-
autoComplete="username"
145
282
/>
283
+
<label>AT Handle</label>
284
+
</div>
285
+
<div className="m3input-field m3input-label m3input-border size-md flex-1">
146
286
<input
147
-
type="password"
148
-
placeholder="Password"
287
+
type="text"
288
+
placeholder=" "
149
289
value={password}
150
290
onChange={(e) => setPassword(e.target.value)}
151
-
className="px-3 py-2 rounded border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 text-base focus:outline-none focus:ring-2 focus:ring-blue-500"
152
-
autoComplete="current-password"
153
291
/>
292
+
<label>App Password</label>
293
+
</div>
294
+
<div className="m3input-field m3input-label m3input-border size-md flex-1">
154
295
<input
155
296
type="text"
156
-
placeholder="bsky.social"
297
+
placeholder=" "
157
298
value={serviceURL}
158
299
onChange={(e) => setServiceURL(e.target.value)}
159
-
className="px-3 py-2 rounded border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 text-base focus:outline-none focus:ring-2 focus:ring-blue-500"
160
300
/>
161
-
<button
162
-
type="submit"
163
-
className="bg-gray-600 hover:bg-gray-700 text-white rounded px-6 py-2 font-semibold text-base transition-colors mt-2"
164
-
>
165
-
Log in
166
-
</button>
167
-
</form>
168
-
)}
169
-
</div>
301
+
<label>PDS</label>
302
+
</div>
303
+
{error && <p className="text-xs text-red-500">{error}</p>}
304
+
<button
305
+
type="submit"
306
+
className="bg-gray-600 hover:bg-gray-700 text-white rounded-full px-4 py-2 font-medium text-sm transition-colors"
307
+
>
308
+
Log in
309
+
</button>
310
+
</form>
170
311
);
171
-
}
312
+
};
172
313
173
-
export const ProfileThing = () => {
174
-
const { agent, loading, loginStatus, authed } = useAuth();
175
-
const [response, setResponse] = useState<any>(null);
314
+
// --- Profile Component (now supports a `large` prop for styling) ---
315
+
export const ProfileThing = ({
316
+
agent,
317
+
large = false,
318
+
}: {
319
+
agent: Agent | null;
320
+
large?: boolean;
321
+
}) => {
322
+
const did = ((agent as AtpAgent)?.session?.did ??
323
+
(agent as AtpAgent)?.assertDid ??
324
+
agent?.did) as string | undefined;
325
+
const { data: identity } = useQueryIdentity(did);
326
+
const { data: profiledata } = useQueryProfile(
327
+
`at://${did}/app.bsky.actor.profile/self`
328
+
);
329
+
const profile = profiledata?.value;
176
330
177
-
useEffect(() => {
178
-
if (loginStatus && agent && !loading && authed) {
179
-
fetchUser();
180
-
}
181
-
// eslint-disable-next-line
182
-
}, [loginStatus, agent, loading, authed]);
183
-
184
-
const fetchUser = async () => {
185
-
if (!agent) {
186
-
console.error("Agent is null or undefined");
187
-
return;
188
-
}
189
-
const res = await agent.app.bsky.actor.getProfile({
190
-
actor: agent.assertDid,
191
-
});
192
-
setResponse(res.data);
193
-
};
331
+
const [imgcdn] = useAtom(imgCDNAtom)
194
332
195
-
if (!authed) {
196
-
return (
197
-
<div className="inline-block">
198
-
<span className="text-gray-100 text-base font-medium px-1.5">
199
-
Login
200
-
</span>
201
-
</div>
202
-
);
333
+
function getAvatarUrl(p: typeof profile) {
334
+
const link = p?.avatar?.ref?.["$link"];
335
+
if (!link || !did) return null;
336
+
return `https://${imgcdn}/img/avatar/plain/${did}/${link}@jpeg`;
203
337
}
204
338
205
-
if (!response) {
339
+
if (!profiledata) {
206
340
return (
207
-
<div className="flex flex-col items-start gap-1.5">
208
-
<span className="w-5 h-5 border-2 border-gray-200 dark:border-gray-600 border-t-transparent rounded-full animate-spin inline-block" />
209
-
<span className="text-gray-100">Loading... </span>
341
+
// Skeleton loader
342
+
<div
343
+
className={`flex items-center gap-2.5 animate-pulse ${large ? "mb-1" : ""}`}
344
+
>
345
+
<div
346
+
className={`rounded-full bg-gray-300 dark:bg-gray-700 ${large ? "w-10 h-10" : "w-[30px] h-[30px]"}`}
347
+
/>
348
+
<div className="flex flex-col gap-2">
349
+
<div
350
+
className={`bg-gray-300 dark:bg-gray-700 rounded ${large ? "h-4 w-28" : "h-3 w-20"}`}
351
+
/>
352
+
<div
353
+
className={`bg-gray-300 dark:bg-gray-700 rounded ${large ? "h-4 w-20" : "h-3 w-16"}`}
354
+
/>
355
+
</div>
210
356
</div>
211
357
);
212
358
}
213
359
214
360
return (
215
-
<div className="flex flex-row items-start gap-1.5">
361
+
<div
362
+
className={`flex flex-row items-center gap-2.5 ${large ? "mb-1" : ""}`}
363
+
>
216
364
<img
217
-
src={response?.avatar}
365
+
src={getAvatarUrl(profile) ?? undefined}
218
366
alt="avatar"
219
-
className="w-[30px] h-[30px] rounded-full object-cover"
367
+
className={`object-cover rounded-full ${large ? "w-10 h-10" : "w-[30px] h-[30px]"}`}
220
368
/>
221
-
<div>
222
-
<div className="text-gray-100 text-xs">{response?.displayName}</div>
223
-
<div className="text-gray-100 text-xs">@{response?.handle}</div>
369
+
<div className="flex flex-col items-start text-left">
370
+
<div
371
+
className={`font-medium ${large ? "text-gray-800 dark:text-gray-100 text-md" : "text-gray-800 dark:text-gray-100 text-sm"}`}
372
+
>
373
+
{profile?.displayName}
374
+
</div>
375
+
<div
376
+
className={` ${large ? "text-gray-500 dark:text-gray-400 text-sm" : "text-gray-500 dark:text-gray-400 text-xs"}`}
377
+
>
378
+
@{identity?.handle}
379
+
</div>
224
380
</div>
225
381
</div>
226
382
);
+6
src/components/Star.tsx
+6
src/components/Star.tsx
···
1
+
import type { SVGProps } from 'react';
2
+
import React from 'react';
3
+
4
+
export function FluentEmojiHighContrastGlowingStar(props: SVGProps<SVGSVGElement>) {
5
+
return (<svg xmlns="http://www.w3.org/2000/svg" width={32} height={32} viewBox="0 0 32 32" {...props}><g fill="currentColor"><path d="m28.979 17.003l-3.108.214c-.834.06-1.178 1.079-.542 1.608l2.388 1.955c.521.428 1.314.204 1.523-.428l.709-2.127c.219-.632-.292-1.273-.97-1.222M21.75 2.691l-.72 2.9c-.2.78.66 1.41 1.34.98l2.54-1.58c.55-.34.58-1.14.05-1.52l-1.78-1.29a.912.912 0 0 0-1.43.51M6.43 4.995l2.53 1.58c.68.43 1.54-.19 1.35-.98l-.72-2.9a.92.92 0 0 0-1.43-.52l-1.78 1.29c-.53.4-.5 1.19.05 1.53M4.185 20.713l2.29-1.92c.62-.52.29-1.53-.51-1.58l-2.98-.21a.92.92 0 0 0-.94 1.2l.68 2.09c.2.62.97.84 1.46.42m13.61 7.292l-1.12-2.77c-.3-.75-1.36-.75-1.66 0l-1.12 2.77c-.24.6.2 1.26.85 1.26h2.2a.92.92 0 0 0 .85-1.26"></path><path d="m17.565 3.324l1.726 3.72c.326.694.967 1.18 1.717 1.29l4.056.624c1.835.278 2.575 2.53 1.293 3.859L23.268 16a2.28 2.28 0 0 0-.612 1.964l.71 4.374c.307 1.885-1.687 3.293-3.354 2.37l-3.405-1.894a2.25 2.25 0 0 0-2.21 0l-3.404 1.895c-1.668.922-3.661-.486-3.355-2.37l.71-4.375A2.28 2.28 0 0 0 7.736 16l-3.088-3.184c-1.293-1.34-.543-3.581 1.293-3.859l4.055-.625a2.3 2.3 0 0 0 1.717-1.29l1.727-3.719c.819-1.765 3.306-1.765 4.124 0"></path></g></svg>);
6
+
}
+1359
-1143
src/components/UniversalPostRenderer.tsx
+1359
-1143
src/components/UniversalPostRenderer.tsx
···
1
-
import * as React from "react";
2
-
import { usePersistentStore } from "~/providers/PersistentStoreProvider";
3
1
import { useNavigate } from "@tanstack/react-router";
2
+
import DOMPurify from "dompurify";
3
+
import { useAtom } from "jotai";
4
+
import { DropdownMenu } from "radix-ui";
5
+
import { HoverCard } from "radix-ui";
6
+
import * as React from "react";
4
7
import { type SVGProps } from "react";
5
8
9
+
import {
10
+
composerAtom,
11
+
constellationURLAtom,
12
+
imgCDNAtom,
13
+
likedPostsAtom,
14
+
} from "~/utils/atoms";
15
+
import { useHydratedEmbed } from "~/utils/useHydrated";
16
+
import {
17
+
useQueryConstellation,
18
+
useQueryIdentity,
19
+
useQueryPost,
20
+
useQueryProfile,
21
+
yknowIReallyHateThisButWhateverGuardedConstructConstellationInfiniteQueryLinks,
22
+
} from "~/utils/useQuery";
23
+
6
24
function asTyped<T extends { $type: string }>(obj: T): $Typed<T> {
7
25
return obj as $Typed<T>;
8
26
}
···
16
34
detailed?: boolean;
17
35
bottomReplyLine?: boolean;
18
36
topReplyLine?: boolean;
19
-
bottomBorder?:boolean;
20
-
feedviewpost?:boolean;
37
+
bottomBorder?: boolean;
38
+
feedviewpost?: boolean;
39
+
repostedby?: string;
40
+
style?: React.CSSProperties;
41
+
ref?: React.Ref<HTMLDivElement>;
42
+
dataIndexPropPass?: number;
43
+
nopics?: boolean;
44
+
lightboxCallback?: (d: LightboxProps) => void;
45
+
maxReplies?: number;
46
+
isQuote?: boolean;
21
47
}
22
48
23
-
export async function cachedGetRecord({
24
-
atUri,
25
-
cacheTimeout = CACHE_TIMEOUT,
26
-
get,
27
-
set,
28
-
}: {
29
-
atUri: string;
30
-
//resolved: { pdsUrl: string; did: string } | null | undefined;
31
-
cacheTimeout?: number;
32
-
get: (key: string) => any;
33
-
set: (key: string, value: string) => void;
34
-
}): Promise<any> {
35
-
const cacheKey = `record:${atUri}`;
36
-
const cached = get(cacheKey);
37
-
const now = Date.now();
38
-
if (
39
-
cached &&
40
-
cached.value &&
41
-
cached.time &&
42
-
now - cached.time < cacheTimeout
43
-
) {
44
-
try {
45
-
return JSON.parse(cached.value);
46
-
} catch {
47
-
// fall through to fetch
48
-
}
49
-
}
50
-
const parsed = parseAtUri(atUri);
51
-
if (!parsed) return null;
52
-
const resolved = await cachedResolveIdentity({
53
-
didOrHandle: parsed.did,
54
-
get,
55
-
set,
56
-
});
57
-
if (!resolved?.pdsUrl || !resolved?.did)
58
-
throw new Error("Missing resolved PDS info");
49
+
// export async function cachedGetRecord({
50
+
// atUri,
51
+
// cacheTimeout = CACHE_TIMEOUT,
52
+
// get,
53
+
// set,
54
+
// }: {
55
+
// atUri: string;
56
+
// //resolved: { pdsUrl: string; did: string } | null | undefined;
57
+
// cacheTimeout?: number;
58
+
// get: (key: string) => any;
59
+
// set: (key: string, value: string) => void;
60
+
// }): Promise<any> {
61
+
// const cacheKey = `record:${atUri}`;
62
+
// const cached = get(cacheKey);
63
+
// const now = Date.now();
64
+
// if (
65
+
// cached &&
66
+
// cached.value &&
67
+
// cached.time &&
68
+
// now - cached.time < cacheTimeout
69
+
// ) {
70
+
// try {
71
+
// return JSON.parse(cached.value);
72
+
// } catch {
73
+
// // fall through to fetch
74
+
// }
75
+
// }
76
+
// const parsed = parseAtUri(atUri);
77
+
// if (!parsed) return null;
78
+
// const resolved = await cachedResolveIdentity({
79
+
// didOrHandle: parsed.did,
80
+
// get,
81
+
// set,
82
+
// });
83
+
// if (!resolved?.pdsUrl || !resolved?.did)
84
+
// throw new Error("Missing resolved PDS info");
59
85
60
-
if (!parsed) throw new Error("Invalid atUri");
61
-
const { collection, rkey } = parsed;
62
-
const url = `${
63
-
resolved.pdsUrl
64
-
}/xrpc/com.atproto.repo.getRecord?repo=${encodeURIComponent(
65
-
resolved.did,
66
-
)}&collection=${encodeURIComponent(collection)}&rkey=${encodeURIComponent(
67
-
rkey,
68
-
)}`;
69
-
const res = await fetch(url);
70
-
if (!res.ok) throw new Error("Failed to fetch base record");
71
-
const data = await res.json();
72
-
set(cacheKey, JSON.stringify(data));
73
-
return data;
74
-
}
86
+
// if (!parsed) throw new Error("Invalid atUri");
87
+
// const { collection, rkey } = parsed;
88
+
// const url = `${
89
+
// resolved.pdsUrl
90
+
// }/xrpc/com.atproto.repo.getRecord?repo=${encodeURIComponent(
91
+
// resolved.did,
92
+
// )}&collection=${encodeURIComponent(collection)}&rkey=${encodeURIComponent(
93
+
// rkey,
94
+
// )}`;
95
+
// const res = await fetch(url);
96
+
// if (!res.ok) throw new Error("Failed to fetch base record");
97
+
// const data = await res.json();
98
+
// set(cacheKey, JSON.stringify(data));
99
+
// return data;
100
+
// }
75
101
76
-
export async function cachedResolveIdentity({
77
-
didOrHandle,
78
-
cacheTimeout = HANDLE_DID_CACHE_TIMEOUT,
79
-
get,
80
-
set,
81
-
}: {
82
-
didOrHandle: string;
83
-
cacheTimeout?: number;
84
-
get: (key: string) => any;
85
-
set: (key: string, value: string) => void;
86
-
}): Promise<any> {
87
-
const isDidInput = didOrHandle.startsWith("did:");
88
-
const cacheKey = `handleDid:${didOrHandle}`;
89
-
const now = Date.now();
90
-
const cached = get(cacheKey);
91
-
if (
92
-
cached &&
93
-
cached.value &&
94
-
cached.time &&
95
-
now - cached.time < cacheTimeout
96
-
) {
97
-
try {
98
-
return JSON.parse(cached.value);
99
-
} catch {}
100
-
}
101
-
const url = `https://free-fly-24.deno.dev/?${
102
-
isDidInput
103
-
? `did=${encodeURIComponent(didOrHandle)}`
104
-
: `handle=${encodeURIComponent(didOrHandle)}`
105
-
}`;
106
-
const res = await fetch(url);
107
-
if (!res.ok) throw new Error("Failed to resolve handle/did");
108
-
const data = await res.json();
109
-
set(cacheKey, JSON.stringify(data));
110
-
if (!isDidInput && data.did) {
111
-
set(`handleDid:${data.did}`, JSON.stringify(data));
112
-
}
113
-
return data;
114
-
}
102
+
// export async function cachedResolveIdentity({
103
+
// didOrHandle,
104
+
// cacheTimeout = HANDLE_DID_CACHE_TIMEOUT,
105
+
// get,
106
+
// set,
107
+
// }: {
108
+
// didOrHandle: string;
109
+
// cacheTimeout?: number;
110
+
// get: (key: string) => any;
111
+
// set: (key: string, value: string) => void;
112
+
// }): Promise<any> {
113
+
// const isDidInput = didOrHandle.startsWith("did:");
114
+
// const cacheKey = `handleDid:${didOrHandle}`;
115
+
// const now = Date.now();
116
+
// const cached = get(cacheKey);
117
+
// if (
118
+
// cached &&
119
+
// cached.value &&
120
+
// cached.time &&
121
+
// now - cached.time < cacheTimeout
122
+
// ) {
123
+
// try {
124
+
// return JSON.parse(cached.value);
125
+
// } catch {}
126
+
// }
127
+
// const url = `https://free-fly-24.deno.dev/?${
128
+
// isDidInput
129
+
// ? `did=${encodeURIComponent(didOrHandle)}`
130
+
// : `handle=${encodeURIComponent(didOrHandle)}`
131
+
// }`;
132
+
// const res = await fetch(url);
133
+
// if (!res.ok) throw new Error("Failed to resolve handle/did");
134
+
// const data = await res.json();
135
+
// set(cacheKey, JSON.stringify(data));
136
+
// if (!isDidInput && data.did) {
137
+
// set(`handleDid:${data.did}`, JSON.stringify(data));
138
+
// }
139
+
// return data;
140
+
// }
115
141
116
142
export function UniversalPostRendererATURILoader({
117
143
atUri,
···
119
145
detailed = false,
120
146
bottomReplyLine,
121
147
topReplyLine,
122
-
bottomBorder= true,
148
+
bottomBorder = true,
123
149
feedviewpost = false,
150
+
repostedby,
151
+
style,
152
+
ref,
153
+
dataIndexPropPass,
154
+
nopics,
155
+
lightboxCallback,
156
+
maxReplies,
157
+
isQuote,
124
158
}: UniversalPostRendererATURILoaderProps) {
125
-
console.log("atUri", atUri);
126
-
const { get, set } = usePersistentStore();
127
-
const [record, setRecord] = React.useState<any>(null);
128
-
const [links, setLinks] = React.useState<any>(null);
159
+
// todo remove this once tree rendering is implemented, use a prop like isTree
160
+
const TEMPLINEAR = true;
161
+
// /*mass comment*/ console.log("atUri", atUri);
162
+
//const { get, set } = usePersistentStore();
163
+
//const [record, setRecord] = React.useState<any>(null);
164
+
//const [links, setLinks] = React.useState<any>(null);
129
165
//const [error, setError] = React.useState<string | null>(null);
130
166
//const [cacheTime, setCacheTime] = React.useState<number | null>(null);
131
-
const [resolved, setResolved] = React.useState<any>(null); // { did, pdsUrl, bskyPds, handle }
132
-
const [opProfile, setOpProfile] = React.useState<any>(null);
167
+
//const [resolved, setResolved] = React.useState<any>(null); // { did, pdsUrl, bskyPds, handle }
168
+
//const [opProfile, setOpProfile] = React.useState<any>(null);
133
169
// const [opProfileCacheTime, setOpProfileCacheTime] = React.useState<
134
170
// number | null
135
171
// >(null);
136
172
//const router = useRouter();
137
173
138
-
const parsed = React.useMemo(() => parseAtUri(atUri), [atUri]);
139
-
const did = parsed?.did;
174
+
//const parsed = React.useMemo(() => parseAtUri(atUri), [atUri]);
175
+
const parsed = new AtUri(atUri);
176
+
const did = parsed?.host;
140
177
const rkey = parsed?.rkey;
141
-
console.log("did", did);
142
-
console.log("rkey", rkey);
178
+
// /*mass comment*/ console.log("did", did);
179
+
// /*mass comment*/ console.log("rkey", rkey);
143
180
144
-
React.useEffect(() => {
145
-
const checkCache = async () => {
146
-
const postUri = atUri;
147
-
const cacheKey = `record:${postUri}`;
148
-
const cached = await get(cacheKey);
149
-
const now = Date.now();
150
-
console.log(
151
-
"UniversalPostRenderer checking cache for",
152
-
cacheKey,
153
-
"cached:",
154
-
!!cached,
155
-
);
156
-
if (
157
-
cached &&
158
-
cached.value &&
159
-
cached.time &&
160
-
now - cached.time < CACHE_TIMEOUT
161
-
) {
162
-
try {
163
-
console.log("UniversalPostRenderer found cached data for", cacheKey);
164
-
setRecord(JSON.parse(cached.value));
165
-
} catch {
166
-
setRecord(null);
167
-
}
168
-
}
169
-
};
170
-
checkCache();
171
-
}, [atUri, get]);
181
+
// React.useEffect(() => {
182
+
// const checkCache = async () => {
183
+
// const postUri = atUri;
184
+
// const cacheKey = `record:${postUri}`;
185
+
// const cached = await get(cacheKey);
186
+
// const now = Date.now();
187
+
// // /*mass comment*/ console.log(
188
+
// "UniversalPostRenderer checking cache for",
189
+
// cacheKey,
190
+
// "cached:",
191
+
// !!cached,
192
+
// );
193
+
// if (
194
+
// cached &&
195
+
// cached.value &&
196
+
// cached.time &&
197
+
// now - cached.time < CACHE_TIMEOUT
198
+
// ) {
199
+
// try {
200
+
// // /*mass comment*/ console.log("UniversalPostRenderer found cached data for", cacheKey);
201
+
// setRecord(JSON.parse(cached.value));
202
+
// } catch {
203
+
// setRecord(null);
204
+
// }
205
+
// }
206
+
// };
207
+
// checkCache();
208
+
// }, [atUri, get]);
172
209
173
-
React.useEffect(() => {
174
-
if (!did || record) return;
175
-
(async () => {
176
-
try {
177
-
const resolvedData = await cachedResolveIdentity({
178
-
didOrHandle: did,
179
-
get,
180
-
set,
181
-
});
182
-
setResolved(resolvedData);
183
-
} catch (e: any) {
184
-
//setError("Failed to resolve handle/did: " + e?.message);
185
-
}
186
-
})();
187
-
}, [did, get, set, record]);
210
+
const {
211
+
data: postQuery,
212
+
isLoading: isPostLoading,
213
+
isError: isPostError,
214
+
} = useQueryPost(atUri);
215
+
//const record = postQuery?.value;
216
+
217
+
// React.useEffect(() => {
218
+
// if (!did || record) return;
219
+
// (async () => {
220
+
// try {
221
+
// const resolvedData = await cachedResolveIdentity({
222
+
// didOrHandle: did,
223
+
// get,
224
+
// set,
225
+
// });
226
+
// setResolved(resolvedData);
227
+
// } catch (e: any) {
228
+
// //setError("Failed to resolve handle/did: " + e?.message);
229
+
// }
230
+
// })();
231
+
// }, [did, get, set, record]);
232
+
233
+
const { data: resolved } = useQueryIdentity(did || "");
234
+
235
+
// React.useEffect(() => {
236
+
// if (!resolved || !resolved.pdsUrl || !resolved.did || !rkey || record)
237
+
// return;
238
+
// let ignore = false;
239
+
// (async () => {
240
+
// try {
241
+
// const data = await cachedGetRecord({
242
+
// atUri,
243
+
// get,
244
+
// set,
245
+
// });
246
+
// if (!ignore) setRecord(data);
247
+
// } catch (e: any) {
248
+
// //if (!ignore) setError("Failed to fetch base record: " + e?.message);
249
+
// }
250
+
// })();
251
+
// return () => {
252
+
// ignore = true;
253
+
// };
254
+
// }, [resolved, rkey, atUri, record]);
255
+
256
+
// React.useEffect(() => {
257
+
// if (!resolved || !resolved.did || !rkey) return;
258
+
// const fetchLinks = async () => {
259
+
// const postUri = atUri;
260
+
// const cacheKey = `constellation:${postUri}`;
261
+
// const cached = await get(cacheKey);
262
+
// const now = Date.now();
263
+
// if (
264
+
// cached &&
265
+
// cached.value &&
266
+
// cached.time &&
267
+
// now - cached.time < CACHE_TIMEOUT
268
+
// ) {
269
+
// try {
270
+
// const data = JSON.parse(cached.value);
271
+
// setLinks(data);
272
+
// if (onConstellation) onConstellation(data);
273
+
// } catch {
274
+
// setLinks(null);
275
+
// }
276
+
// //setCacheTime(cached.time);
277
+
// return;
278
+
// }
279
+
// try {
280
+
// const url = `https://constellation.microcosm.blue/links/all?target=${encodeURIComponent(
281
+
// atUri,
282
+
// )}`;
283
+
// const res = await fetch(url);
284
+
// if (!res.ok) throw new Error("Failed to fetch constellation links");
285
+
// const data = await res.json();
286
+
// setLinks(data);
287
+
// //setCacheTime(now);
288
+
// set(cacheKey, JSON.stringify(data));
289
+
// if (onConstellation) onConstellation(data);
290
+
// } catch (e: any) {
291
+
// //setError("Failed to fetch constellation links: " + e?.message);
292
+
// }
293
+
// };
294
+
// fetchLinks();
295
+
// }, [resolved, rkey, get, set, atUri, onConstellation]);
188
296
189
-
React.useEffect(() => {
190
-
if (!resolved || !resolved.pdsUrl || !resolved.did || !rkey || record)
191
-
return;
192
-
let ignore = false;
193
-
(async () => {
194
-
try {
195
-
const data = await cachedGetRecord({
196
-
atUri,
197
-
get,
198
-
set,
199
-
});
200
-
if (!ignore) setRecord(data);
201
-
} catch (e: any) {
202
-
//if (!ignore) setError("Failed to fetch base record: " + e?.message);
203
-
}
204
-
})();
205
-
return () => {
206
-
ignore = true;
207
-
};
208
-
}, [resolved, rkey, atUri, record]);
297
+
const { data: links } = useQueryConstellation({
298
+
method: "/links/all",
299
+
target: atUri,
300
+
});
209
301
210
-
React.useEffect(() => {
211
-
if (!resolved || !resolved.did || !rkey) return;
212
-
const fetchLinks = async () => {
213
-
const postUri = atUri;
214
-
const cacheKey = `constellation:${postUri}`;
215
-
const cached = await get(cacheKey);
216
-
const now = Date.now();
217
-
if (
218
-
cached &&
219
-
cached.value &&
220
-
cached.time &&
221
-
now - cached.time < CACHE_TIMEOUT
222
-
) {
223
-
try {
224
-
const data = JSON.parse(cached.value);
225
-
setLinks(data);
226
-
if (onConstellation) onConstellation(data);
227
-
} catch {
228
-
setLinks(null);
229
-
}
230
-
//setCacheTime(cached.time);
231
-
return;
232
-
}
233
-
try {
234
-
const url = `https://constellation.microcosm.blue/links/all?target=${encodeURIComponent(
235
-
atUri,
236
-
)}`;
237
-
const res = await fetch(url);
238
-
if (!res.ok) throw new Error("Failed to fetch constellation links");
239
-
const data = await res.json();
240
-
setLinks(data);
241
-
//setCacheTime(now);
242
-
set(cacheKey, JSON.stringify(data));
243
-
if (onConstellation) onConstellation(data);
244
-
} catch (e: any) {
245
-
//setError("Failed to fetch constellation links: " + e?.message);
246
-
}
247
-
};
248
-
fetchLinks();
249
-
}, [resolved, rkey, get, set, atUri, onConstellation]);
302
+
// React.useEffect(() => {
303
+
// if (!record || !resolved || !resolved.did) return;
304
+
// const fetchOpProfile = async () => {
305
+
// const opDid = resolved.did;
306
+
// const postUri = atUri;
307
+
// const cacheKey = `profile:${postUri}`;
308
+
// const cached = await get(cacheKey);
309
+
// const now = Date.now();
310
+
// if (
311
+
// cached &&
312
+
// cached.value &&
313
+
// cached.time &&
314
+
// now - cached.time < CACHE_TIMEOUT
315
+
// ) {
316
+
// try {
317
+
// setOpProfile(JSON.parse(cached.value));
318
+
// } catch {
319
+
// setOpProfile(null);
320
+
// }
321
+
// //setOpProfileCacheTime(cached.time);
322
+
// return;
323
+
// }
324
+
// try {
325
+
// let opResolvedRaw = await get(`handleDid:${opDid}`);
326
+
// let opResolved: any = null;
327
+
// if (
328
+
// opResolvedRaw &&
329
+
// opResolvedRaw.value &&
330
+
// opResolvedRaw.time &&
331
+
// now - opResolvedRaw.time < HANDLE_DID_CACHE_TIMEOUT
332
+
// ) {
333
+
// try {
334
+
// opResolved = JSON.parse(opResolvedRaw.value);
335
+
// } catch {
336
+
// opResolved = null;
337
+
// }
338
+
// } else {
339
+
// const url = `https://free-fly-24.deno.dev/?did=${encodeURIComponent(
340
+
// opDid,
341
+
// )}`;
342
+
// const res = await fetch(url);
343
+
// if (!res.ok) throw new Error("Failed to resolve OP did");
344
+
// opResolved = await res.json();
345
+
// set(`handleDid:${opDid}`, JSON.stringify(opResolved));
346
+
// }
347
+
// if (!opResolved || !opResolved.pdsUrl)
348
+
// throw new Error("OP did resolution failed or missing pdsUrl");
349
+
// const profileUrl = `${
350
+
// opResolved.pdsUrl
351
+
// }/xrpc/com.atproto.repo.getRecord?repo=${encodeURIComponent(
352
+
// opDid,
353
+
// )}&collection=app.bsky.actor.profile&rkey=self`;
354
+
// const profileRes = await fetch(profileUrl);
355
+
// if (!profileRes.ok) throw new Error("Failed to fetch OP profile");
356
+
// const profileData = await profileRes.json();
357
+
// setOpProfile(profileData);
358
+
// //setOpProfileCacheTime(now);
359
+
// set(cacheKey, JSON.stringify(profileData));
360
+
// } catch (e: any) {
361
+
// //setError("Failed to fetch OP profile: " + e?.message);
362
+
// }
363
+
// };
364
+
// fetchOpProfile();
365
+
// }, [record, get, set, rkey, resolved, atUri]);
250
366
251
-
React.useEffect(() => {
252
-
if (!record || !resolved || !resolved.did) return;
253
-
const fetchOpProfile = async () => {
254
-
const opDid = resolved.did;
255
-
const postUri = atUri;
256
-
const cacheKey = `profile:${postUri}`;
257
-
const cached = await get(cacheKey);
258
-
const now = Date.now();
259
-
if (
260
-
cached &&
261
-
cached.value &&
262
-
cached.time &&
263
-
now - cached.time < CACHE_TIMEOUT
264
-
) {
265
-
try {
266
-
setOpProfile(JSON.parse(cached.value));
267
-
} catch {
268
-
setOpProfile(null);
269
-
}
270
-
//setOpProfileCacheTime(cached.time);
271
-
return;
272
-
}
273
-
try {
274
-
let opResolvedRaw = await get(`handleDid:${opDid}`);
275
-
let opResolved: any = null;
276
-
if (
277
-
opResolvedRaw &&
278
-
opResolvedRaw.value &&
279
-
opResolvedRaw.time &&
280
-
now - opResolvedRaw.time < HANDLE_DID_CACHE_TIMEOUT
281
-
) {
282
-
try {
283
-
opResolved = JSON.parse(opResolvedRaw.value);
284
-
} catch {
285
-
opResolved = null;
286
-
}
287
-
} else {
288
-
const url = `https://free-fly-24.deno.dev/?did=${encodeURIComponent(
289
-
opDid,
290
-
)}`;
291
-
const res = await fetch(url);
292
-
if (!res.ok) throw new Error("Failed to resolve OP did");
293
-
opResolved = await res.json();
294
-
set(`handleDid:${opDid}`, JSON.stringify(opResolved));
295
-
}
296
-
if (!opResolved || !opResolved.pdsUrl)
297
-
throw new Error("OP did resolution failed or missing pdsUrl");
298
-
const profileUrl = `${
299
-
opResolved.pdsUrl
300
-
}/xrpc/com.atproto.repo.getRecord?repo=${encodeURIComponent(
301
-
opDid,
302
-
)}&collection=app.bsky.actor.profile&rkey=self`;
303
-
const profileRes = await fetch(profileUrl);
304
-
if (!profileRes.ok) throw new Error("Failed to fetch OP profile");
305
-
const profileData = await profileRes.json();
306
-
setOpProfile(profileData);
307
-
//setOpProfileCacheTime(now);
308
-
set(cacheKey, JSON.stringify(profileData));
309
-
} catch (e: any) {
310
-
//setError("Failed to fetch OP profile: " + e?.message);
311
-
}
312
-
};
313
-
fetchOpProfile();
314
-
}, [record, get, set, rkey, resolved, atUri]);
367
+
const { data: opProfile } = useQueryProfile(
368
+
resolved ? `at://${resolved?.did}/app.bsky.actor.profile/self` : undefined
369
+
);
315
370
316
371
// const displayName =
317
372
// opProfile?.value?.displayName || resolved?.handle || resolved?.did;
···
328
383
const [replies, setReplies] = React.useState<number | null>(null);
329
384
330
385
React.useEffect(() => {
331
-
console.log(JSON.stringify(links, null, 2));
386
+
// /*mass comment*/ console.log(JSON.stringify(links, null, 2));
332
387
setLikes(
333
388
links
334
389
? links?.links?.["app.bsky.feed.like"]?.[".subject.uri"]?.records || 0
335
-
: null,
390
+
: null
336
391
);
337
392
setReposts(
338
393
links
339
394
? links?.links?.["app.bsky.feed.repost"]?.[".subject.uri"]?.records || 0
340
-
: null,
395
+
: null
341
396
);
342
397
setReplies(
343
398
links
344
399
? links?.links?.["app.bsky.feed.post"]?.[".reply.parent.uri"]
345
400
?.records || 0
346
-
: null,
401
+
: null
347
402
);
348
403
}, [links]);
349
404
405
+
// const { data: repliesData } = useQueryConstellation({
406
+
// method: "/links",
407
+
// target: atUri,
408
+
// collection: "app.bsky.feed.post",
409
+
// path: ".reply.parent.uri",
410
+
// });
411
+
412
+
const [constellationurl] = useAtom(constellationURLAtom);
413
+
414
+
const infinitequeryresults = useInfiniteQuery({
415
+
...yknowIReallyHateThisButWhateverGuardedConstructConstellationInfiniteQueryLinks(
416
+
{
417
+
constellation: constellationurl,
418
+
method: "/links",
419
+
target: atUri,
420
+
collection: "app.bsky.feed.post",
421
+
path: ".reply.parent.uri",
422
+
}
423
+
),
424
+
enabled: !!atUri && !!maxReplies && !isQuote,
425
+
});
426
+
427
+
const {
428
+
data: repliesData,
429
+
// fetchNextPage,
430
+
// hasNextPage,
431
+
// isFetchingNextPage,
432
+
} = infinitequeryresults;
433
+
434
+
// auto-fetch all pages
435
+
useEffect(() => {
436
+
if (!maxReplies || isQuote || TEMPLINEAR) return;
437
+
if (
438
+
infinitequeryresults.hasNextPage &&
439
+
!infinitequeryresults.isFetchingNextPage
440
+
) {
441
+
console.log("Fetching the next page...");
442
+
infinitequeryresults.fetchNextPage();
443
+
}
444
+
}, [TEMPLINEAR, infinitequeryresults, isQuote, maxReplies]);
445
+
446
+
const replyAturis = repliesData
447
+
? repliesData.pages.flatMap((page) =>
448
+
page
449
+
? page.linking_records.map((record) => {
450
+
const aturi = `at://${record.did}/${record.collection}/${record.rkey}`;
451
+
return aturi;
452
+
})
453
+
: []
454
+
)
455
+
: [];
456
+
457
+
//const [oldestOpsReply, setOldestOpsReply] = useState<string | undefined>(undefined);
458
+
459
+
const { oldestOpsReply, oldestOpsReplyElseNewestNonOpsReply } = (() => {
460
+
if (isQuote || !replyAturis || replyAturis.length === 0 || !maxReplies)
461
+
return {
462
+
oldestOpsReply: undefined,
463
+
oldestOpsReplyElseNewestNonOpsReply: undefined,
464
+
};
465
+
466
+
const opdid = new AtUri(
467
+
//postQuery?.value.reply?.root.uri ?? postQuery?.uri ?? atUri
468
+
atUri
469
+
).host;
470
+
471
+
const opReplies = replyAturis.filter(
472
+
(aturi) => new AtUri(aturi).host === opdid
473
+
);
474
+
475
+
if (opReplies.length > 0) {
476
+
const opreply = opReplies[opReplies.length - 1];
477
+
//setOldestOpsReply(opreply);
478
+
return {
479
+
oldestOpsReply: opreply,
480
+
oldestOpsReplyElseNewestNonOpsReply: opreply,
481
+
};
482
+
} else {
483
+
return {
484
+
oldestOpsReply: undefined,
485
+
oldestOpsReplyElseNewestNonOpsReply: replyAturis[0],
486
+
};
487
+
}
488
+
})();
489
+
350
490
// const navigateToProfile = (e: React.MouseEvent) => {
351
491
// e.stopPropagation();
352
492
// if (resolved?.did) {
···
356
496
// });
357
497
// }
358
498
// };
499
+
if (!postQuery?.value) {
500
+
// deleted post more often than a non-resolvable post
501
+
return <></>;
502
+
}
359
503
360
504
return (
361
-
<UniversalPostRendererRawRecordShim
362
-
detailed={detailed}
363
-
postRecord={record}
364
-
profileRecord={opProfile}
365
-
aturi={atUri}
366
-
resolved={resolved}
367
-
likesCount={likes}
368
-
repostsCount={reposts}
369
-
repliesCount={replies}
370
-
bottomReplyLine={bottomReplyLine}
371
-
topReplyLine={topReplyLine}
372
-
bottomBorder={bottomBorder}
373
-
feedviewpost={feedviewpost}
374
-
/>
505
+
<>
506
+
{/* <span>uprrs {maxReplies} {!!maxReplies&&!!oldestOpsReplyElseNewestNonOpsReply ? "true" : "false"}</span> */}
507
+
<UniversalPostRendererRawRecordShim
508
+
detailed={detailed}
509
+
postRecord={postQuery}
510
+
profileRecord={opProfile}
511
+
aturi={atUri}
512
+
resolved={resolved}
513
+
likesCount={likes}
514
+
repostsCount={reposts}
515
+
repliesCount={replies}
516
+
bottomReplyLine={
517
+
maxReplies && oldestOpsReplyElseNewestNonOpsReply
518
+
? true
519
+
: maxReplies && !oldestOpsReplyElseNewestNonOpsReply
520
+
? false
521
+
: (maxReplies === 0 && (!replies || (!!replies && replies === 0))) ? false : bottomReplyLine
522
+
}
523
+
topReplyLine={topReplyLine}
524
+
//bottomBorder={maxReplies&&oldestOpsReplyElseNewestNonOpsReply ? false : bottomBorder}
525
+
bottomBorder={
526
+
maxReplies && oldestOpsReplyElseNewestNonOpsReply
527
+
? false
528
+
: maxReplies === 0
529
+
? false
530
+
: bottomBorder
531
+
}
532
+
feedviewpost={feedviewpost}
533
+
repostedby={repostedby}
534
+
//style={{...style, background: oldestOpsReply === atUri ? "Red" : undefined}}
535
+
style={style}
536
+
ref={ref}
537
+
dataIndexPropPass={dataIndexPropPass}
538
+
nopics={nopics}
539
+
lightboxCallback={lightboxCallback}
540
+
maxReplies={maxReplies}
541
+
isQuote={isQuote}
542
+
/>
543
+
<>
544
+
{(maxReplies && maxReplies === 0 && replies && replies > 0) ? (
545
+
<>
546
+
{/* <div>hello</div> */}
547
+
<MoreReplies atUri={atUri} />
548
+
</>
549
+
) : (<></>)}
550
+
</>
551
+
{!isQuote && oldestOpsReplyElseNewestNonOpsReply && (
552
+
<>
553
+
{/* <span>hello {maxReplies}</span> */}
554
+
<UniversalPostRendererATURILoader
555
+
//detailed={detailed}
556
+
atUri={oldestOpsReplyElseNewestNonOpsReply}
557
+
bottomReplyLine={(maxReplies ?? 0) > 0}
558
+
topReplyLine={
559
+
(!!(maxReplies && maxReplies - 1 === 0) &&
560
+
!!(replies && replies > 0)) ||
561
+
!!((maxReplies ?? 0) > 1)
562
+
}
563
+
bottomBorder={bottomBorder}
564
+
feedviewpost={feedviewpost}
565
+
repostedby={repostedby}
566
+
style={style}
567
+
ref={ref}
568
+
dataIndexPropPass={dataIndexPropPass}
569
+
nopics={nopics}
570
+
lightboxCallback={lightboxCallback}
571
+
maxReplies={
572
+
maxReplies && maxReplies > 0 ? maxReplies - 1 : undefined
573
+
}
574
+
/>
575
+
</>
576
+
)}
577
+
</>
578
+
);
579
+
}
580
+
581
+
function MoreReplies({ atUri }: { atUri: string }) {
582
+
const navigate = useNavigate();
583
+
const aturio = new AtUri(atUri);
584
+
return (
585
+
<div
586
+
onClick={() =>
587
+
navigate({
588
+
to: "/profile/$did/post/$rkey",
589
+
params: { did: aturio.host, rkey: aturio.rkey },
590
+
})
591
+
}
592
+
className="border-b border-gray-300 dark:border-gray-800 flex flex-row px-4 cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-900 transition-colors"
593
+
>
594
+
<div className="w-[42px] h-12 flex flex-col items-center justify-center">
595
+
<div
596
+
style={{
597
+
width: 2,
598
+
height: "100%",
599
+
backgroundImage:
600
+
"repeating-linear-gradient(to bottom, var(--color-gray-500) 0, var(--color-gray-500) 4px, transparent 4px, transparent 8px)",
601
+
opacity: 0.5,
602
+
}}
603
+
className="dark:bg-[repeating-linear-gradient(to_bottom,var(--color-gray-500)_0,var(--color-gray-400)_4px,transparent_4px,transparent_8px)]"
604
+
//className="border-gray-400 dark:border-gray-500"
605
+
/>
606
+
</div>
607
+
608
+
<div className="flex items-center pl-3 text-sm text-gray-500 dark:text-gray-400 select-none">
609
+
More Replies
610
+
</div>
611
+
</div>
375
612
);
376
613
}
377
614
615
+
function getAvatarUrl(opProfile: any, did: string, cdn: string) {
616
+
const link = opProfile?.value?.avatar?.ref?.["$link"];
617
+
if (!link) return null;
618
+
return `https://${cdn}/img/avatar/plain/${did}/${link}@jpeg`;
619
+
}
620
+
378
621
export function UniversalPostRendererRawRecordShim({
379
622
postRecord,
380
623
profileRecord,
···
386
629
detailed = false,
387
630
bottomReplyLine = false,
388
631
topReplyLine = false,
389
-
bottomBorder= true,
390
-
feedviewpost= false,
632
+
bottomBorder = true,
633
+
feedviewpost = false,
634
+
repostedby,
635
+
style,
636
+
ref,
637
+
dataIndexPropPass,
638
+
nopics,
639
+
lightboxCallback,
640
+
maxReplies,
641
+
isQuote,
391
642
}: {
392
643
postRecord: any;
393
644
profileRecord: any;
···
401
652
topReplyLine?: boolean;
402
653
bottomBorder?: boolean;
403
654
feedviewpost?: boolean;
655
+
repostedby?: string;
656
+
style?: React.CSSProperties;
657
+
ref?: React.Ref<HTMLDivElement>;
658
+
dataIndexPropPass?: number;
659
+
nopics?: boolean;
660
+
lightboxCallback?: (d: LightboxProps) => void;
661
+
maxReplies?: number;
662
+
isQuote?: boolean;
404
663
}) {
664
+
// /*mass comment*/ console.log(`received aturi: ${aturi} of post content: ${postRecord}`);
405
665
const navigate = useNavigate();
406
666
407
-
const { get, set } = usePersistentStore();
408
-
function getAvatarUrl(opProfile: any) {
409
-
const link = opProfile?.value?.avatar?.ref?.["$link"];
410
-
if (!link) return null;
411
-
return `https://cdn.bsky.app/img/avatar/plain/${resolved?.did}/${link}@jpeg`;
412
-
}
667
+
//const { get, set } = usePersistentStore();
668
+
// const [hydratedEmbed, setHydratedEmbed] = useState<any>(undefined);
413
669
414
-
const [hydratedEmbed, setHydratedEmbed] = useState<any>(undefined);
670
+
// useEffect(() => {
671
+
// const run = async () => {
672
+
// if (!postRecord?.value?.embed) return;
673
+
// const embed = postRecord?.value?.embed;
674
+
// if (!embed || !embed.$type) {
675
+
// setHydratedEmbed(undefined);
676
+
// return;
677
+
// }
415
678
416
-
useEffect(() => {
417
-
const run = async () => {
418
-
if (!postRecord?.value?.embed) return;
419
-
const embed = postRecord?.value?.embed;
420
-
if (!embed || !embed.$type) {
421
-
setHydratedEmbed(undefined);
422
-
return;
423
-
}
679
+
// try {
680
+
// let result: any;
424
681
425
-
try {
426
-
let result: any;
682
+
// if (embed?.$type === "app.bsky.embed.recordWithMedia") {
683
+
// const mediaEmbed = embed.media;
427
684
428
-
if (embed?.$type === "app.bsky.embed.recordWithMedia") {
429
-
const mediaEmbed = embed.media;
685
+
// let hydratedMedia;
686
+
// if (mediaEmbed?.$type === "app.bsky.embed.images") {
687
+
// hydratedMedia = hydrateEmbedImages(mediaEmbed, resolved?.did);
688
+
// } else if (mediaEmbed?.$type === "app.bsky.embed.external") {
689
+
// hydratedMedia = hydrateEmbedExternal(mediaEmbed, resolved?.did);
690
+
// } else if (mediaEmbed?.$type === "app.bsky.embed.video") {
691
+
// hydratedMedia = hydrateEmbedVideo(mediaEmbed, resolved?.did);
692
+
// } else {
693
+
// throw new Error("idiot");
694
+
// }
695
+
// if (!hydratedMedia) throw new Error("idiot");
430
696
431
-
let hydratedMedia;
432
-
if (mediaEmbed?.$type === "app.bsky.embed.images") {
433
-
hydratedMedia = hydrateEmbedImages(mediaEmbed, resolved?.did);
434
-
} else if (mediaEmbed?.$type === "app.bsky.embed.external") {
435
-
hydratedMedia = hydrateEmbedExternal(mediaEmbed, resolved?.did);
436
-
} else if (mediaEmbed?.$type === "app.bsky.embed.video") {
437
-
hydratedMedia = hydrateEmbedVideo(mediaEmbed, resolved?.did);
438
-
} else {
439
-
throw new Error("idiot");
440
-
}
441
-
if (!hydratedMedia) throw new Error("idiot");
697
+
// // hydrate the outer recordWithMedia now using the hydrated media
698
+
// result = await hydrateEmbedRecordWithMedia(
699
+
// embed,
700
+
// resolved?.did,
701
+
// hydratedMedia,
702
+
// get,
703
+
// set,
704
+
// );
705
+
// } else {
706
+
// const hydrated =
707
+
// embed?.$type === "app.bsky.embed.images"
708
+
// ? hydrateEmbedImages(embed, resolved?.did)
709
+
// : embed?.$type === "app.bsky.embed.external"
710
+
// ? hydrateEmbedExternal(embed, resolved?.did)
711
+
// : embed?.$type === "app.bsky.embed.video"
712
+
// ? hydrateEmbedVideo(embed, resolved?.did)
713
+
// : embed?.$type === "app.bsky.embed.record"
714
+
// ? hydrateEmbedRecord(embed, resolved?.did, get, set)
715
+
// : undefined;
442
716
443
-
// hydrate the outer recordWithMedia now using the hydrated media
444
-
result = await hydrateEmbedRecordWithMedia(
445
-
embed,
446
-
resolved?.did,
447
-
hydratedMedia,
448
-
get,
449
-
set,
450
-
);
451
-
} else {
452
-
const hydrated =
453
-
embed?.$type === "app.bsky.embed.images"
454
-
? hydrateEmbedImages(embed, resolved?.did)
455
-
: embed?.$type === "app.bsky.embed.external"
456
-
? hydrateEmbedExternal(embed, resolved?.did)
457
-
: embed?.$type === "app.bsky.embed.video"
458
-
? hydrateEmbedVideo(embed, resolved?.did)
459
-
: embed?.$type === "app.bsky.embed.record"
460
-
? hydrateEmbedRecord(embed, resolved?.did, get, set)
461
-
: undefined;
717
+
// result = hydrated instanceof Promise ? await hydrated : hydrated;
718
+
// }
719
+
720
+
// // /*mass comment*/ console.log(
721
+
// String(result) + " hydrateEmbedRecordWithMedia hey hyeh ye",
722
+
// );
723
+
// setHydratedEmbed(result);
724
+
// } catch (e) {
725
+
// console.error("Error hydrating embed", e);
726
+
// setHydratedEmbed(undefined);
727
+
// }
728
+
// };
462
729
463
-
result = hydrated instanceof Promise ? await hydrated : hydrated;
464
-
}
730
+
// run();
731
+
// }, [postRecord, resolved?.did]);
465
732
466
-
console.log(
467
-
String(result) + " hydrateEmbedRecordWithMedia hey hyeh ye",
468
-
);
469
-
setHydratedEmbed(result);
470
-
} catch (e) {
471
-
console.error("Error hydrating embed", e);
472
-
setHydratedEmbed(undefined);
473
-
}
474
-
};
733
+
const {
734
+
data: hydratedEmbed,
735
+
isLoading: isEmbedLoading,
736
+
error: embedError,
737
+
} = useHydratedEmbed(postRecord?.value?.embed, resolved?.did);
475
738
476
-
run();
477
-
}, [postRecord, resolved?.did]);
739
+
const [imgcdn] = useAtom(imgCDNAtom);
478
740
479
-
const parsedaturi = parseAtUri(aturi);
741
+
const parsedaturi = new AtUri(aturi); //parseAtUri(aturi);
480
742
481
-
const fakepost = React.useMemo<AppBskyFeedDefs.PostView>(() => ({
482
-
$type: "app.bsky.feed.defs#postView",
483
-
uri: aturi,
484
-
cid: postRecord?.cid || "",
485
-
author: {
743
+
const fakeprofileviewbasic = React.useMemo<AppBskyActorDefs.ProfileViewBasic>(
744
+
() => ({
486
745
did: resolved?.did || "",
487
746
handle: resolved?.handle || "",
488
747
displayName: profileRecord?.value?.displayName || "",
489
-
avatar: getAvatarUrl(profileRecord) || "",
748
+
avatar: getAvatarUrl(profileRecord, resolved?.did, imgcdn) || "",
490
749
viewer: undefined,
491
750
labels: profileRecord?.labels || undefined,
492
751
verification: undefined,
493
-
},
494
-
record: postRecord?.value || {},
495
-
embed: hydratedEmbed ?? undefined,
496
-
replyCount: repliesCount ?? 0,
497
-
repostCount: repostsCount ?? 0,
498
-
likeCount: likesCount ?? 0,
499
-
quoteCount: 0,
500
-
indexedAt: postRecord?.value?.createdAt || "",
501
-
viewer: undefined,
502
-
labels: postRecord?.labels || undefined,
503
-
threadgate: undefined,
504
-
}), [
505
-
aturi,
506
-
postRecord,
507
-
profileRecord,
508
-
hydratedEmbed,
509
-
repliesCount,
510
-
repostsCount,
511
-
likesCount,
512
-
resolved,
513
-
]);
752
+
}),
753
+
[imgcdn, profileRecord, resolved?.did, resolved?.handle]
754
+
);
514
755
515
-
const [feedviewpostreplyhandle, setFeedviewpostreplyhandle] = useState<string | undefined>(undefined);
756
+
const fakeprofileviewdetailed =
757
+
React.useMemo<AppBskyActorDefs.ProfileViewDetailed>(
758
+
() => ({
759
+
...fakeprofileviewbasic,
760
+
$type: "app.bsky.actor.defs#profileViewDetailed",
761
+
description: profileRecord?.value?.description || undefined,
762
+
}),
763
+
[fakeprofileviewbasic, profileRecord?.value?.description]
764
+
);
516
765
517
-
useEffect(() => {
518
-
if(!feedviewpost) return;
519
-
let cancelled = false;
766
+
const fakepost = React.useMemo<AppBskyFeedDefs.PostView>(
767
+
() => ({
768
+
$type: "app.bsky.feed.defs#postView",
769
+
uri: aturi,
770
+
cid: postRecord?.cid || "",
771
+
author: fakeprofileviewbasic,
772
+
record: postRecord?.value || {},
773
+
embed: hydratedEmbed ?? undefined,
774
+
replyCount: repliesCount ?? 0,
775
+
repostCount: repostsCount ?? 0,
776
+
likeCount: likesCount ?? 0,
777
+
quoteCount: 0,
778
+
indexedAt: postRecord?.value?.createdAt || "",
779
+
viewer: undefined,
780
+
labels: postRecord?.labels || undefined,
781
+
threadgate: undefined,
782
+
}),
783
+
[
784
+
aturi,
785
+
postRecord?.cid,
786
+
postRecord?.value,
787
+
postRecord?.labels,
788
+
fakeprofileviewbasic,
789
+
hydratedEmbed,
790
+
repliesCount,
791
+
repostsCount,
792
+
likesCount,
793
+
]
794
+
);
520
795
521
-
const run = async () => {
522
-
const thereply = (fakepost?.record as AppBskyFeedPost.Record)?.reply?.parent?.uri;
523
-
const feedviewpostreplydid = thereply ? new AtUri(thereply).host : undefined;
796
+
//const [feedviewpostreplyhandle, setFeedviewpostreplyhandle] = useState<string | undefined>(undefined);
524
797
525
-
if (feedviewpostreplydid) {
526
-
const opi = await cachedResolveIdentity({
527
-
didOrHandle: feedviewpostreplydid,
528
-
get,
529
-
set,
530
-
});
798
+
// useEffect(() => {
799
+
// if(!feedviewpost) return;
800
+
// let cancelled = false;
531
801
532
-
if (!cancelled) {
533
-
setFeedviewpostreplyhandle(opi?.handle);
534
-
}
535
-
}
536
-
};
802
+
// const run = async () => {
803
+
// const thereply = (fakepost?.record as AppBskyFeedPost.Record)?.reply?.parent?.uri;
804
+
// const feedviewpostreplydid = thereply ? new AtUri(thereply).host : undefined;
537
805
538
-
run();
806
+
// if (feedviewpostreplydid) {
807
+
// const opi = await cachedResolveIdentity({
808
+
// didOrHandle: feedviewpostreplydid,
809
+
// get,
810
+
// set,
811
+
// });
812
+
813
+
// if (!cancelled) {
814
+
// setFeedviewpostreplyhandle(opi?.handle);
815
+
// }
816
+
// }
817
+
// };
539
818
540
-
return () => {
541
-
cancelled = true;
542
-
};
543
-
}, [fakepost, get, set]);
819
+
// run();
544
820
821
+
// return () => {
822
+
// cancelled = true;
823
+
// };
824
+
// }, [fakepost, get, set]);
825
+
const thereply = (fakepost?.record as AppBskyFeedPost.Record)?.reply?.parent
826
+
?.uri;
827
+
const feedviewpostreplydid = thereply ? new AtUri(thereply).host : undefined;
828
+
const replyhookvalue = useQueryIdentity(
829
+
feedviewpost ? feedviewpostreplydid : undefined
830
+
);
831
+
const feedviewpostreplyhandle = replyhookvalue?.data?.handle;
832
+
833
+
const aturirepostbydid = repostedby ? new AtUri(repostedby).host : undefined;
834
+
const repostedbyhookvalue = useQueryIdentity(
835
+
repostedby ? aturirepostbydid : undefined
836
+
);
837
+
const feedviewpostrepostedbyhandle = repostedbyhookvalue?.data?.handle;
545
838
return (
546
839
<>
547
840
{/* <p>
···
553
846
parsedaturi &&
554
847
navigate({
555
848
to: "/profile/$did/post/$rkey",
556
-
params: { did: parsedaturi.did, rkey: parsedaturi.rkey },
849
+
params: { did: parsedaturi.host, rkey: parsedaturi.rkey },
557
850
})
558
851
}
559
852
// onProfileClick={() => parsedaturi && navigate({to: "/profile/$did",
···
564
857
if (parsedaturi) {
565
858
navigate({
566
859
to: "/profile/$did",
567
-
params: { did: parsedaturi.did },
860
+
params: { did: parsedaturi.host },
568
861
});
569
862
}
570
863
}}
571
864
post={fakepost}
865
+
uprrrsauthor={fakeprofileviewdetailed}
572
866
salt={aturi}
573
867
bottomReplyLine={bottomReplyLine}
574
868
topReplyLine={topReplyLine}
575
869
bottomBorder={bottomBorder}
576
870
//extraOptionalItemInfo={{reply: postRecord?.value?.reply as AppBskyFeedDefs.ReplyRef, post: fakepost}}
577
871
feedviewpostreplyhandle={feedviewpostreplyhandle}
872
+
repostedby={feedviewpostrepostedbyhandle}
873
+
style={style}
874
+
ref={ref}
875
+
dataIndexPropPass={dataIndexPropPass}
876
+
nopics={nopics}
877
+
lightboxCallback={lightboxCallback}
878
+
maxReplies={maxReplies}
879
+
isQuote={isQuote}
578
880
/>
579
881
</>
580
882
);
581
883
}
582
884
583
-
function hydrateEmbedImages(
584
-
embed: any,
585
-
did: string,
586
-
): $Typed<AppBskyEmbedImages.View> | undefined {
587
-
if (!embed || embed.$type !== "app.bsky.embed.images") return undefined;
588
-
if (!Array.isArray(embed.images)) return undefined;
589
-
return asTyped({
590
-
$type: "app.bsky.embed.images#view" as const, // <-- literal type
591
-
images: embed.images
592
-
.map((img: any) => {
593
-
const link = img?.image?.ref?.["$link"];
594
-
if (!link) return null;
595
-
return {
596
-
thumb: `https://cdn.bsky.app/img/feed_thumbnail/plain/${did}/${link}@jpeg`,
597
-
fullsize: `https://cdn.bsky.app/img/feed_fullsize/plain/${did}/${link}@jpeg`,
598
-
alt: img.alt || "",
599
-
aspectRatio: img.aspectRatio,
600
-
};
601
-
})
602
-
.filter(Boolean),
603
-
});
604
-
}
605
-
606
-
function hydrateEmbedExternal(
607
-
/*{embed, did} : {*/ embed: any,
608
-
did: string, //}
609
-
): $Typed<AppBskyEmbedExternal.View> | undefined {
610
-
if (!embed || embed.$type !== "app.bsky.embed.external") return undefined;
611
-
if (!embed.external) return undefined;
612
-
return asTyped({
613
-
$type: "app.bsky.embed.external#view" as const,
614
-
external: {
615
-
uri: embed.external.uri,
616
-
title: embed.external.title,
617
-
description: embed.external.description,
618
-
thumb: embed?.external?.thumb?.ref?.$link
619
-
? `https://cdn.bsky.app/img/feed_thumbnail/plain/${did}/${embed.external.thumb.ref.$link}@jpeg`
620
-
: undefined,
621
-
},
622
-
});
623
-
}
624
-
625
-
function hydrateEmbedVideo(
626
-
embed: any,
627
-
did: string,
628
-
): $Typed<AppBskyEmbedVideo.View> | undefined {
629
-
if (!embed || embed.$type !== "app.bsky.embed.video") return undefined;
630
-
if (!embed.video || !embed.video.ref?.$link) return undefined;
631
-
632
-
const videoLink = embed.video.ref.$link;
633
-
634
-
return asTyped({
635
-
$type: "app.bsky.embed.video#view" as const,
636
-
playlist: `https://video.bsky.app/watch/${did}/${videoLink}/playlist.m3u8`,
637
-
thumbnail: `https://video.bsky.app/watch/${did}/${videoLink}/thumbnail.jpg`,
638
-
aspectRatio: embed.aspectRatio,
639
-
cid: videoLink,
640
-
});
641
-
}
642
-
async function hydrateEmbedRecordWithMedia(
643
-
embed: any,
644
-
did: string,
645
-
mediaHydratedEmbed:
646
-
| $Typed<AppBskyEmbedImages.View>
647
-
| $Typed<AppBskyEmbedVideo.View>
648
-
| $Typed<AppBskyEmbedExternal.View>
649
-
| { $type: string },
650
-
get: (key: string) => any,
651
-
set: (key: string, value: string) => void,
652
-
): Promise<$Typed<AppBskyEmbedRecordWithMedia.View> | undefined> {
653
-
//return({"hello": "wow"} as any)
654
-
console.log("hydrateEmbedRecordWithMedia called!!");
655
-
if (!embed || embed.$type !== "app.bsky.embed.recordWithMedia")
656
-
return undefined;
657
-
console.log("hydrateEmbedRecordWithMedia 1!!");
658
-
async function deferredrecordget(): Promise<
659
-
$Typed<AppBskyEmbedRecord.ViewRecord>
660
-
> {
661
-
console.log("hydrateEmbedRecordWithMedia 3!!");
662
-
const quoterr = await cachedGetRecord({
663
-
atUri: embed.record.record.uri,
664
-
get,
665
-
set,
666
-
});
667
-
async function defferedQuotedRecordget(): Promise<{
668
-
[_ in string]: unknown;
669
-
}> {
670
-
console.log("hydrateEmbedRecordWithMedia 4!!");
671
-
return quoterr.value;
672
-
}
673
-
async function defferedOPRecordget(): Promise<
674
-
$Typed<AppBskyActorDefs.ProfileViewBasic>
675
-
> {
676
-
const parseduri = parseAtUri(embed.record.record.uri);
677
-
if (!parseduri) throw new Error("invalid uri");
678
-
console.log("deep- hydrateEmbedRecordWithMedia " + parseduri.did);
679
-
const didwhat = parseduri?.did;
680
-
console.log("hydrateEmbedRecordWithMedia 4.97!!");
681
-
const opr = await cachedGetRecord({
682
-
atUri: `at://${didwhat}/app.bsky.actor.profile/self`,
683
-
get,
684
-
set,
685
-
});
686
-
console.log("hydrateEmbedRecordWithMedia 4.98!! opr:" + opr);
687
-
const opi = await cachedResolveIdentity({
688
-
didOrHandle: didwhat,
689
-
get,
690
-
set,
691
-
});
692
-
console.log("hydrateEmbedRecordWithMedia 4.99!!");
693
-
console.log("hydrateEmbedRecordWithMedia 5!!");
694
-
const thedid = didwhat;
695
-
console.log("hydrateEmbedRecordWithMedia 5.01!! " + thedid);
696
-
const thehandle = opi?.handle || "";
697
-
console.log("hydrateEmbedRecordWithMedia 5.02!! " + thehandle);
698
-
const thedisplayname = (opr.value?.displayName ?? opi?.handle) || "";
699
-
console.log("hydrateEmbedRecordWithMedia 5.03!! " + thedisplayname);
700
-
const theavatar = opr.value?.avatar?.ref?.$link
701
-
? `https://cdn.bsky.app/img/avatar/plain/${didwhat}/${opr.value?.avatar?.ref?.$link}@jpeg`
702
-
: undefined;
703
-
console.log("hydrateEmbedRecordWithMedia 5.04!! " + theavatar);
704
-
console.log("hydrateEmbedRecordWithMedia 5.05!!");
705
-
const thecreatedat = opr.value?.createdAt ?? undefined;
706
-
console.log("hydrateEmbedRecordWithMedia 5.06!! " + thecreatedat);
707
-
console.log("hydrateEmbedRecordWithMedia 5.07!!");
708
-
console.log("hydrateEmbedRecordWithMedia 5.08!!");
709
-
const crying = {
710
-
$type: "app.bsky.actor.defs#profileViewBasic" as const,
711
-
did: thedid,
712
-
handle: thehandle,
713
-
displayName: thedisplayname,
714
-
avatar: theavatar,
715
-
associated: {
716
-
chat: {
717
-
allowIncoming: "all",
718
-
},
719
-
},
720
-
labels: [],
721
-
createdAt: thecreatedat,
722
-
};
723
-
return asTyped(crying);
724
-
}
885
+
// export function parseAtUri(
886
+
// atUri: string
887
+
// ): { did: string; collection: string; rkey: string } | null {
888
+
// const PREFIX = "at://";
889
+
// if (!atUri.startsWith(PREFIX)) {
890
+
// return null;
891
+
// }
725
892
726
-
const record = await defferedQuotedRecordget();
727
-
const OP = await defferedOPRecordget();
893
+
// const parts = atUri.slice(PREFIX.length).split("/");
728
894
729
-
console.log("hydrateEmbedRecordWithMedia victory-lap 6!!");
730
-
return asTyped({
731
-
$type: "app.bsky.embed.record#viewRecord" as const,
732
-
uri: embed.record.record.uri,
733
-
cid: embed.record.record.cid,
734
-
indexedAt: String(record.createdAt || "") || "",
735
-
author: OP,
736
-
value: record,
737
-
});
738
-
}
739
-
console.log("hydrateEmbedRecordWithMedia 2!!");
895
+
// if (parts.length !== 3) {
896
+
// return null;
897
+
// }
740
898
741
-
const recordion = await deferredrecordget();
742
-
console.log("hydrateEmbedRecordWithMedia victory-lap 7!!");
899
+
// const [did, collection, rkey] = parts;
743
900
744
-
const final = asTyped({
745
-
$type: "app.bsky.embed.recordWithMedia#view" as const,
746
-
record: {
747
-
//$type: "app.bsky.embed.record#view" as const,
748
-
record: recordion,
749
-
},
750
-
media: mediaHydratedEmbed,
751
-
// media: asTyped({
752
-
// $type: "app.bsky.embed.images" as const,
753
-
// images: embed.media.images
754
-
// ? embed.media.images
755
-
// .map((img: any) => {
756
-
// const link = img?.image?.ref?.["$link"];
757
-
// if (!link) return null;
758
-
// return {
759
-
// thumb: `https://cdn.bsky.app/img/feed_thumbnail/plain/${did}/${link}@jpeg`,
760
-
// fullsize: `https://cdn.bsky.app/img/feed_fullsize/plain/${did}/${link}@jpeg`,
761
-
// alt: img.alt || "",
762
-
// aspectRatio: img.aspectRatio,
763
-
// };
764
-
// })
765
-
// .filter(Boolean)
766
-
// : undefined,
767
-
// }),
768
-
});
769
-
console.log("hydrateEmbedRecordWithMedia final " + final);
770
-
return final;
771
-
}
901
+
// if (!did || !collection || !rkey) {
902
+
// return null;
903
+
// }
772
904
773
-
async function hydrateEmbedRecord(
774
-
embed: any,
775
-
did: string,
776
-
get: (key: string) => any,
777
-
set: (key: string, value: string) => void,
778
-
): Promise<$Typed<AppBskyEmbedRecord.View> | undefined> {
779
-
if (!embed || embed.$type !== "app.bsky.embed.record") return undefined;
780
-
781
-
const recordRef = embed.record?.record?.uri
782
-
? embed.record.record
783
-
: embed.record;
784
-
785
-
const quoted = await cachedGetRecord({
786
-
atUri: recordRef.uri,
787
-
get,
788
-
set,
789
-
});
790
-
791
-
const parseduri = parseAtUri(recordRef.uri);
792
-
if (!parseduri) throw new Error("invalid uri");
793
-
const didwhat = parseduri.did;
794
-
795
-
const opr = await cachedGetRecord({
796
-
atUri: `at://${didwhat}/app.bsky.actor.profile/self`,
797
-
get,
798
-
set,
799
-
});
800
-
const opi = await cachedResolveIdentity({
801
-
didOrHandle: didwhat,
802
-
get,
803
-
set,
804
-
});
805
-
806
-
const author = {
807
-
$type: "app.bsky.actor.defs#profileViewBasic" as const,
808
-
did: didwhat,
809
-
handle: opi?.handle || "",
810
-
displayName: (opr.value?.displayName ?? opi?.handle) || "",
811
-
avatar: opr.value?.avatar?.ref?.$link
812
-
? `https://cdn.bsky.app/img/avatar/plain/${didwhat}/${opr.value?.avatar?.ref?.$link}@jpeg`
813
-
: undefined,
814
-
associated: {
815
-
chat: {
816
-
allowIncoming: "all",
817
-
},
818
-
},
819
-
labels: [],
820
-
createdAt: opr.value?.createdAt ?? undefined,
821
-
};
822
-
823
-
const viewRecord: $Typed<AppBskyEmbedRecord.ViewRecord> = asTyped({
824
-
$type: "app.bsky.embed.record#viewRecord" as const,
825
-
uri: recordRef.uri,
826
-
cid: recordRef.cid,
827
-
indexedAt: String(quoted.value.createdAt || "") || "",
828
-
author,
829
-
value: quoted.value,
830
-
replyCount: quoted.value.replyCount,
831
-
repostCount: quoted.value.repostCount,
832
-
likeCount: quoted.value.likeCount,
833
-
quoteCount: quoted.value.quoteCount,
834
-
labels: quoted.value.labels,
835
-
embeds: quoted.value.embed ? [quoted.value.embed] : undefined,
836
-
});
837
-
838
-
return asTyped({
839
-
$type: "app.bsky.embed.record#view" as const,
840
-
record: viewRecord,
841
-
});
842
-
}
843
-
844
-
export function parseAtUri(
845
-
atUri: string,
846
-
): { did: string; collection: string; rkey: string } | null {
847
-
const PREFIX = "at://";
848
-
if (!atUri.startsWith(PREFIX)) {
849
-
return null;
850
-
}
851
-
852
-
const parts = atUri.slice(PREFIX.length).split("/");
853
-
854
-
if (parts.length !== 3) {
855
-
return null;
856
-
}
857
-
858
-
const [did, collection, rkey] = parts;
859
-
860
-
if (!did || !collection || !rkey) {
861
-
return null;
862
-
}
863
-
864
-
return { did, collection, rkey };
865
-
}
905
+
// return { did, collection, rkey };
906
+
// }
866
907
867
908
export function MdiCommentOutline(props: SVGProps<SVGSVGElement>) {
868
909
return (
···
874
915
{...props}
875
916
>
876
917
<path
877
-
fill="oklch(0.704 0.05 28)"
918
+
fill="var(--color-gray-400)"
878
919
d="M9 22a1 1 0 0 1-1-1v-3H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2h-6.1l-3.7 3.71c-.2.19-.45.29-.7.29zm1-6v3.08L13.08 16H20V4H4v12z"
879
920
></path>
880
921
</svg>
···
891
932
{...props}
892
933
>
893
934
<path
894
-
fill="oklch(0.704 0.05 28)"
935
+
fill="var(--color-gray-400)"
895
936
d="M17 17H7v-3l-4 4l4 4v-3h12v-6h-2M7 7h10v3l4-4l-4-4v3H5v6h2z"
896
937
></path>
897
938
</svg>
···
942
983
{...props}
943
984
>
944
985
<path
945
-
fill="oklch(0.704 0.05 28)"
986
+
fill="var(--color-gray-400)"
946
987
d="m12.1 18.55l-.1.1l-.11-.1C7.14 14.24 4 11.39 4 8.5C4 6.5 5.5 5 7.5 5c1.54 0 3.04 1 3.57 2.36h1.86C13.46 6 14.96 5 16.5 5c2 0 3.5 1.5 3.5 3.5c0 2.89-3.14 5.74-7.9 10.05M16.5 3c-1.74 0-3.41.81-4.5 2.08C10.91 3.81 9.24 3 7.5 3C4.42 3 2 5.41 2 8.5c0 3.77 3.4 6.86 8.55 11.53L12 21.35l1.45-1.32C18.6 15.36 22 12.27 22 8.5C22 5.41 19.58 3 16.5 3"
947
988
></path>
948
989
</svg>
···
959
1000
{...props}
960
1001
>
961
1002
<path
962
-
fill="oklch(0.704 0.05 28)"
1003
+
fill="var(--color-gray-400)"
963
1004
d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81a3 3 0 0 0 3-3a3 3 0 0 0-3-3a3 3 0 0 0-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9a3 3 0 0 0-3 3a3 3 0 0 0 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.15c-.05.21-.08.43-.08.66c0 1.61 1.31 2.91 2.92 2.91s2.92-1.3 2.92-2.91A2.92 2.92 0 0 0 18 16.08"
964
1005
></path>
965
1006
</svg>
···
976
1017
{...props}
977
1018
>
978
1019
<path
979
-
fill="oklch(0.704 0.05 28)"
1020
+
fill="var(--color-gray-400)"
980
1021
d="M16 12a2 2 0 0 1 2-2a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2m-6 0a2 2 0 0 1 2-2a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2m-6 0a2 2 0 0 1 2-2a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2"
981
1022
></path>
982
1023
</svg>
···
993
1034
{...props}
994
1035
>
995
1036
<path
996
-
fill="oklch(0.704 0.05 28)"
1037
+
fill="var(--color-gray-400)"
997
1038
d="M17.9 17.39c-.26-.8-1.01-1.39-1.9-1.39h-1v-3a1 1 0 0 0-1-1H8v-2h2a1 1 0 0 0 1-1V7h2a2 2 0 0 0 2-2v-.41a7.984 7.984 0 0 1 2.9 12.8M11 19.93c-3.95-.49-7-3.85-7-7.93c0-.62.08-1.22.21-1.79L9 15v1a2 2 0 0 0 2 2m1-16A10 10 0 0 0 2 12a10 10 0 0 0 10 10a10 10 0 0 0 10-10A10 10 0 0 0 12 2"
998
1039
></path>
999
1040
</svg>
···
1027
1068
{...props}
1028
1069
>
1029
1070
<path
1030
-
fill="oklch(0.704 0.05 28)"
1071
+
fill="var(--color-gray-400)"
1031
1072
d="M10 9V5l-7 7l7 7v-4.1c5 0 8.5 1.6 11 5.1c-1-5-4-10-11-11"
1032
1073
></path>
1033
1074
</svg>
···
1081
1122
{...props}
1082
1123
>
1083
1124
<path
1084
-
fill="oklch(0.704 0.05 28)"
1125
+
fill="var(--color-gray-400)"
1085
1126
d="M17 17H7v-3l-4 4l4 4v-3h12v-6h-2M7 7h10v3l4-4l-4-4v3H5v6h2z"
1086
1127
></path>
1087
1128
</svg>
···
1098
1139
{...props}
1099
1140
>
1100
1141
<path
1101
-
fill="oklch(0.704 0.05 28)"
1142
+
fill="var(--color-gray-400)"
1102
1143
d="M6 5.75L10.25 10H7v6h6.5l2 2H7a2 2 0 0 1-2-2v-6H1.75zm12 12.5L13.75 14H17V8h-6.5l-2-2H17a2 2 0 0 1 2 2v6h3.25z"
1103
1144
></path>
1104
1145
</svg>
···
1123
1164
}
1124
1165
1125
1166
/* what imported from testfront */
1126
-
import defaultpfp from "~/../public/favicon.png";
1127
-
1128
1167
//import Masonry from "@mui/lab/Masonry";
1129
1168
import {
1169
+
type $Typed,
1130
1170
AppBskyActorDefs,
1131
1171
AppBskyEmbedDefs,
1132
1172
AppBskyEmbedExternal,
···
1138
1178
AppBskyFeedPost,
1139
1179
AppBskyGraphDefs,
1140
1180
AtUri,
1181
+
type Facet,
1141
1182
//AppBskyLabelerDefs,
1142
1183
//AtUri,
1143
1184
//ComAtprotoRepoStrongRef,
1144
1185
ModerationDecision,
1145
-
type $Typed,
1146
-
type Facet,
1147
1186
} from "@atproto/api";
1148
1187
import type {
1149
1188
//BlockedPost,
···
1152
1191
PostView,
1153
1192
//ThreadViewPost,
1154
1193
} from "@atproto/api/dist/client/types/app/bsky/feed/defs";
1194
+
import { useInfiniteQuery } from "@tanstack/react-query";
1155
1195
import { useEffect, useRef, useState } from "react";
1156
1196
import ReactPlayer from "react-player";
1157
-
import { useAuth } from "~/providers/PassAuthProvider";
1197
+
1198
+
import defaultpfp from "~/../public/favicon.png";
1199
+
import { useAuth } from "~/providers/UnifiedAuthProvider";
1200
+
import { FollowButton, Mutual } from "~/routes/profile.$did";
1201
+
import type { LightboxProps } from "~/routes/profile.$did/post.$rkey.image.$i";
1158
1202
// import type { OutputSchema } from "@atproto/api/dist/client/types/app/bsky/feed/getFeed";
1159
1203
// import type {
1160
1204
// ViewRecord,
···
1256
1300
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
1257
1301
return Array.from(
1258
1302
{ length },
1259
-
() => chars[Math.floor(Math.random() * chars.length)],
1303
+
() => chars[Math.floor(Math.random() * chars.length)]
1260
1304
).join("");
1261
1305
}
1262
1306
1263
1307
function UniversalPostRenderer({
1264
1308
post,
1309
+
uprrrsauthor,
1265
1310
//setMainItem,
1266
1311
//isMainItem,
1267
1312
onPostClick,
···
1276
1321
salt,
1277
1322
bottomBorder = true,
1278
1323
feedviewpostreplyhandle,
1324
+
depth = 0,
1325
+
repostedby,
1326
+
style,
1327
+
ref,
1328
+
dataIndexPropPass,
1329
+
nopics,
1330
+
lightboxCallback,
1331
+
maxReplies,
1279
1332
}: {
1280
1333
post: PostView;
1334
+
uprrrsauthor?: AppBskyActorDefs.ProfileViewDetailed;
1281
1335
// optional for now because i havent ported every use to this yet
1282
1336
// setMainItem?: React.Dispatch<
1283
1337
// React.SetStateAction<AppBskyFeedDefs.FeedViewPost>
···
1293
1347
salt: string;
1294
1348
bottomBorder?: boolean;
1295
1349
feedviewpostreplyhandle?: string;
1350
+
depth?: number;
1351
+
repostedby?: string;
1352
+
style?: React.CSSProperties;
1353
+
ref?: React.Ref<HTMLDivElement>;
1354
+
dataIndexPropPass?: number;
1355
+
nopics?: boolean;
1356
+
lightboxCallback?: (d: LightboxProps) => void;
1357
+
maxReplies?: number;
1296
1358
}) {
1359
+
const parsed = new AtUri(post.uri);
1297
1360
const navigate = useNavigate();
1298
-
const [hasRetweeted, setHasRetweeted] = useState<Boolean>(
1299
-
post.viewer?.repost ? true : false,
1361
+
const [likedPosts, setLikedPosts] = useAtom(likedPostsAtom);
1362
+
const [hasRetweeted, setHasRetweeted] = useState<boolean>(
1363
+
post.viewer?.repost ? true : false
1300
1364
);
1301
-
const [hasLiked, setHasLiked] = useState<Boolean>(
1302
-
post.viewer?.like ? true : false,
1365
+
const [hasLiked, setHasLiked] = useState<boolean>(
1366
+
post.uri in likedPosts || post.viewer?.like ? true : false
1303
1367
);
1368
+
const [, setComposerPost] = useAtom(composerAtom);
1304
1369
const { agent } = useAuth();
1305
1370
const [likeUri, setLikeUri] = useState<string | undefined>(post.viewer?.like);
1306
1371
const [retweetUri, setRetweetUri] = useState<string | undefined>(
1307
-
post.viewer?.repost,
1372
+
post.viewer?.repost
1308
1373
);
1309
1374
1310
1375
const likeOrUnlikePost = async () => {
1376
+
const newLikedPosts = { ...likedPosts };
1311
1377
if (!agent) {
1312
1378
console.error("Agent is null or undefined");
1313
1379
return;
1314
1380
}
1315
1381
if (hasLiked) {
1382
+
if (post.uri in likedPosts) {
1383
+
const likeUri = likedPosts[post.uri];
1384
+
setLikeUri(likeUri);
1385
+
}
1316
1386
if (likeUri) {
1317
1387
await agent.deleteLike(likeUri);
1318
1388
setHasLiked(false);
1389
+
delete newLikedPosts[post.uri];
1319
1390
}
1320
1391
} else {
1321
1392
const { uri } = await agent.like(post.uri, post.cid);
1322
1393
setLikeUri(uri);
1323
1394
setHasLiked(true);
1395
+
newLikedPosts[post.uri] = uri;
1324
1396
}
1397
+
setLikedPosts(newLikedPosts);
1325
1398
};
1326
1399
1327
1400
const repostOrUnrepostPost = async () => {
···
1341
1414
}
1342
1415
};
1343
1416
1344
-
const isRepost = extraOptionalItemInfo
1345
-
? AppBskyFeedDefs.isReasonRepost(extraOptionalItemInfo.reason)
1346
-
? extraOptionalItemInfo.reason?.by.displayName
1347
-
: undefined
1348
-
: undefined;
1417
+
const isRepost = repostedby
1418
+
? repostedby
1419
+
: extraOptionalItemInfo
1420
+
? AppBskyFeedDefs.isReasonRepost(extraOptionalItemInfo.reason)
1421
+
? extraOptionalItemInfo.reason?.by.displayName
1422
+
: undefined
1423
+
: undefined;
1349
1424
const isReply = extraOptionalItemInfo
1350
1425
? extraOptionalItemInfo.reply
1351
1426
: undefined;
1352
1427
1353
1428
const emergencySalt = randomString();
1429
+
const fedi = (post.record as { bridgyOriginalText?: string })
1430
+
.bridgyOriginalText;
1354
1431
1355
1432
/* fuck you */
1356
1433
const isMainItem = false;
1357
1434
const setMainItem = (any: any) => {};
1435
+
// eslint-disable-next-line react-hooks/refs
1436
+
console.log("Received ref in UniversalPostRenderer:", ref);
1358
1437
return (
1359
-
<div
1360
-
key={salt + "-" + (post.uri || emergencySalt)}
1361
-
onClick={
1362
-
isMainItem
1363
-
? onPostClick
1364
-
: setMainItem
1365
-
? onPostClick
1366
-
? (e) => {
1367
-
setMainItem({ post: post });
1368
-
onPostClick(e);
1369
-
}
1370
-
: () => {
1371
-
setMainItem({ post: post });
1372
-
}
1373
-
: undefined
1374
-
}
1375
-
style={{
1376
-
//border: "1px solid #e1e8ed",
1377
-
//borderRadius: 12,
1378
-
opacity: "1 !important",
1379
-
background: "transparent",
1380
-
paddingLeft: isQuote ? 12 : 16,
1381
-
paddingRight: isQuote ? 12 : 16,
1382
-
//paddingTop: 16,
1383
-
paddingTop: isRepost ? 10 : isQuote ? 12 : 16,
1384
-
//paddingBottom: bottomReplyLine ? 0 : 16,
1385
-
paddingBottom: 0,
1386
-
fontFamily: "system-ui, sans-serif",
1387
-
//boxShadow: "0 2px 8px rgba(0,0,0,0.04)",
1388
-
position: "relative",
1389
-
// dont cursor: "pointer",
1390
-
borderBottomWidth: bottomBorder ? isQuote ? 0 : 1 : 0,
1391
-
}}
1392
-
className="border-gray-300 dark:border-gray-600"
1393
-
>
1394
-
{isRepost && (
1395
-
<div
1396
-
style={{
1397
-
marginLeft: 36,
1398
-
display: "flex",
1399
-
borderRadius: 12,
1400
-
paddingBottom: "calc(22px - 1rem)",
1401
-
fontSize: 14,
1402
-
maxHeight: "1rem",
1403
-
justifyContent: "flex-start",
1404
-
//color: theme.textSecondary,
1405
-
gap: 4,
1406
-
alignItems: "center",
1407
-
}}
1408
-
className="text-gray-500 dark:text-gray-400"
1409
-
>
1410
-
<MdiRepost /> Reposted by {isRepost}{" "}
1411
-
</div>
1412
-
)}
1413
-
{!isQuote && (
1414
-
<div
1415
-
style={{
1416
-
opacity: topReplyLine || (isReply && (true || expanded)) ? 0.5 : 0,
1417
-
position: "absolute",
1418
-
top: 0,
1419
-
left: 36, // why 36 ???
1420
-
//left: 16 + (42 / 2),
1421
-
width: 2,
1422
-
//height: "100%",
1423
-
height: isRepost ? "calc(16px + 1rem - 6px)" : 16 - 6,
1424
-
// background: theme.textSecondary,
1425
-
//opacity: 0.5,
1426
-
// no flex here
1427
-
}}
1428
-
className="bg-gray-500 dark:bg-gray-400"
1429
-
/>
1430
-
)}
1438
+
<div ref={ref} style={style} data-index={dataIndexPropPass}>
1431
1439
<div
1440
+
//ref={ref}
1441
+
key={salt + "-" + (post.uri || emergencySalt)}
1442
+
onClick={
1443
+
isMainItem
1444
+
? onPostClick
1445
+
: setMainItem
1446
+
? onPostClick
1447
+
? (e) => {
1448
+
setMainItem({ post: post });
1449
+
onPostClick(e);
1450
+
}
1451
+
: () => {
1452
+
setMainItem({ post: post });
1453
+
}
1454
+
: undefined
1455
+
}
1432
1456
style={{
1433
-
position: "absolute",
1434
-
//top: isRepost ? "calc(16px + 1rem)" : 16,
1435
-
//left: 16,
1436
-
zIndex: 1,
1437
-
top: isRepost ? "calc(16px + 1rem)" : isQuote ? 12 : 16,
1438
-
left: isQuote ? 12 : 16,
1457
+
//...style,
1458
+
//border: "1px solid #e1e8ed",
1459
+
//borderRadius: 12,
1460
+
opacity: "1 !important",
1461
+
background: "transparent",
1462
+
paddingLeft: isQuote ? 12 : 16,
1463
+
paddingRight: isQuote ? 12 : 16,
1464
+
//paddingTop: 16,
1465
+
paddingTop: isRepost ? 10 : isQuote ? 12 : topReplyLine ? 8 : 16,
1466
+
//paddingBottom: bottomReplyLine ? 0 : 16,
1467
+
paddingBottom: 0,
1468
+
fontFamily: "system-ui, sans-serif",
1469
+
//boxShadow: "0 2px 8px rgba(0,0,0,0.04)",
1470
+
position: "relative",
1471
+
// dont cursor: "pointer",
1472
+
borderBottomWidth: bottomBorder ? (isQuote ? 0 : 1) : 0,
1439
1473
}}
1440
-
onClick={onProfileClick}
1474
+
className="border-gray-300 dark:border-gray-800"
1441
1475
>
1442
-
<img
1443
-
src={post.author.avatar || defaultpfp}
1444
-
alt="avatar"
1445
-
// transition={{
1446
-
// type: "spring",
1447
-
// stiffness: 260,
1448
-
// damping: 20,
1449
-
// }}
1450
-
style={{
1451
-
borderRadius: "50%",
1452
-
marginRight: 12,
1453
-
objectFit: "cover",
1454
-
//background: theme.border,
1455
-
//border: `1px solid ${theme.border}`,
1456
-
width: isQuote ? 16 : 42,
1457
-
height: isQuote ? 16 : 42,
1458
-
}}
1459
-
className="border border-gray-300 dark:border-gray-600 bg-gray-300 dark:bg-gray-600"
1460
-
/>
1461
-
</div>
1462
-
<div style={{ display: "flex", alignItems: "flex-start", zIndex: 2 }}>
1463
-
<div
1464
-
style={{
1465
-
display: "flex",
1466
-
flexDirection: "column",
1467
-
alignSelf: "stretch",
1468
-
alignItems: "center",
1469
-
overflow: "hidden",
1470
-
width: expanded || isQuote ? 0 : "auto",
1471
-
marginRight: expanded || isQuote ? 0 : 12,
1472
-
}}
1473
-
>
1474
-
{/* dummy for later use */}
1475
-
<div style={{ width: 42, height: 42 + 8, minHeight: 42 + 8 }} />
1476
-
{/* reply line !!!! bottomReplyLine */}
1477
-
{bottomReplyLine && (
1476
+
{isRepost && (
1477
+
<div
1478
+
style={{
1479
+
marginLeft: 36,
1480
+
display: "flex",
1481
+
borderRadius: 12,
1482
+
paddingBottom: "calc(22px - 1rem)",
1483
+
fontSize: 14,
1484
+
maxHeight: "1rem",
1485
+
justifyContent: "flex-start",
1486
+
//color: theme.textSecondary,
1487
+
gap: 4,
1488
+
alignItems: "center",
1489
+
}}
1490
+
className="text-gray-500 dark:text-gray-400"
1491
+
>
1492
+
<MdiRepost /> Reposted by @{isRepost}{" "}
1493
+
</div>
1494
+
)}
1495
+
{!isQuote && (
1496
+
<div
1497
+
style={{
1498
+
opacity:
1499
+
topReplyLine || isReply /*&& (true || expanded)*/ ? 0.5 : 0,
1500
+
position: "absolute",
1501
+
top: 0,
1502
+
left: 36, // why 36 ???
1503
+
//left: 16 + (42 / 2),
1504
+
width: 2,
1505
+
//height: "100%",
1506
+
height: isRepost
1507
+
? "calc(16px + 1rem - 6px)"
1508
+
: topReplyLine
1509
+
? 8 - 6
1510
+
: 16 - 6,
1511
+
// background: theme.textSecondary,
1512
+
//opacity: 0.5,
1513
+
// no flex here
1514
+
}}
1515
+
className="bg-gray-500 dark:bg-gray-400"
1516
+
/>
1517
+
)}
1518
+
<HoverCard.Root>
1519
+
<HoverCard.Trigger asChild>
1478
1520
<div
1521
+
className={`absolute`}
1479
1522
style={{
1480
-
width: 2,
1481
-
height: "100%",
1482
-
//background: theme.textSecondary,
1483
-
opacity: 0.5,
1484
-
// no flex here
1485
-
//color: "Red",
1486
-
//zIndex: 99
1523
+
top: isRepost
1524
+
? "calc(16px + 1rem)"
1525
+
: isQuote
1526
+
? 12
1527
+
: topReplyLine
1528
+
? 8
1529
+
: 16,
1530
+
left: isQuote ? 12 : 16,
1487
1531
}}
1488
-
className="bg-gray-500 dark:bg-gray-400"
1489
-
/>
1490
-
)}
1491
-
{/* <div
1532
+
onClick={onProfileClick}
1533
+
>
1534
+
<img
1535
+
src={post.author.avatar || defaultpfp}
1536
+
alt="avatar"
1537
+
className={`rounded-full object-cover border border-gray-300 dark:border-gray-800 bg-gray-300 dark:bg-gray-600`}
1538
+
style={{
1539
+
width: isQuote ? 16 : 42,
1540
+
height: isQuote ? 16 : 42,
1541
+
}}
1542
+
/>
1543
+
</div>
1544
+
</HoverCard.Trigger>
1545
+
<HoverCard.Portal>
1546
+
<HoverCard.Content
1547
+
className="rounded-md p-4 w-72 bg-gray-50 dark:bg-gray-900 shadow-lg border border-gray-300 dark:border-gray-800 animate-slide-fade z-50"
1548
+
side={"bottom"}
1549
+
sideOffset={5}
1550
+
onClick={onProfileClick}
1551
+
>
1552
+
<div className="flex flex-col gap-2">
1553
+
<div className="flex flex-row">
1554
+
<img
1555
+
src={post.author.avatar || defaultpfp}
1556
+
alt="avatar"
1557
+
className="rounded-full w-[58px] h-[58px] object-cover border border-gray-300 dark:border-gray-800 bg-gray-300 dark:bg-gray-600"
1558
+
/>
1559
+
<div className=" flex-1 flex flex-row align-middle justify-end">
1560
+
<div className=" flex flex-col justify-start">
1561
+
<FollowButton targetdidorhandle={post.author.did} />
1562
+
</div>
1563
+
</div>
1564
+
</div>
1565
+
<div className="flex flex-col gap-3">
1566
+
<div>
1567
+
<div className="text-gray-900 dark:text-gray-100 font-medium text-md">
1568
+
{post.author.displayName || post.author.handle}{" "}
1569
+
</div>
1570
+
<div className="text-gray-500 dark:text-gray-400 text-md flex flex-row gap-1">
1571
+
<Mutual targetdidorhandle={post.author.did} />@{post.author.handle}{" "}
1572
+
</div>
1573
+
</div>
1574
+
{uprrrsauthor?.description && (
1575
+
<div className="text-gray-700 dark:text-gray-300 text-sm text-left break-words line-clamp-3">
1576
+
{uprrrsauthor.description}
1577
+
</div>
1578
+
)}
1579
+
{/* <div className="flex gap-4">
1580
+
<div className="flex gap-1">
1581
+
<div className="font-medium text-gray-900 dark:text-gray-100">
1582
+
0
1583
+
</div>
1584
+
<div className="text-gray-500 dark:text-gray-400">
1585
+
Following
1586
+
</div>
1587
+
</div>
1588
+
<div className="flex gap-1">
1589
+
<div className="font-medium text-gray-900 dark:text-gray-100">
1590
+
2,900
1591
+
</div>
1592
+
<div className="text-gray-500 dark:text-gray-400">
1593
+
Followers
1594
+
</div>
1595
+
</div>
1596
+
</div> */}
1597
+
</div>
1598
+
</div>
1599
+
1600
+
{/* <HoverCard.Arrow className="fill-gray-50 dark:fill-gray-900" /> */}
1601
+
</HoverCard.Content>
1602
+
</HoverCard.Portal>
1603
+
</HoverCard.Root>
1604
+
1605
+
<div style={{ display: "flex", alignItems: "flex-start", zIndex: 2 }}>
1606
+
<div
1607
+
style={{
1608
+
display: "flex",
1609
+
flexDirection: "column",
1610
+
alignSelf: "stretch",
1611
+
alignItems: "center",
1612
+
overflow: "hidden",
1613
+
width: expanded || isQuote ? 0 : "auto",
1614
+
marginRight: expanded || isQuote ? 0 : 12,
1615
+
}}
1616
+
>
1617
+
{/* dummy for later use */}
1618
+
<div style={{ width: 42, height: 42 + 6, minHeight: 42 + 6 }} />
1619
+
{/* reply line !!!! bottomReplyLine */}
1620
+
{bottomReplyLine && (
1621
+
<div
1622
+
style={{
1623
+
width: 2,
1624
+
height: "100%",
1625
+
//background: theme.textSecondary,
1626
+
opacity: 0.5,
1627
+
// no flex here
1628
+
//color: "Red",
1629
+
//zIndex: 99
1630
+
}}
1631
+
className="bg-gray-500 dark:bg-gray-400"
1632
+
/>
1633
+
)}
1634
+
{/* <div
1492
1635
layout
1493
1636
transition={{ duration: 0.2 }}
1494
1637
animate={{ height: expanded ? 0 : '100%' }}
···
1498
1641
// no flex here
1499
1642
}}
1500
1643
/> */}
1501
-
</div>
1502
-
<div style={{ flex: 1, maxWidth: "100%" }}>
1503
-
<div
1504
-
style={{
1505
-
display: "flex",
1506
-
flexDirection: "row",
1507
-
alignItems: "center",
1508
-
flexWrap: "nowrap",
1509
-
maxWidth: `calc(100% - ${!expanded ? (isQuote ? 26 : 0) : 54}px)`,
1510
-
width: `calc(100% - ${!expanded ? (isQuote ? 26 : 0) : 54}px)`,
1511
-
marginLeft: !expanded ? (isQuote ? 26 : 0) : 54,
1512
-
marginBottom: !expanded ? 4 : 0,
1513
-
}}
1514
-
>
1644
+
</div>
1645
+
<div style={{ flex: 1, maxWidth: "100%" }}>
1515
1646
<div
1516
1647
style={{
1517
1648
display: "flex",
1518
-
//overflow: "hidden", // hey why is overflow hidden unapplied
1519
-
overflow: "hidden",
1520
-
textOverflow: "ellipsis",
1521
-
flexShrink: 1,
1522
-
flexGrow: 1,
1523
-
flexBasis: 0,
1524
-
width: 0,
1525
-
gap: expanded ? 0 : 6,
1526
-
alignItems: expanded ? "flex-start" : "center",
1527
-
flexDirection: expanded ? "column" : "row",
1528
-
height: expanded ? 48 : "1rem",
1649
+
flexDirection: "row",
1650
+
alignItems: "center",
1651
+
flexWrap: "nowrap",
1652
+
maxWidth: `calc(100% - ${!expanded ? (isQuote ? 26 : 0) : 54}px)`,
1653
+
width: `calc(100% - ${!expanded ? (isQuote ? 26 : 0) : 54}px)`,
1654
+
marginLeft: !expanded ? (isQuote ? 26 : 0) : 54,
1655
+
marginBottom: !expanded ? 4 : 6,
1529
1656
}}
1530
1657
>
1531
-
<span
1658
+
<div
1532
1659
style={{
1533
1660
display: "flex",
1534
-
fontWeight: 700,
1535
-
fontSize: 16,
1661
+
//overflow: "hidden", // hey why is overflow hidden unapplied
1536
1662
overflow: "hidden",
1537
1663
textOverflow: "ellipsis",
1538
-
whiteSpace: "nowrap",
1539
1664
flexShrink: 1,
1540
-
minWidth: 0,
1541
-
gap: 4,
1542
-
alignItems: "center",
1543
-
//color: theme.text,
1665
+
flexGrow: 1,
1666
+
flexBasis: 0,
1667
+
width: 0,
1668
+
gap: expanded ? 0 : 6,
1669
+
alignItems: expanded ? "flex-start" : "center",
1670
+
flexDirection: expanded ? "column" : "row",
1671
+
height: expanded ? 42 : "1rem",
1544
1672
}}
1545
-
className="text-gray-900 dark:text-gray-100"
1546
1673
>
1547
-
{/* verified checkmark */}
1548
-
{post.author.displayName || post.author.handle}{" "}
1549
-
{post.author.verification?.verifiedStatus == "valid" && (
1550
-
<MdiVerified />
1551
-
)}
1552
-
</span>
1674
+
<span
1675
+
style={{
1676
+
display: "flex",
1677
+
fontWeight: 700,
1678
+
fontSize: 16,
1679
+
overflow: "hidden",
1680
+
textOverflow: "ellipsis",
1681
+
whiteSpace: "nowrap",
1682
+
flexShrink: 1,
1683
+
minWidth: 0,
1684
+
gap: 4,
1685
+
alignItems: "center",
1686
+
//color: theme.text,
1687
+
}}
1688
+
className="text-gray-900 dark:text-gray-100"
1689
+
>
1690
+
{/* verified checkmark */}
1691
+
{post.author.displayName || post.author.handle}{" "}
1692
+
{post.author.verification?.verifiedStatus == "valid" && (
1693
+
<MdiVerified />
1694
+
)}
1695
+
</span>
1553
1696
1554
-
<span
1697
+
<span
1698
+
style={{
1699
+
//color: theme.textSecondary,
1700
+
fontSize: 16,
1701
+
overflowX: "hidden",
1702
+
textOverflow: "ellipsis",
1703
+
whiteSpace: "nowrap",
1704
+
flexShrink: 1,
1705
+
flexGrow: 0,
1706
+
minWidth: 0,
1707
+
}}
1708
+
className="text-gray-500 dark:text-gray-400"
1709
+
>
1710
+
@{post.author.handle}
1711
+
</span>
1712
+
</div>
1713
+
<div
1555
1714
style={{
1556
-
//color: theme.textSecondary,
1557
-
fontSize: 16,
1558
-
overflowX: "hidden",
1559
-
textOverflow: "ellipsis",
1560
-
whiteSpace: "nowrap",
1561
-
flexShrink: 1,
1562
-
flexGrow: 0,
1563
-
minWidth: 0,
1715
+
display: "flex",
1716
+
alignItems: "center",
1717
+
height: "1rem",
1564
1718
}}
1565
-
className="text-gray-500 dark:text-gray-400"
1566
1719
>
1567
-
@{post.author.handle}
1568
-
</span>
1720
+
<span
1721
+
style={{
1722
+
//color: theme.textSecondary,
1723
+
fontSize: 16,
1724
+
marginLeft: 8,
1725
+
whiteSpace: "nowrap",
1726
+
flexShrink: 0,
1727
+
maxWidth: "100%",
1728
+
}}
1729
+
className="text-gray-500 dark:text-gray-400"
1730
+
>
1731
+
ยท {/* time placeholder */}
1732
+
{shortTimeAgo(post.indexedAt)}
1733
+
</span>
1734
+
</div>
1569
1735
</div>
1570
-
<div
1571
-
style={{
1572
-
display: "flex",
1573
-
alignItems: "center",
1574
-
height: "1rem",
1575
-
}}
1576
-
>
1577
-
<span
1736
+
{/* reply indicator */}
1737
+
{!!feedviewpostreplyhandle && (
1738
+
<div
1578
1739
style={{
1740
+
display: "flex",
1741
+
borderRadius: 12,
1742
+
paddingBottom: 2,
1743
+
fontSize: 14,
1744
+
justifyContent: "flex-start",
1579
1745
//color: theme.textSecondary,
1580
-
fontSize: 16,
1581
-
marginLeft: 8,
1582
-
whiteSpace: "nowrap",
1583
-
flexShrink: 0,
1584
-
maxWidth: "100%",
1746
+
gap: 4,
1747
+
alignItems: "center",
1748
+
//marginLeft: 36,
1749
+
height:
1750
+
!(expanded || isQuote) && !!feedviewpostreplyhandle
1751
+
? "1rem"
1752
+
: 0,
1753
+
opacity:
1754
+
!(expanded || isQuote) && !!feedviewpostreplyhandle ? 1 : 0,
1585
1755
}}
1586
1756
className="text-gray-500 dark:text-gray-400"
1587
1757
>
1588
-
ยท {/* time placeholder */}
1589
-
{shortTimeAgo(post.indexedAt)}
1590
-
</span>
1591
-
</div>
1592
-
</div>
1593
-
{/* reply indicator */}
1594
-
{!!feedviewpostreplyhandle && (
1758
+
<MdiReply /> Reply to @{feedviewpostreplyhandle}
1759
+
</div>
1760
+
)}
1595
1761
<div
1596
1762
style={{
1597
-
display: "flex",
1598
-
borderRadius: 12,
1599
-
paddingBottom: 2,
1600
-
fontSize: 14,
1601
-
justifyContent: "flex-start",
1602
-
//color: theme.textSecondary,
1603
-
gap: 4,
1604
-
alignItems: "center",
1605
-
//marginLeft: 36,
1606
-
height: !(expanded || isQuote) && !!feedviewpostreplyhandle ? "1rem" : 0,
1607
-
opacity: !(expanded || isQuote) && !!feedviewpostreplyhandle ? 1 : 0,
1763
+
fontSize: 16,
1764
+
marginBottom: !post.embed /*|| depth > 0*/ ? 0 : 8,
1765
+
whiteSpace: "pre-wrap",
1766
+
textAlign: "left",
1767
+
overflowWrap: "anywhere",
1768
+
wordBreak: "break-word",
1769
+
//color: theme.text,
1608
1770
}}
1609
-
className="text-gray-500 dark:text-gray-400"
1771
+
className="text-gray-900 dark:text-gray-100"
1610
1772
>
1611
-
<MdiReply /> Reply to {feedviewpostreplyhandle}
1773
+
{fedi ? (
1774
+
<>
1775
+
<span
1776
+
className="dangerousFediContent"
1777
+
dangerouslySetInnerHTML={{
1778
+
__html: DOMPurify.sanitize(fedi),
1779
+
}}
1780
+
/>
1781
+
</>
1782
+
) : (
1783
+
<>
1784
+
{renderTextWithFacets({
1785
+
text: (post.record as { text?: string }).text ?? "",
1786
+
facets: (post.record.facets as Facet[]) ?? [],
1787
+
navigate: navigate,
1788
+
})}
1789
+
</>
1790
+
)}
1612
1791
</div>
1613
-
)}
1614
-
<div
1615
-
style={{
1616
-
fontSize: 16,
1617
-
marginBottom: (!post.embed && !expanded) ? 0 : 8,
1618
-
whiteSpace: "pre-wrap",
1619
-
textAlign: "left",
1620
-
overflowWrap: "anywhere",
1621
-
wordBreak: "break-word",
1622
-
//color: theme.text,
1623
-
}}
1624
-
className="text-gray-900 dark:text-gray-100"
1625
-
>
1626
-
{renderTextWithFacets(
1627
-
(post.record as { text?: string }).text ?? "",
1628
-
(post.record.facets as Facet[]) ?? [],
1792
+
{post.embed && depth < 1 ? (
1793
+
<PostEmbeds
1794
+
embed={post.embed}
1795
+
//moderation={moderation}
1796
+
viewContext={PostEmbedViewContext.Feed}
1797
+
salt={salt}
1798
+
navigate={navigate}
1799
+
postid={{ did: post.author.did, rkey: parsed.rkey }}
1800
+
nopics={nopics}
1801
+
lightboxCallback={lightboxCallback}
1802
+
/>
1803
+
) : null}
1804
+
{post.embed && depth > 0 && (
1805
+
/* pretty bad hack imo. its trying to sync up with how the embed shim doesnt
1806
+
hydrate embeds this deep but the connection here is implicit
1807
+
todo: idk make this a real part of the embed shim so its not implicit */
1808
+
<>
1809
+
<div className="border-gray-300 dark:border-gray-800 p-3 rounded-xl border italic text-gray-400 text-[14px]">
1810
+
(there is an embed here thats too deep to render)
1811
+
</div>
1812
+
</>
1629
1813
)}
1630
-
{}
1631
-
</div>
1632
-
{post.embed ? (
1633
-
<PostEmbeds
1634
-
embed={post.embed}
1635
-
//moderation={moderation}
1636
-
viewContext={PostEmbedViewContext.Feed}
1637
-
salt={salt}
1638
-
navigate={navigate}
1639
-
/>
1640
-
) : null}
1641
-
<div style={{ paddingTop: post.embed ? 4 : 0 }}>
1642
-
<>
1643
-
{expanded && (
1814
+
<div style={{ paddingTop: post.embed && depth < 1 ? 4 : 0 }}>
1815
+
<>
1816
+
{expanded && (
1817
+
<div
1818
+
style={{
1819
+
overflow: "hidden",
1820
+
//color: theme.textSecondary,
1821
+
fontSize: 14,
1822
+
display: "flex",
1823
+
borderBottomStyle: "solid",
1824
+
//borderBottomColor: theme.border,
1825
+
//background: "#f00",
1826
+
// height: "1rem",
1827
+
paddingTop: 4,
1828
+
paddingBottom: 8,
1829
+
borderBottomWidth: 1,
1830
+
marginBottom: 8,
1831
+
}} // important for height animation
1832
+
className="text-gray-500 dark:text-gray-400 border-gray-200 dark:border-gray-800 was7"
1833
+
>
1834
+
{fullDateTimeFormat(post.indexedAt)}
1835
+
</div>
1836
+
)}
1837
+
</>
1838
+
{!isQuote && (
1644
1839
<div
1645
1840
style={{
1646
-
overflow: "hidden",
1647
-
//color: theme.textSecondary,
1648
-
fontSize: 14,
1649
1841
display: "flex",
1650
-
borderBottomStyle: "solid",
1651
-
//borderBottomColor: theme.border,
1652
-
//background: "#f00",
1653
-
// height: "1rem",
1654
-
paddingTop: 4,
1655
-
paddingBottom: 8,
1656
-
borderBottomWidth: 1,
1657
-
marginBottom: 8,
1658
-
}} // important for height animation
1659
-
className="text-gray-500 dark:text-gray-400 border-gray-200 dark:border-gray-700"
1660
-
>
1661
-
{fullDateTimeFormat(post.indexedAt)}
1662
-
</div>
1663
-
)}
1664
-
</>
1665
-
{!isQuote && (
1666
-
<div
1667
-
style={{
1668
-
display: "flex",
1669
-
gap: 32,
1670
-
paddingTop: 8,
1671
-
//color: theme.textSecondary,
1672
-
fontSize: 15,
1673
-
justifyContent: "space-between",
1674
-
//background: "#0f0",
1675
-
}}
1676
-
className="text-gray-500 dark:text-gray-400"
1677
-
>
1678
-
<span style={btnstyle}>
1679
-
<MdiCommentOutline />
1680
-
{post.replyCount}
1681
-
</span>
1682
-
<HitSlopButton
1683
-
onClick={() => {
1684
-
repostOrUnrepostPost();
1842
+
gap: 32,
1843
+
paddingTop: 8,
1844
+
//color: theme.textSecondary,
1845
+
fontSize: 15,
1846
+
justifyContent: "space-between",
1847
+
//background: "#0f0",
1685
1848
}}
1686
-
style={{
1687
-
...btnstyle,
1688
-
...(hasRetweeted ? { color: "#5CEFAA" } : {}),
1689
-
}}
1849
+
className="text-gray-500 dark:text-gray-400"
1690
1850
>
1691
-
{hasRetweeted ? <MdiRepeatGreen /> : <MdiRepeat />}
1692
-
{(post.repostCount || 0) + (hasRetweeted ? 1 : 0)}
1693
-
</HitSlopButton>
1694
-
<HitSlopButton
1695
-
onClick={() => {
1696
-
likeOrUnlikePost();
1697
-
}}
1698
-
style={{
1699
-
...btnstyle,
1700
-
...(hasLiked ? { color: "#EC4899" } : {}),
1701
-
}}
1702
-
>
1703
-
{hasLiked ? <MdiCardsHeart /> : <MdiCardsHeartOutline />}
1704
-
{(post.likeCount || 0) + (hasLiked ? 1 : 0)}
1705
-
</HitSlopButton>
1706
-
<div style={{ display: "flex", gap: 8 }}>
1851
+
<HitSlopButton
1852
+
onClick={() => {
1853
+
setComposerPost({ kind: "reply", parent: post.uri });
1854
+
}}
1855
+
style={{
1856
+
...btnstyle,
1857
+
}}
1858
+
>
1859
+
<MdiCommentOutline />
1860
+
{post.replyCount}
1861
+
</HitSlopButton>
1862
+
<DropdownMenu.Root modal={false}>
1863
+
<DropdownMenu.Trigger asChild>
1864
+
<div
1865
+
style={{
1866
+
...btnstyle,
1867
+
...(hasRetweeted ? { color: "#5CEFAA" } : {}),
1868
+
}}
1869
+
aria-label="Repost or quote post"
1870
+
>
1871
+
{hasRetweeted ? <MdiRepeatGreen /> : <MdiRepeat />}
1872
+
{post.repostCount ?? 0}
1873
+
</div>
1874
+
</DropdownMenu.Trigger>
1875
+
1876
+
<DropdownMenu.Portal>
1877
+
<DropdownMenu.Content
1878
+
align="start"
1879
+
sideOffset={5}
1880
+
className="bg-white dark:bg-gray-800 rounded-lg shadow-xl border border-gray-200 dark:border-gray-700 w-32 z-50 overflow-hidden"
1881
+
>
1882
+
<DropdownMenu.Item
1883
+
onSelect={repostOrUnrepostPost}
1884
+
className="px-3 py-2 text-sm flex items-center gap-2 cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none focus:bg-gray-100 dark:focus:bg-gray-700"
1885
+
>
1886
+
<MdiRepeat
1887
+
className={hasRetweeted ? "text-green-400" : ""}
1888
+
/>
1889
+
<span>{hasRetweeted ? "Undo Repost" : "Repost"}</span>
1890
+
</DropdownMenu.Item>
1891
+
1892
+
<DropdownMenu.Item
1893
+
onSelect={() => {
1894
+
setComposerPost({
1895
+
kind: "quote",
1896
+
subject: post.uri,
1897
+
});
1898
+
}}
1899
+
className="px-3 py-2 text-sm flex items-center gap-2 cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none focus:bg-gray-100 dark:focus:bg-gray-700"
1900
+
>
1901
+
{/* You might want a specific quote icon here */}
1902
+
<MdiCommentOutline />
1903
+
<span>Quote</span>
1904
+
</DropdownMenu.Item>
1905
+
</DropdownMenu.Content>
1906
+
</DropdownMenu.Portal>
1907
+
</DropdownMenu.Root>
1707
1908
<HitSlopButton
1708
-
onClick={async (e) => {
1709
-
e.stopPropagation();
1710
-
try {
1711
-
await navigator.clipboard.writeText(
1712
-
"https://bsky.app" +
1713
-
"/profile/" +
1714
-
post.author.handle +
1715
-
"/post/" +
1716
-
post.uri.split("/").pop(),
1717
-
);
1718
-
} catch {}
1909
+
onClick={() => {
1910
+
likeOrUnlikePost();
1719
1911
}}
1720
1912
style={{
1721
1913
...btnstyle,
1914
+
...(hasLiked ? { color: "#EC4899" } : {}),
1722
1915
}}
1723
1916
>
1724
-
<MdiShareVariant />
1917
+
{hasLiked ? <MdiCardsHeart /> : <MdiCardsHeartOutline />}
1918
+
{(post.likeCount || 0) + (hasLiked ? 1 : 0)}
1725
1919
</HitSlopButton>
1726
-
<span style={btnstyle}>
1727
-
<MdiMoreHoriz />
1728
-
</span>
1920
+
<div style={{ display: "flex", gap: 8 }}>
1921
+
<HitSlopButton
1922
+
onClick={async (e) => {
1923
+
e.stopPropagation();
1924
+
try {
1925
+
await navigator.clipboard.writeText(
1926
+
"https://bsky.app" +
1927
+
"/profile/" +
1928
+
post.author.handle +
1929
+
"/post/" +
1930
+
post.uri.split("/").pop()
1931
+
);
1932
+
} catch (_e) {
1933
+
// idk
1934
+
}
1935
+
}}
1936
+
style={{
1937
+
...btnstyle,
1938
+
}}
1939
+
>
1940
+
<MdiShareVariant />
1941
+
</HitSlopButton>
1942
+
<span style={btnstyle}>
1943
+
<MdiMoreHoriz />
1944
+
</span>
1945
+
</div>
1729
1946
</div>
1730
-
</div>
1731
-
)}
1947
+
)}
1948
+
</div>
1949
+
<div
1950
+
style={{
1951
+
//height: bottomReplyLine ? 16 : 0
1952
+
height: isQuote ? 12 : 16,
1953
+
}}
1954
+
/>
1732
1955
</div>
1733
-
<div
1734
-
style={{
1735
-
//height: bottomReplyLine ? 16 : 0
1736
-
height: isQuote ? 12 : 16,
1737
-
}}
1738
-
/>
1739
1956
</div>
1740
1957
</div>
1741
1958
</div>
···
1827
2044
viewContext,
1828
2045
salt,
1829
2046
navigate,
2047
+
postid,
2048
+
nopics,
2049
+
lightboxCallback,
1830
2050
}: {
1831
2051
embed?: Embed;
1832
2052
moderation?: ModerationDecision;
···
1834
2054
allowNestedQuotes?: boolean;
1835
2055
viewContext?: PostEmbedViewContext;
1836
2056
salt: string;
1837
-
navigate: ({}: any) => void;
2057
+
navigate: (_: any) => void;
2058
+
postid?: { did: string; rkey: string };
2059
+
nopics?: boolean;
2060
+
lightboxCallback?: (d: LightboxProps) => void;
1838
2061
}) {
1839
-
const [lightboxIndex, setLightboxIndex] = useState<number | null>(null);
2062
+
//const [lightboxIndex, setLightboxIndex] = useState<number | null>(null);
2063
+
function setLightboxIndex(number: number) {
2064
+
navigate({
2065
+
to: "/profile/$did/post/$rkey/image/$i",
2066
+
params: {
2067
+
did: postid?.did,
2068
+
rkey: postid?.rkey,
2069
+
i: number.toString(),
2070
+
},
2071
+
});
2072
+
}
1840
2073
if (
1841
2074
AppBskyEmbedRecordWithMedia.isView(embed) &&
1842
2075
AppBskyEmbedRecord.isViewRecord(embed.record.record) &&
···
1870
2103
viewContext={viewContext}
1871
2104
salt={salt}
1872
2105
navigate={navigate}
2106
+
postid={postid}
2107
+
nopics={nopics}
2108
+
lightboxCallback={lightboxCallback}
1873
2109
/>
1874
2110
{/* padding empty div of 8px height */}
1875
2111
<div style={{ height: 12 }} />
···
1883
2119
//boxShadow: theme.cardShadow,
1884
2120
overflow: "hidden",
1885
2121
}}
1886
-
className="shadow border border-gray-200 dark:border-gray-700"
2122
+
className="shadow border border-gray-200 dark:border-gray-800 was7"
1887
2123
>
1888
2124
<UniversalPostRenderer
1889
2125
post={post}
···
1891
2127
salt={salt}
1892
2128
onPostClick={(e) => {
1893
2129
e.stopPropagation();
1894
-
const parsed = parseAtUri(post.uri);
2130
+
const parsed = new AtUri(post.uri); //parseAtUri(post.uri);
1895
2131
if (parsed) {
1896
2132
navigate({
1897
2133
to: "/profile/$did/post/$rkey",
1898
-
params: { did: parsed.did, rkey: parsed.rkey },
2134
+
params: { did: parsed.host, rkey: parsed.rkey },
1899
2135
});
1900
2136
}
1901
2137
}}
2138
+
depth={1}
1902
2139
/>
1903
2140
</div>
1904
2141
{/* <QuotePostRenderer
···
1999
2236
//boxShadow: theme.cardShadow,
2000
2237
overflow: "hidden",
2001
2238
}}
2002
-
className="shadow border border-gray-200 dark:border-gray-700"
2239
+
className="shadow border border-gray-200 dark:border-gray-800 was7"
2003
2240
>
2004
2241
<UniversalPostRenderer
2005
2242
post={post}
···
2007
2244
salt={salt}
2008
2245
onPostClick={(e) => {
2009
2246
e.stopPropagation();
2010
-
const parsed = parseAtUri(post.uri);
2247
+
const parsed = new AtUri(post.uri); //parseAtUri(post.uri);
2011
2248
if (parsed) {
2012
2249
navigate({
2013
2250
to: "/profile/$did/post/$rkey",
2014
-
params: { did: parsed.did, rkey: parsed.rkey },
2251
+
params: { did: parsed.host, rkey: parsed.rkey },
2015
2252
});
2016
2253
}
2017
2254
}}
2255
+
depth={1}
2018
2256
/>
2019
2257
</div>
2020
2258
);
···
2042
2280
src: img.fullsize,
2043
2281
alt: img.alt,
2044
2282
}));
2283
+
console.log("rendering images");
2284
+
if (lightboxCallback) {
2285
+
lightboxCallback({ images: lightboxImages });
2286
+
console.log("rendering images");
2287
+
}
2045
2288
2289
+
if (nopics) return;
2046
2290
2047
2291
if (images.length > 0) {
2048
2292
// const items = embed.images.map(img => ({
···
2072
2316
//border: `1px solid ${theme.border}`,
2073
2317
overflow: "hidden",
2074
2318
}}
2075
-
className="border border-gray-200 dark:border-gray-700 bg-gray-200 dark:bg-gray-900"
2319
+
className="border border-gray-200 dark:border-gray-800 was7 bg-gray-200 dark:bg-gray-900"
2076
2320
>
2077
-
{lightboxIndex !== null && (
2078
-
<Lightbox
2079
-
images={lightboxImages}
2080
-
index={lightboxIndex}
2081
-
onClose={() => setLightboxIndex(null)}
2082
-
onNavigate={(newIndex) => setLightboxIndex(newIndex)}
2083
-
/>
2084
-
)}
2321
+
{/* {lightboxIndex !== null && (
2322
+
<Lightbox
2323
+
images={lightboxImages}
2324
+
index={lightboxIndex}
2325
+
onClose={() => setLightboxIndex(null)}
2326
+
onNavigate={(newIndex) => setLightboxIndex(newIndex)}
2327
+
post={postid}
2328
+
/>
2329
+
)} */}
2085
2330
<img
2086
2331
src={image.fullsize}
2087
2332
alt={image.alt}
···
2090
2335
height: "100%",
2091
2336
objectFit: "contain", // letterbox or scale to fit
2092
2337
}}
2093
-
onClick={(e) => {e.stopPropagation();setLightboxIndex(0)}}
2338
+
onClick={(e) => {
2339
+
e.stopPropagation();
2340
+
setLightboxIndex(0);
2341
+
}}
2094
2342
/>
2095
2343
</div>
2096
2344
</div>
···
2109
2357
overflow: "hidden",
2110
2358
//border: `1px solid ${theme.border}`,
2111
2359
}}
2112
-
className="border border-gray-200 dark:border-gray-700"
2360
+
className="border border-gray-200 dark:border-gray-800 was7"
2113
2361
>
2114
-
{lightboxIndex !== null && (
2362
+
{/* {lightboxIndex !== null && (
2115
2363
<Lightbox
2116
2364
images={lightboxImages}
2117
2365
index={lightboxIndex}
2118
2366
onClose={() => setLightboxIndex(null)}
2119
2367
onNavigate={(newIndex) => setLightboxIndex(newIndex)}
2368
+
post={postid}
2120
2369
/>
2121
-
)}
2370
+
)} */}
2122
2371
{images.map((img, i) => (
2123
2372
<div
2124
2373
key={i}
···
2133
2382
objectFit: "cover",
2134
2383
borderRadius: i === 0 ? "12px 0 0 12px" : "0 12px 12px 0",
2135
2384
}}
2136
-
onClick={(e) => {e.stopPropagation();setLightboxIndex(i)}}
2385
+
onClick={(e) => {
2386
+
e.stopPropagation();
2387
+
setLightboxIndex(i);
2388
+
}}
2137
2389
/>
2138
2390
</div>
2139
2391
))}
···
2155
2407
//border: `1px solid ${theme.border}`,
2156
2408
// height: 240, // fixed height for cropping
2157
2409
}}
2158
-
className="border border-gray-200 dark:border-gray-700"
2410
+
className="border border-gray-200 dark:border-gray-800 was7"
2159
2411
>
2160
-
{lightboxIndex !== null && (
2412
+
{/* {lightboxIndex !== null && (
2161
2413
<Lightbox
2162
2414
images={lightboxImages}
2163
2415
index={lightboxIndex}
2164
2416
onClose={() => setLightboxIndex(null)}
2165
2417
onNavigate={(newIndex) => setLightboxIndex(newIndex)}
2418
+
post={postid}
2166
2419
/>
2167
-
)}
2420
+
)} */}
2168
2421
{/* Left: 1:1 */}
2169
2422
<div
2170
2423
style={{ flex: 1, aspectRatio: "1 / 1", position: "relative" }}
···
2178
2431
objectFit: "cover",
2179
2432
borderRadius: "12px 0 0 12px",
2180
2433
}}
2181
-
onClick={(e) => {e.stopPropagation();setLightboxIndex(0)}}
2434
+
onClick={(e) => {
2435
+
e.stopPropagation();
2436
+
setLightboxIndex(0);
2437
+
}}
2182
2438
/>
2183
2439
</div>
2184
2440
{/* Right: two stacked 2:1 */}
···
2208
2464
objectFit: "cover",
2209
2465
borderRadius: i === 1 ? "0 12px 0 0" : "0 0 12px 0",
2210
2466
}}
2211
-
onClick={(e) => {e.stopPropagation();setLightboxIndex(i+1)}}
2467
+
onClick={(e) => {
2468
+
e.stopPropagation();
2469
+
setLightboxIndex(i + 1);
2470
+
}}
2212
2471
/>
2213
2472
</div>
2214
2473
))}
···
2233
2492
//border: `1px solid ${theme.border}`,
2234
2493
//aspectRatio: "3 / 2", // overall grid aspect
2235
2494
}}
2236
-
className="border border-gray-200 dark:border-gray-700"
2495
+
className="border border-gray-200 dark:border-gray-800 was7"
2237
2496
>
2238
-
{lightboxIndex !== null && (
2497
+
{/* {lightboxIndex !== null && (
2239
2498
<Lightbox
2240
2499
images={lightboxImages}
2241
2500
index={lightboxIndex}
2242
2501
onClose={() => setLightboxIndex(null)}
2243
2502
onNavigate={(newIndex) => setLightboxIndex(newIndex)}
2503
+
post={postid}
2244
2504
/>
2245
-
)}
2505
+
)} */}
2246
2506
{images.map((img, i) => (
2247
2507
<div
2248
2508
key={i}
···
2269
2529
? "0 0 0 12px"
2270
2530
: "0 0 12px 0",
2271
2531
}}
2272
-
onClick={(e) => {e.stopPropagation();setLightboxIndex(i)}}
2532
+
onClick={(e) => {
2533
+
e.stopPropagation();
2534
+
setLightboxIndex(i);
2535
+
}}
2273
2536
/>
2274
2537
</div>
2275
2538
))}
···
2330
2593
return <div />;
2331
2594
}
2332
2595
2333
-
import { createPortal } from "react-dom";
2334
-
type LightboxProps = {
2335
-
images: { src: string; alt?: string }[];
2336
-
index: number;
2337
-
onClose: () => void;
2338
-
onNavigate?: (newIndex: number) => void;
2339
-
};
2340
-
export function Lightbox({ images, index, onClose, onNavigate }: LightboxProps) {
2341
-
const image = images[index];
2342
-
2343
-
useEffect(() => {
2344
-
function handleKey(e: KeyboardEvent) {
2345
-
if (e.key === "Escape") onClose();
2346
-
if (e.key === "ArrowRight" && onNavigate) onNavigate((index + 1) % images.length);
2347
-
if (e.key === "ArrowLeft" && onNavigate) onNavigate((index - 1 + images.length) % images.length);
2348
-
}
2349
-
window.addEventListener("keydown", handleKey);
2350
-
return () => window.removeEventListener("keydown", handleKey);
2351
-
}, [index, images.length, onClose, onNavigate]);
2352
-
2353
-
return createPortal(
2354
-
<div
2355
-
className="fixed inset-0 z-50 flex items-center justify-center bg-black/80"
2356
-
onClick={(e)=>{e.stopPropagation();onClose()}}
2357
-
>
2358
-
<img
2359
-
src={image.src}
2360
-
alt={image.alt}
2361
-
className="max-h-[90vh] max-w-[90vw] object-contain rounded-lg shadow-lg"
2362
-
onClick={(e) => e.stopPropagation()}
2363
-
/>
2364
-
2365
-
{images.length > 1 && (
2366
-
<>
2367
-
<button
2368
-
onClick={(e) => {
2369
-
e.stopPropagation();
2370
-
onNavigate?.((index - 1 + images.length) % images.length);
2371
-
}}
2372
-
className="absolute left-4 top-1/2 -translate-y-1/2 text-white text-4xl h-8 w-8 rounded-full bg-gray-900 flex items-center justify-center"
2373
-
>
2374
-
<svg xmlns="http://www.w3.org/2000/svg" width={28} height={28} viewBox="0 0 24 24"><g fill="none" fillRule="evenodd"><path d="M24 0v24H0V0zM12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.019-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"></path><path fill="currentColor" d="M8.293 12.707a1 1 0 0 1 0-1.414l5.657-5.657a1 1 0 1 1 1.414 1.414L10.414 12l4.95 4.95a1 1 0 0 1-1.414 1.414z"></path></g></svg>
2375
-
</button>
2376
-
<button
2377
-
onClick={(e) => {
2378
-
e.stopPropagation();
2379
-
onNavigate?.((index + 1) % images.length);
2380
-
}}
2381
-
className="absolute right-4 top-1/2 -translate-y-1/2 text-white text-4xl h-8 w-8 rounded-full bg-gray-900 flex items-center justify-center"
2382
-
>
2383
-
<svg xmlns="http://www.w3.org/2000/svg" width={28} height={28} viewBox="0 0 24 24"><g fill="none" fillRule="evenodd"><path d="M24 0v24H0V0zM12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.019-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"></path><path fill="currentColor" d="M15.707 11.293a1 1 0 0 1 0 1.414l-5.657 5.657a1 1 0 1 1-1.414-1.414l4.95-4.95l-4.95-4.95a1 1 0 0 1 1.414-1.414z"></path></g></svg>
2384
-
</button>
2385
-
</>
2386
-
)}
2387
-
</div>,
2388
-
document.body
2389
-
);
2390
-
}
2391
-
2392
2596
function getDomain(url: string) {
2393
2597
try {
2394
2598
const { hostname } = new URL(url);
···
2419
2623
for (let i = 0; i < bytes.length; i++) {
2420
2624
map[byteIndex++] = charIndex;
2421
2625
}
2422
-
charIndex++;
2626
+
charIndex += char.length;
2423
2627
}
2424
2628
2425
2629
return map;
···
2428
2632
function facetByteRangeToCharRange(
2429
2633
byteStart: number,
2430
2634
byteEnd: number,
2431
-
byteToCharMap: number[],
2635
+
byteToCharMap: number[]
2432
2636
): [number, number] {
2433
2637
return [
2434
2638
byteToCharMap[byteStart] ?? 0,
···
2448
2652
const [start, end] = facetByteRangeToCharRange(
2449
2653
f.index.byteStart,
2450
2654
f.index.byteEnd,
2451
-
map,
2655
+
map
2452
2656
);
2453
2657
return { start, end, feature: f.features[0] };
2454
2658
});
2455
2659
}
2456
-
function renderTextWithFacets(text: string, facets: Facet[]) {
2660
+
export function renderTextWithFacets({
2661
+
text,
2662
+
facets,
2663
+
navigate,
2664
+
}: {
2665
+
text: string;
2666
+
facets: Facet[];
2667
+
navigate: (_: any) => void;
2668
+
}) {
2457
2669
const ranges = extractFacetRanges(text, facets).sort(
2458
-
(a: any, b: any) => a.start - b.start,
2670
+
(a: any, b: any) => a.start - b.start
2459
2671
);
2460
2672
2461
2673
const result: React.ReactNode[] = [];
···
2467
2679
}
2468
2680
2469
2681
const fragment = text.slice(start, end);
2470
-
// @ts-ignore
2682
+
// @ts-expect-error i didnt bother with the correct types here sorry. bsky api types are cursed
2471
2683
if (feature.$type === "app.bsky.richtext.facet#link" && feature.uri) {
2472
2684
result.push(
2473
2685
<a
2474
-
// @ts-ignore
2686
+
// @ts-expect-error i didnt bother with the correct types here sorry. bsky api types are cursed
2475
2687
href={feature.uri}
2476
2688
key={start}
2477
2689
className="link"
···
2487
2699
}}
2488
2700
>
2489
2701
{fragment}
2490
-
</a>,
2702
+
</a>
2491
2703
);
2492
2704
} else if (
2493
2705
feature.$type === "app.bsky.richtext.facet#mention" &&
2494
-
// @ts-ignore
2706
+
// @ts-expect-error i didnt bother with the correct types here sorry. bsky api types are cursed
2495
2707
feature.did
2496
2708
) {
2497
2709
result.push(
2498
2710
<span
2499
2711
key={start}
2500
2712
style={{ color: "rgb(29, 122, 242)" }}
2713
+
className=" cursor-pointer"
2501
2714
onClick={(e) => {
2502
2715
e.stopPropagation();
2716
+
navigate({
2717
+
to: "/profile/$did",
2718
+
// @ts-expect-error i didnt bother with the correct types here sorry. bsky api types are cursed
2719
+
params: { did: feature.did },
2720
+
});
2503
2721
}}
2504
2722
>
2505
2723
{fragment}
2506
-
</span>,
2724
+
</span>
2507
2725
);
2508
2726
} else if (feature.$type === "app.bsky.richtext.facet#tag") {
2509
2727
result.push(
···
2515
2733
}}
2516
2734
>
2517
2735
{fragment}
2518
-
</span>,
2736
+
</span>
2519
2737
);
2520
2738
} else {
2521
2739
result.push(<span key={start}>{fragment}</span>);
···
2594
2812
rel="noopener noreferrer"
2595
2813
onClick={(e) => {
2596
2814
e.stopPropagation();
2597
-
onOpen;
2815
+
if (onOpen) onOpen();
2598
2816
}}
2599
-
/* @ts-ignore */
2817
+
/* @ts-expect-error css arent typed or something idk fuck you */
2600
2818
style={linkStyle}
2601
2819
className="text-gray-500 dark:text-gray-400"
2602
2820
>
2603
-
{/* @ts-ignore ehiaeih */}
2604
2821
<div
2605
2822
style={containerStyle as React.CSSProperties}
2606
-
className="border border-gray-200 dark:border-gray-700"
2823
+
className="border border-gray-200 dark:border-gray-800 was7"
2607
2824
>
2608
2825
{thumb && (
2609
2826
<div
···
2617
2834
marginBottom: 8,
2618
2835
//borderBottom: `1px solid ${theme.border}`,
2619
2836
}}
2620
-
className="border-b border-gray-200 dark:border-gray-700"
2837
+
className="border-b border-gray-200 dark:border-gray-800 was7"
2621
2838
>
2622
2839
<img
2623
2840
src={thumb}
···
2641
2858
paddingTop: thumb ? 0 : 12,
2642
2859
}}
2643
2860
>
2644
-
{/* @ts-ignore */}
2861
+
{/* @ts-expect-error css */}
2645
2862
<div style={titleStyle} className="text-gray-900 dark:text-gray-100">
2646
2863
{title}
2647
2864
</div>
2648
-
{/* @ts-ignore */}
2649
2865
<div
2650
2866
style={descriptionStyle as React.CSSProperties}
2651
2867
className="text-gray-500 dark:text-gray-400"
···
2708
2924
{
2709
2925
root: null,
2710
2926
threshold: 0.25,
2711
-
},
2927
+
}
2712
2928
);
2713
2929
2714
2930
if (containerRef.current) {
···
2744
2960
borderRadius: 12,
2745
2961
//border: `1px solid ${theme.border}`,
2746
2962
}}
2747
-
className="border border-gray-200 dark:border-gray-700"
2963
+
className="border border-gray-200 dark:border-gray-800 was7"
2748
2964
onClick={async (e) => {
2749
2965
e.stopPropagation();
2750
2966
setPlaying(true);
···
2785
3001
100 / (aspect ? aspect.width / aspect.height : 16 / 9)
2786
3002
}%`, // 16:9 = 56.25%, 4:3 = 75%
2787
3003
}}
2788
-
className="border border-gray-200 dark:border-gray-700"
3004
+
className="border border-gray-200 dark:border-gray-800 was7"
2789
3005
>
2790
3006
<ReactPlayer
2791
3007
src={url}
+59
src/components/radix-m3-rd/Button.tsx
+59
src/components/radix-m3-rd/Button.tsx
···
1
+
import { Slot } from "@radix-ui/react-slot";
2
+
import clsx from "clsx";
3
+
import * as React from "react";
4
+
5
+
export type ButtonVariant = "filled" | "outlined" | "text" | "secondary";
6
+
export type ButtonSize = "sm" | "md" | "lg";
7
+
8
+
const variantClasses: Record<ButtonVariant, string> = {
9
+
filled:
10
+
"bg-gray-300 text-gray-900 hover:bg-gray-400 dark:bg-gray-600 dark:text-white dark:hover:bg-gray-500",
11
+
secondary:
12
+
"bg-gray-300 text-gray-900 hover:bg-gray-400 dark:bg-gray-600 dark:text-white dark:hover:bg-gray-500",
13
+
outlined:
14
+
"border border-gray-800 text-gray-800 hover:bg-gray-100 dark:border-gray-200 dark:text-gray-200 dark:hover:bg-gray-800/10",
15
+
text: "bg-transparent text-gray-800 hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-gray-800/10",
16
+
};
17
+
18
+
const sizeClasses: Record<ButtonSize, string> = {
19
+
sm: "px-3 py-1.5 text-sm",
20
+
md: "px-4 py-2 text-base",
21
+
lg: "px-6 py-3 text-lg",
22
+
};
23
+
24
+
export function Button({
25
+
variant = "filled",
26
+
size = "md",
27
+
asChild = false,
28
+
ref,
29
+
className,
30
+
children,
31
+
...props
32
+
}: {
33
+
variant?: ButtonVariant;
34
+
size?: ButtonSize;
35
+
asChild?: boolean;
36
+
className?: string;
37
+
children?: React.ReactNode;
38
+
ref?: React.Ref<HTMLButtonElement>;
39
+
} & React.ComponentPropsWithoutRef<"button">) {
40
+
const Comp = asChild ? Slot : "button";
41
+
42
+
return (
43
+
<Comp
44
+
ref={ref}
45
+
className={clsx(
46
+
//focus:outline-none focus:ring-1 focus:ring-offset-1 focus:ring-gray-500 dark:focus:ring-gray-300
47
+
"inline-flex items-center justify-center rounded-full transition-colors disabled:opacity-50 disabled:cursor-not-allowed",
48
+
variantClasses[variant],
49
+
sizeClasses[size],
50
+
className
51
+
)}
52
+
{...props}
53
+
>
54
+
{children}
55
+
</Comp>
56
+
);
57
+
}
58
+
59
+
Button.displayName = "Button";
+24
src/components/shrinkpadding.tsx
+24
src/components/shrinkpadding.tsx
···
1
+
import { useEffect, useState } from "react";
2
+
3
+
export default function ShrinkingBox() {
4
+
const [size, setSize] = useState(2000);
5
+
6
+
useEffect(() => {
7
+
const interval = setInterval(() => {
8
+
setSize(prev => Math.max(prev - 125, 0));
9
+
}, 250);
10
+
11
+
return () => clearInterval(interval);
12
+
}, []);
13
+
14
+
return (
15
+
<div
16
+
style={{
17
+
//width: `${size}px`,
18
+
height: `${size}px`,
19
+
//backgroundColor: "skyblue",
20
+
transition: "all 0.5s ease",
21
+
}}
22
+
/>
23
+
);
24
+
}
+77
-8
src/main.tsx
+77
-8
src/main.tsx
···
1
-
import { StrictMode } from "react";
1
+
import "~/styles/app.css";
2
+
3
+
import { createSyncStoragePersister } from "@tanstack/query-sync-storage-persister";
4
+
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
5
+
import { persistQueryClient } from "@tanstack/react-query-persist-client";
6
+
import { createRouter, RouterProvider } from "@tanstack/react-router";
7
+
import { useSetAtom } from "jotai";
8
+
import { useEffect } from "react";
9
+
//import { StrictMode } from "react";
2
10
import ReactDOM from "react-dom/client";
3
-
import { RouterProvider, createRouter } from "@tanstack/react-router";
4
11
12
+
import reportWebVitals from "./reportWebVitals.ts";
5
13
// Import the generated route tree
6
14
import { routeTree } from "./routeTree.gen";
15
+
import { isAtTopAtom } from "./utils/atoms.ts";
7
16
8
-
import "~/styles/app.css";
9
-
import reportWebVitals from "./reportWebVitals.ts";
17
+
//initAtomToCssVar(hueAtom, "--tw-gray-hue")
18
+
19
+
const queryClient = new QueryClient({
20
+
defaultOptions: {
21
+
queries: {
22
+
gcTime: 1000 * 60 * 60 * 24 * 24, // 24 days
23
+
},
24
+
},
25
+
});
26
+
const localStoragePersister = createSyncStoragePersister({
27
+
storage: window.localStorage,
28
+
});
29
+
30
+
persistQueryClient({
31
+
queryClient,
32
+
persister: localStoragePersister,
33
+
});
10
34
11
35
// Create a new router instance
12
36
const router = createRouter({
13
37
routeTree,
14
-
context: {},
38
+
context: { queryClient },
15
39
defaultPreload: "intent",
16
40
scrollRestoration: true,
17
41
defaultStructuralSharing: true,
···
31
55
const root = ReactDOM.createRoot(rootElement);
32
56
root.render(
33
57
// double queries annoys me
34
-
<StrictMode>
58
+
// <StrictMode>
59
+
<QueryClientProvider client={queryClient}>
60
+
<ScrollTopWatcher />
35
61
<RouterProvider router={router} />
36
-
</StrictMode>
62
+
</QueryClientProvider>
63
+
// </StrictMode>
37
64
);
38
65
}
39
66
40
67
// If you want to start measuring performance in your app, pass a function
41
-
// to log results (for example: reportWebVitals(console.log))
68
+
// to log results (for example: reportWebVitals(// /*mass comment*/ console.log))
42
69
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
43
70
reportWebVitals();
71
+
72
+
export default function ScrollTopWatcher() {
73
+
const setIsAtTop = useSetAtom(isAtTopAtom);
74
+
useEffect(() => {
75
+
const meta = document.querySelector('meta[name="theme-color"]');
76
+
let lastAtTop = window.scrollY === 0;
77
+
let timeoutId: number | undefined;
78
+
79
+
const setVars = (atTop: boolean) => {
80
+
const root = document.documentElement;
81
+
root.style.setProperty("--is-top", atTop ? "1" : "0");
82
+
83
+
const bg = getComputedStyle(root).getPropertyValue("--header-bg").trim();
84
+
if (meta && bg) meta.setAttribute("content", bg);
85
+
setIsAtTop(atTop);
86
+
};
87
+
88
+
const check = () => {
89
+
const atTop = window.scrollY === 0;
90
+
if (atTop !== lastAtTop) {
91
+
lastAtTop = atTop;
92
+
setVars(atTop);
93
+
}
94
+
};
95
+
96
+
const handleScroll = () => {
97
+
if (timeoutId) clearTimeout(timeoutId);
98
+
timeoutId = window.setTimeout(check, 2);
99
+
};
100
+
101
+
// initialize
102
+
setVars(lastAtTop);
103
+
window.addEventListener("scroll", handleScroll, { passive: true });
104
+
105
+
return () => {
106
+
window.removeEventListener("scroll", handleScroll);
107
+
if (timeoutId) clearTimeout(timeoutId);
108
+
};
109
+
}, []);
110
+
111
+
return null;
112
+
}
-149
src/providers/PassAuthProvider.tsx
-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
-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
+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
+57
-5
src/routeTree.gen.ts
···
15
15
import { Route as FeedsRouteImport } from './routes/feeds'
16
16
import { Route as PathlessLayoutRouteImport } from './routes/_pathlessLayout'
17
17
import { Route as IndexRouteImport } from './routes/index'
18
+
import { Route as CallbackIndexRouteImport } from './routes/callback/index'
18
19
import { Route as PathlessLayoutNestedLayoutRouteImport } from './routes/_pathlessLayout/_nested-layout'
19
20
import { Route as ProfileDidIndexRouteImport } from './routes/profile.$did/index'
20
21
import { Route as PathlessLayoutNestedLayoutRouteBRouteImport } from './routes/_pathlessLayout/_nested-layout/route-b'
21
22
import { Route as PathlessLayoutNestedLayoutRouteARouteImport } from './routes/_pathlessLayout/_nested-layout/route-a'
22
23
import { Route as ProfileDidPostRkeyRouteImport } from './routes/profile.$did/post.$rkey'
24
+
import { Route as ProfileDidPostRkeyImageIRouteImport } from './routes/profile.$did/post.$rkey.image.$i'
23
25
24
26
const SettingsRoute = SettingsRouteImport.update({
25
27
id: '/settings',
···
50
52
path: '/',
51
53
getParentRoute: () => rootRouteImport,
52
54
} as any)
55
+
const CallbackIndexRoute = CallbackIndexRouteImport.update({
56
+
id: '/callback/',
57
+
path: '/callback/',
58
+
getParentRoute: () => rootRouteImport,
59
+
} as any)
53
60
const PathlessLayoutNestedLayoutRoute =
54
61
PathlessLayoutNestedLayoutRouteImport.update({
55
62
id: '/_nested-layout',
···
77
84
path: '/profile/$did/post/$rkey',
78
85
getParentRoute: () => rootRouteImport,
79
86
} as any)
87
+
const ProfileDidPostRkeyImageIRoute =
88
+
ProfileDidPostRkeyImageIRouteImport.update({
89
+
id: '/image/$i',
90
+
path: '/image/$i',
91
+
getParentRoute: () => ProfileDidPostRkeyRoute,
92
+
} as any)
80
93
81
94
export interface FileRoutesByFullPath {
82
95
'/': typeof IndexRoute
···
84
97
'/notifications': typeof NotificationsRoute
85
98
'/search': typeof SearchRoute
86
99
'/settings': typeof SettingsRoute
100
+
'/callback': typeof CallbackIndexRoute
87
101
'/route-a': typeof PathlessLayoutNestedLayoutRouteARoute
88
102
'/route-b': typeof PathlessLayoutNestedLayoutRouteBRoute
89
103
'/profile/$did': typeof ProfileDidIndexRoute
90
-
'/profile/$did/post/$rkey': typeof ProfileDidPostRkeyRoute
104
+
'/profile/$did/post/$rkey': typeof ProfileDidPostRkeyRouteWithChildren
105
+
'/profile/$did/post/$rkey/image/$i': typeof ProfileDidPostRkeyImageIRoute
91
106
}
92
107
export interface FileRoutesByTo {
93
108
'/': typeof IndexRoute
···
95
110
'/notifications': typeof NotificationsRoute
96
111
'/search': typeof SearchRoute
97
112
'/settings': typeof SettingsRoute
113
+
'/callback': typeof CallbackIndexRoute
98
114
'/route-a': typeof PathlessLayoutNestedLayoutRouteARoute
99
115
'/route-b': typeof PathlessLayoutNestedLayoutRouteBRoute
100
116
'/profile/$did': typeof ProfileDidIndexRoute
101
-
'/profile/$did/post/$rkey': typeof ProfileDidPostRkeyRoute
117
+
'/profile/$did/post/$rkey': typeof ProfileDidPostRkeyRouteWithChildren
118
+
'/profile/$did/post/$rkey/image/$i': typeof ProfileDidPostRkeyImageIRoute
102
119
}
103
120
export interface FileRoutesById {
104
121
__root__: typeof rootRouteImport
···
109
126
'/search': typeof SearchRoute
110
127
'/settings': typeof SettingsRoute
111
128
'/_pathlessLayout/_nested-layout': typeof PathlessLayoutNestedLayoutRouteWithChildren
129
+
'/callback/': typeof CallbackIndexRoute
112
130
'/_pathlessLayout/_nested-layout/route-a': typeof PathlessLayoutNestedLayoutRouteARoute
113
131
'/_pathlessLayout/_nested-layout/route-b': typeof PathlessLayoutNestedLayoutRouteBRoute
114
132
'/profile/$did/': typeof ProfileDidIndexRoute
115
-
'/profile/$did/post/$rkey': typeof ProfileDidPostRkeyRoute
133
+
'/profile/$did/post/$rkey': typeof ProfileDidPostRkeyRouteWithChildren
134
+
'/profile/$did/post/$rkey/image/$i': typeof ProfileDidPostRkeyImageIRoute
116
135
}
117
136
export interface FileRouteTypes {
118
137
fileRoutesByFullPath: FileRoutesByFullPath
···
122
141
| '/notifications'
123
142
| '/search'
124
143
| '/settings'
144
+
| '/callback'
125
145
| '/route-a'
126
146
| '/route-b'
127
147
| '/profile/$did'
128
148
| '/profile/$did/post/$rkey'
149
+
| '/profile/$did/post/$rkey/image/$i'
129
150
fileRoutesByTo: FileRoutesByTo
130
151
to:
131
152
| '/'
···
133
154
| '/notifications'
134
155
| '/search'
135
156
| '/settings'
157
+
| '/callback'
136
158
| '/route-a'
137
159
| '/route-b'
138
160
| '/profile/$did'
139
161
| '/profile/$did/post/$rkey'
162
+
| '/profile/$did/post/$rkey/image/$i'
140
163
id:
141
164
| '__root__'
142
165
| '/'
···
146
169
| '/search'
147
170
| '/settings'
148
171
| '/_pathlessLayout/_nested-layout'
172
+
| '/callback/'
149
173
| '/_pathlessLayout/_nested-layout/route-a'
150
174
| '/_pathlessLayout/_nested-layout/route-b'
151
175
| '/profile/$did/'
152
176
| '/profile/$did/post/$rkey'
177
+
| '/profile/$did/post/$rkey/image/$i'
153
178
fileRoutesById: FileRoutesById
154
179
}
155
180
export interface RootRouteChildren {
···
159
184
NotificationsRoute: typeof NotificationsRoute
160
185
SearchRoute: typeof SearchRoute
161
186
SettingsRoute: typeof SettingsRoute
187
+
CallbackIndexRoute: typeof CallbackIndexRoute
162
188
ProfileDidIndexRoute: typeof ProfileDidIndexRoute
163
-
ProfileDidPostRkeyRoute: typeof ProfileDidPostRkeyRoute
189
+
ProfileDidPostRkeyRoute: typeof ProfileDidPostRkeyRouteWithChildren
164
190
}
165
191
166
192
declare module '@tanstack/react-router' {
···
207
233
preLoaderRoute: typeof IndexRouteImport
208
234
parentRoute: typeof rootRouteImport
209
235
}
236
+
'/callback/': {
237
+
id: '/callback/'
238
+
path: '/callback'
239
+
fullPath: '/callback'
240
+
preLoaderRoute: typeof CallbackIndexRouteImport
241
+
parentRoute: typeof rootRouteImport
242
+
}
210
243
'/_pathlessLayout/_nested-layout': {
211
244
id: '/_pathlessLayout/_nested-layout'
212
245
path: ''
···
242
275
preLoaderRoute: typeof ProfileDidPostRkeyRouteImport
243
276
parentRoute: typeof rootRouteImport
244
277
}
278
+
'/profile/$did/post/$rkey/image/$i': {
279
+
id: '/profile/$did/post/$rkey/image/$i'
280
+
path: '/image/$i'
281
+
fullPath: '/profile/$did/post/$rkey/image/$i'
282
+
preLoaderRoute: typeof ProfileDidPostRkeyImageIRouteImport
283
+
parentRoute: typeof ProfileDidPostRkeyRoute
284
+
}
245
285
}
246
286
}
247
287
···
275
315
PathlessLayoutRouteChildren,
276
316
)
277
317
318
+
interface ProfileDidPostRkeyRouteChildren {
319
+
ProfileDidPostRkeyImageIRoute: typeof ProfileDidPostRkeyImageIRoute
320
+
}
321
+
322
+
const ProfileDidPostRkeyRouteChildren: ProfileDidPostRkeyRouteChildren = {
323
+
ProfileDidPostRkeyImageIRoute: ProfileDidPostRkeyImageIRoute,
324
+
}
325
+
326
+
const ProfileDidPostRkeyRouteWithChildren =
327
+
ProfileDidPostRkeyRoute._addFileChildren(ProfileDidPostRkeyRouteChildren)
328
+
278
329
const rootRouteChildren: RootRouteChildren = {
279
330
IndexRoute: IndexRoute,
280
331
PathlessLayoutRoute: PathlessLayoutRouteWithChildren,
···
282
333
NotificationsRoute: NotificationsRoute,
283
334
SearchRoute: SearchRoute,
284
335
SettingsRoute: SettingsRoute,
336
+
CallbackIndexRoute: CallbackIndexRoute,
285
337
ProfileDidIndexRoute: ProfileDidIndexRoute,
286
-
ProfileDidPostRkeyRoute: ProfileDidPostRkeyRoute,
338
+
ProfileDidPostRkeyRoute: ProfileDidPostRkeyRouteWithChildren,
287
339
}
288
340
export const routeTree = rootRouteImport
289
341
._addFileChildren(rootRouteChildren)
+586
-473
src/routes/__root.tsx
+586
-473
src/routes/__root.tsx
···
2
2
3
3
// dont forget to run this
4
4
// npx @tanstack/router-cli generate
5
-
6
-
import { useState, type SVGProps } from "react";
5
+
import type { QueryClient } from "@tanstack/react-query";
7
6
import {
8
-
HeadContent,
9
-
Link,
10
-
Outlet,
7
+
createRootRouteWithContext,
8
+
// Link,
9
+
// Outlet,
11
10
Scripts,
12
-
createRootRoute,
13
11
useLocation,
12
+
useNavigate,
14
13
} from "@tanstack/react-router";
15
14
import { TanStackRouterDevtools } from "@tanstack/react-router-devtools";
15
+
import { useAtom } from "jotai";
16
16
import * as React from "react";
17
+
import { KeepAliveOutlet, KeepAliveProvider } from "tanstack-router-keepalive";
18
+
19
+
import { Composer } from "~/components/Composer";
17
20
import { DefaultCatchBoundary } from "~/components/DefaultCatchBoundary";
21
+
import { Import } from "~/components/Import";
18
22
import Login from "~/components/Login";
19
23
import { NotFound } from "~/components/NotFound";
20
-
import appCss from "~/styles/app.css?url";
24
+
import { FluentEmojiHighContrastGlowingStar } from "~/components/Star";
25
+
import { UnifiedAuthProvider, useAuth } from "~/providers/UnifiedAuthProvider";
26
+
import { composerAtom, hueAtom, useAtomCssVar } from "~/utils/atoms";
21
27
import { seo } from "~/utils/seo";
22
-
import { AuthProvider, useAuth } from "~/providers/PassAuthProvider";
23
-
import { PersistentStoreProvider } from "~/providers/PersistentStoreProvider";
24
-
import type AtpAgent from "@atproto/api";
25
28
26
-
export const Route = createRootRoute({
29
+
export const Route = createRootRouteWithContext<{
30
+
queryClient: QueryClient;
31
+
}>()({
27
32
head: () => ({
28
33
meta: [
29
34
{
···
39
44
}),
40
45
],
41
46
links: [
42
-
{ rel: "stylesheet", href: appCss },
43
47
{
44
48
rel: "apple-touch-icon",
45
49
sizes: "180x180",
···
61
65
{ rel: "icon", href: "/favicon.ico" },
62
66
],
63
67
}),
64
-
errorComponent: (props) => {
65
-
return (
66
-
<RootDocument>
67
-
<DefaultCatchBoundary {...props} />
68
-
</RootDocument>
69
-
);
70
-
},
68
+
errorComponent: import.meta.env.DEV
69
+
? undefined
70
+
: (props) => (
71
+
<RootDocument>
72
+
<DefaultCatchBoundary {...props} />
73
+
</RootDocument>
74
+
),
71
75
notFoundComponent: () => <NotFound />,
72
76
component: RootComponent,
73
77
});
74
78
75
79
function RootComponent() {
76
80
return (
77
-
<AuthProvider>
78
-
<PersistentStoreProvider>
79
-
<RootDocument>
80
-
<Outlet />
81
-
</RootDocument>
82
-
</PersistentStoreProvider>
83
-
</AuthProvider>
81
+
<UnifiedAuthProvider>
82
+
<RootDocument>
83
+
<KeepAliveProvider>
84
+
<KeepAliveOutlet />
85
+
</KeepAliveProvider>
86
+
</RootDocument>
87
+
</UnifiedAuthProvider>
84
88
);
85
89
}
86
90
87
91
function RootDocument({ children }: { children: React.ReactNode }) {
92
+
useAtomCssVar(hueAtom, "--tw-gray-hue");
88
93
const location = useLocation();
89
-
const { agent, authed } = useAuth();
94
+
const navigate = useNavigate();
95
+
const { agent } = useAuth();
96
+
const authed = !!agent?.did;
90
97
const isHome = location.pathname === "/";
91
98
const isNotifications = location.pathname.startsWith("/notifications");
92
-
const isProfile = location.pathname.startsWith("/profile/");
99
+
const isProfile =
100
+
agent &&
101
+
(location.pathname === `/profile/${agent?.did}` ||
102
+
location.pathname === `/profile/${encodeURIComponent(agent?.did ?? "")}`);
103
+
const isSettings = location.pathname.startsWith("/settings");
104
+
const isSearch = location.pathname.startsWith("/search");
105
+
const isFeeds = location.pathname.startsWith("/feeds");
93
106
94
-
const [postOpen, setPostOpen] = useState(false);
95
-
const [postText, setPostText] = useState("");
96
-
const [posting, setPosting] = useState(false);
97
-
const [postSuccess, setPostSuccess] = useState(false);
98
-
const [postError, setPostError] = useState<string | null>(null);
107
+
const locationEnum:
108
+
| "feeds"
109
+
| "search"
110
+
| "settings"
111
+
| "notifications"
112
+
| "profile"
113
+
| "home" = isFeeds
114
+
? "feeds"
115
+
: isSearch
116
+
? "search"
117
+
: isSettings
118
+
? "settings"
119
+
: isNotifications
120
+
? "notifications"
121
+
: isProfile
122
+
? "profile"
123
+
: "home";
99
124
100
-
async function handlePost() {
101
-
if (!agent) return;
102
-
setPosting(true);
103
-
setPostError(null);
104
-
try {
105
-
await agent.com.atproto.repo.createRecord({
106
-
collection: "app.bsky.feed.post",
107
-
repo: agent.assertDid,
108
-
record: {
109
-
$type: "app.bsky.feed.post",
110
-
text: postText,
111
-
createdAt: new Date().toISOString(),
112
-
},
113
-
});
114
-
setPostSuccess(true);
115
-
setPostText("");
116
-
setTimeout(() => {
117
-
setPostSuccess(false);
118
-
setPostOpen(false);
119
-
}, 1500);
120
-
} catch (e: any) {
121
-
setPostError(e?.message || "Failed to post");
122
-
} finally {
123
-
setPosting(false);
124
-
}
125
-
}
125
+
const [, setComposerPost] = useAtom(composerAtom);
126
126
127
127
return (
128
128
<>
129
-
{postOpen && (
130
-
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40">
131
-
<div className="bg-white dark:bg-gray-900 rounded-lg shadow-lg p-6 w-full max-w-md relative">
132
-
<button
133
-
className="absolute top-2 right-2 text-gray-400 hover:text-gray-700 dark:hover:text-gray-200"
134
-
onClick={() => !posting && setPostOpen(false)}
135
-
disabled={posting}
136
-
aria-label="Close"
137
-
>
138
-
ร
139
-
</button>
140
-
<h2 className="text-lg font-bold mb-2">Create Post</h2>
141
-
{postSuccess ? (
142
-
<div className="flex flex-col items-center justify-center py-8">
143
-
<span className="text-green-500 text-4xl mb-2">โ</span>
144
-
<span className="text-green-600">Posted!</span>
145
-
</div>
146
-
) : (
147
-
<>
148
-
<textarea
149
-
className="w-full border rounded p-2 mb-2 dark:bg-gray-800 dark:border-gray-700"
150
-
rows={4}
151
-
placeholder="What's on your mind?"
152
-
value={postText}
153
-
onChange={(e) => setPostText(e.target.value)}
154
-
disabled={posting}
155
-
autoFocus
156
-
/>
157
-
{postError && (
158
-
<div className="text-red-500 text-sm mb-2">{postError}</div>
159
-
)}
160
-
<button
161
-
className="bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded disabled:opacity-50"
162
-
onClick={handlePost}
163
-
disabled={posting || !postText.trim()}
164
-
>
165
-
{posting ? "Posting..." : "Post"}
166
-
</button>
167
-
</>
168
-
)}
169
-
</div>
170
-
</div>
171
-
)}
129
+
<Composer />
172
130
173
131
<div className="min-h-screen flex justify-center bg-gray-50 dark:bg-gray-950">
174
-
<nav className="hidden lg:flex h-screen w-[250px] flex-col gap-2 p-4 dark:border-gray-800 sticky top-0 self-start">
132
+
<nav className="hidden lg:flex h-screen w-[250px] flex-col gap-0 p-4 dark:border-gray-800 sticky top-0 self-start">
175
133
<div className="flex items-center gap-3 mb-4">
176
-
<img src="/redstar.png" alt="Red Dwarf Logo" className="w-8 h-8" />
134
+
<FluentEmojiHighContrastGlowingStar className="h-8 w-8" style={{color: "oklch(0.6616 0.2249 calc(25.88 + (var(--safe-hue) - 28))"}} />
177
135
<span className="font-extrabold text-2xl tracking-tight text-gray-900 dark:text-gray-100">
178
136
Red Dwarf{" "}
179
137
{/* <span className="text-gray-500 dark:text-gray-400 text-sm">
···
181
139
</span> */}
182
140
</span>
183
141
</div>
184
-
<Link
142
+
<MaterialNavItem
143
+
InactiveIcon={
144
+
<IconMaterialSymbolsHomeOutline className="w-6 h-6" />
145
+
}
146
+
ActiveIcon={<IconMaterialSymbolsHome className="w-6 h-6" />}
147
+
active={locationEnum === "home"}
148
+
onClickCallbback={() =>
149
+
navigate({
150
+
to: "/",
151
+
//params: { did: agent.assertDid },
152
+
})
153
+
}
154
+
text="Home"
155
+
/>
156
+
157
+
<MaterialNavItem
158
+
InactiveIcon={<IconMaterialSymbolsSearch className="w-6 h-6" />}
159
+
ActiveIcon={<IconMaterialSymbolsSearch className="w-6 h-6" />}
160
+
active={locationEnum === "search"}
161
+
onClickCallbback={() =>
162
+
navigate({
163
+
to: "/search",
164
+
//params: { did: agent.assertDid },
165
+
})
166
+
}
167
+
text="Explore"
168
+
/>
169
+
<MaterialNavItem
170
+
InactiveIcon={
171
+
<IconMaterialSymbolsNotificationsOutline className="w-6 h-6" />
172
+
}
173
+
ActiveIcon={
174
+
<IconMaterialSymbolsNotifications className="w-6 h-6" />
175
+
}
176
+
active={locationEnum === "notifications"}
177
+
onClickCallbback={() =>
178
+
navigate({
179
+
to: "/notifications",
180
+
//params: { did: agent.assertDid },
181
+
})
182
+
}
183
+
text="Notifications"
184
+
/>
185
+
<MaterialNavItem
186
+
InactiveIcon={<IconMaterialSymbolsTag className="w-6 h-6" />}
187
+
ActiveIcon={<IconMaterialSymbolsTag className="w-6 h-6" />}
188
+
active={locationEnum === "feeds"}
189
+
onClickCallbback={() =>
190
+
navigate({
191
+
to: "/feeds",
192
+
//params: { did: agent.assertDid },
193
+
})
194
+
}
195
+
text="Feeds"
196
+
/>
197
+
<MaterialNavItem
198
+
InactiveIcon={
199
+
<IconMaterialSymbolsAccountCircleOutline className="w-6 h-6" />
200
+
}
201
+
ActiveIcon={
202
+
<IconMaterialSymbolsAccountCircle className="w-6 h-6" />
203
+
}
204
+
active={locationEnum === "profile"}
205
+
onClickCallbback={() => {
206
+
if (authed && agent && agent.assertDid) {
207
+
//window.location.href = `/profile/${agent.assertDid}`;
208
+
navigate({
209
+
to: "/profile/$did",
210
+
params: { did: agent.assertDid },
211
+
});
212
+
}
213
+
}}
214
+
text="Profile"
215
+
/>
216
+
<MaterialNavItem
217
+
InactiveIcon={
218
+
<IconMaterialSymbolsSettingsOutline className="w-6 h-6" />
219
+
}
220
+
ActiveIcon={<IconMaterialSymbolsSettings className="w-6 h-6" />}
221
+
active={locationEnum === "settings"}
222
+
onClickCallbback={() =>
223
+
navigate({
224
+
to: "/settings",
225
+
//params: { did: agent.assertDid },
226
+
})
227
+
}
228
+
text="Settings"
229
+
/>
230
+
<div className="flex flex-row items-center justify-center mt-3">
231
+
<MaterialPillButton
232
+
InactiveIcon={<IconMdiPencilOutline className="w-6 h-6" />}
233
+
ActiveIcon={<IconMdiPencilOutline className="w-6 h-6" />}
234
+
//active={true}
235
+
onClickCallbback={() => setComposerPost({ kind: 'root' })}
236
+
text="Post"
237
+
/>
238
+
</div>
239
+
{/* <Link
185
240
to="/"
186
241
className={
187
242
`py-2 px-4 hover:bg-gray-100 dark:hover:bg-gray-900 text-xl flex items-center gap-3 ` +
188
243
(isHome ? "font-bold" : "")
189
244
}
190
245
>
191
-
{isHome ? (
192
-
<TablerHomeFilled width={28} height={28} />
246
+
{!isHome ? (
247
+
<IconMaterialSymbolsHomeOutline width={28} height={28} />
193
248
) : (
194
-
<TablerHome width={28} height={28} />
249
+
<IconMaterialSymbolsHome width={28} height={28} />
195
250
)}
196
251
<span>Home</span>
197
252
</Link>
···
202
257
(isNotifications ? "font-bold" : "")
203
258
}
204
259
>
205
-
{isNotifications ? (
206
-
<TablerBellFilled width={28} height={28} />
260
+
{!isNotifications ? (
261
+
<IconMaterialSymbolsNotificationsOutline width={28} height={28} />
207
262
) : (
208
-
<TablerBell width={28} height={28} />
263
+
<IconMaterialSymbolsNotifications width={28} height={28} />
209
264
)}
210
265
<span>Notifications</span>
211
266
</Link>
···
216
271
}`}
217
272
>
218
273
{location.pathname.startsWith("/feeds") ? (
219
-
<TablerHashtagFilled width={28} height={28} />
274
+
<IconMaterialSymbolsTag width={28} height={28} />
220
275
) : (
221
-
<TablerHashtag width={28} height={28} />
276
+
<IconMaterialSymbolsTag width={28} height={28} />
222
277
)}
223
278
<span>Feeds</span>
224
279
</Link>
···
230
285
}`}
231
286
>
232
287
{location.pathname.startsWith("/search") ? (
233
-
<TablerSearchFilled width={28} height={28} />
288
+
<IconMaterialSymbolsSearch width={28} height={28} />
234
289
) : (
235
-
<TablerSearch width={28} height={28} />
290
+
<IconMaterialSymbolsSearch width={28} height={28} />
236
291
)}
237
292
<span>Search</span>
238
293
</Link>
···
242
297
}`}
243
298
onClick={() => {
244
299
if (authed && agent && agent.assertDid) {
245
-
window.location.href = `/profile/${agent.assertDid}`;
300
+
//window.location.href = `/profile/${agent.assertDid}`;
301
+
navigate({
302
+
to: "/profile/$did",
303
+
params: { did: agent.assertDid },
304
+
});
246
305
}
247
306
}}
248
307
type="button"
249
308
>
250
-
<TablerUserCircle width={28} height={28} />
309
+
{!isProfile ? (
310
+
<IconMaterialSymbolsAccountCircleOutline width={28} height={28} />
311
+
) : (
312
+
<IconMaterialSymbolsAccountCircle width={28} height={28} />
313
+
)}
251
314
<span>Profile</span>
252
315
</button>
253
316
<Link
···
256
319
location.pathname.startsWith("/settings") ? "font-bold" : ""
257
320
}`}
258
321
>
259
-
{location.pathname.startsWith("/settings") ? (
260
-
<IonSettingsSharp width={28} height={28} />
322
+
{!location.pathname.startsWith("/settings") ? (
323
+
<IconMaterialSymbolsSettingsOutline width={28} height={28} />
261
324
) : (
262
-
<IonSettings width={28} height={28} />
325
+
<IconMaterialSymbolsSettings width={28} height={28} />
263
326
)}
264
327
<span>Settings</span>
265
-
</Link>
266
-
<button
328
+
</Link> */}
329
+
{/* <button
267
330
className="mt-4 w-full flex items-center justify-center gap-3 py-3 px-0 mb-3 bg-gray-200 dark:bg-gray-800 hover:bg-gray-300 dark:hover:bg-gray-700 text-gray-900 dark:text-gray-100 text-xl font-bold rounded-full transition-colors shadow"
268
331
onClick={() => setPostOpen(true)}
269
332
type="button"
270
333
>
271
-
<TablerEdit
334
+
<IconMdiPencilOutline
272
335
width={24}
273
336
height={24}
274
337
className="text-gray-600 dark:text-gray-400"
275
338
/>
276
339
<span>Post</span>
277
-
</button>
340
+
</button> */}
278
341
<div className="flex-1"></div>
279
342
<a
280
343
href="https://tangled.sh/@whey.party/red-dwarf"
···
305
368
</div>
306
369
</nav>
307
370
308
-
<button
309
-
className="lg:hidden fixed bottom-20 right-6 z-50 bg-gray-200 dark:bg-gray-800 hover:bg-gray-300 dark:hover:bg-gray-700 text-blue-600 dark:text-blue-400 rounded-full shadow-lg w-16 h-16 flex items-center justify-center border-4 border-white dark:border-gray-950 transition-all"
310
-
style={{ boxShadow: "0 4px 24px 0 rgba(0,0,0,0.12)" }}
311
-
onClick={() => setPostOpen(true)}
312
-
type="button"
313
-
aria-label="Create Post"
314
-
>
315
-
<TablerEdit
316
-
width={24}
317
-
height={24}
318
-
className="text-gray-600 dark:text-gray-400"
371
+
<nav className="hidden sm:flex items-center lg:hidden h-screen flex-col gap-2 p-4 dark:border-gray-800 sticky top-0 self-start">
372
+
<div className="flex items-center gap-3 mb-4">
373
+
<FluentEmojiHighContrastGlowingStar className="h-8 w-8" style={{color: "oklch(0.6616 0.2249 calc(25.88 + (var(--safe-hue) - 28))"}} />
374
+
</div>
375
+
<MaterialNavItem
376
+
small
377
+
InactiveIcon={
378
+
<IconMaterialSymbolsHomeOutline className="w-6 h-6" />
379
+
}
380
+
ActiveIcon={<IconMaterialSymbolsHome className="w-6 h-6" />}
381
+
active={locationEnum === "home"}
382
+
onClickCallbback={() =>
383
+
navigate({
384
+
to: "/",
385
+
//params: { did: agent.assertDid },
386
+
})
387
+
}
388
+
text="Home"
319
389
/>
320
-
</button>
321
390
322
-
<main className="w-full max-w-[600px] lg:border-x border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-950 pb-16 lg:pb-0">
323
-
<div className="lg:hidden flex items-center justify-between px-4 py-3 border-b border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-950">
324
-
<div className="flex items-center gap-2">
325
-
<img
326
-
src="/redstar.png"
327
-
alt="Red Dwarf Logo"
328
-
className="w-6 h-6"
329
-
/>
330
-
<span className="font-bold text-lg text-gray-900 dark:text-gray-100">
331
-
Red Dwarf{" "}
332
-
{/* <span className="text-gray-500 dark:text-gray-400 text-sm">
333
-
lite
334
-
</span> */}
335
-
</span>
336
-
</div>
337
-
<div className="flex items-center gap-2">
338
-
<Login compact={true} />
339
-
</div>
391
+
<MaterialNavItem
392
+
small
393
+
InactiveIcon={<IconMaterialSymbolsSearch className="w-6 h-6" />}
394
+
ActiveIcon={<IconMaterialSymbolsSearch className="w-6 h-6" />}
395
+
active={locationEnum === "search"}
396
+
onClickCallbback={() =>
397
+
navigate({
398
+
to: "/search",
399
+
//params: { did: agent.assertDid },
400
+
})
401
+
}
402
+
text="Explore"
403
+
/>
404
+
<MaterialNavItem
405
+
small
406
+
InactiveIcon={
407
+
<IconMaterialSymbolsNotificationsOutline className="w-6 h-6" />
408
+
}
409
+
ActiveIcon={
410
+
<IconMaterialSymbolsNotifications className="w-6 h-6" />
411
+
}
412
+
active={locationEnum === "notifications"}
413
+
onClickCallbback={() =>
414
+
navigate({
415
+
to: "/notifications",
416
+
//params: { did: agent.assertDid },
417
+
})
418
+
}
419
+
text="Notifications"
420
+
/>
421
+
<MaterialNavItem
422
+
small
423
+
InactiveIcon={<IconMaterialSymbolsTag className="w-6 h-6" />}
424
+
ActiveIcon={<IconMaterialSymbolsTag className="w-6 h-6" />}
425
+
active={locationEnum === "feeds"}
426
+
onClickCallbback={() =>
427
+
navigate({
428
+
to: "/feeds",
429
+
//params: { did: agent.assertDid },
430
+
})
431
+
}
432
+
text="Feeds"
433
+
/>
434
+
<MaterialNavItem
435
+
small
436
+
InactiveIcon={
437
+
<IconMaterialSymbolsAccountCircleOutline className="w-6 h-6" />
438
+
}
439
+
ActiveIcon={
440
+
<IconMaterialSymbolsAccountCircle className="w-6 h-6" />
441
+
}
442
+
active={locationEnum === "profile"}
443
+
onClickCallbback={() => {
444
+
if (authed && agent && agent.assertDid) {
445
+
//window.location.href = `/profile/${agent.assertDid}`;
446
+
navigate({
447
+
to: "/profile/$did",
448
+
params: { did: agent.assertDid },
449
+
});
450
+
}
451
+
}}
452
+
text="Profile"
453
+
/>
454
+
<MaterialNavItem
455
+
small
456
+
InactiveIcon={
457
+
<IconMaterialSymbolsSettingsOutline className="w-6 h-6" />
458
+
}
459
+
ActiveIcon={<IconMaterialSymbolsSettings className="w-6 h-6" />}
460
+
active={locationEnum === "settings"}
461
+
onClickCallbback={() =>
462
+
navigate({
463
+
to: "/settings",
464
+
//params: { did: agent.assertDid },
465
+
})
466
+
}
467
+
text="Settings"
468
+
/>
469
+
<div className="flex flex-row items-center justify-center mt-3">
470
+
<MaterialPillButton
471
+
small
472
+
InactiveIcon={<IconMdiPencilOutline className="w-6 h-6" />}
473
+
ActiveIcon={<IconMdiPencilOutline className="w-6 h-6" />}
474
+
//active={true}
475
+
onClickCallbback={() => setComposerPost({ kind: 'root' })}
476
+
text="Post"
477
+
/>
340
478
</div>
479
+
</nav>
341
480
481
+
{agent?.did && (
482
+
<button
483
+
className="lg:hidden fixed bottom-22 right-4 z-50 bg-gray-200 dark:bg-gray-800 hover:bg-gray-300 dark:hover:bg-gray-700 rounded-2xl w-14 h-14 flex items-center justify-center transition-all"
484
+
style={{ boxShadow: "0 4px 24px 0 rgba(0,0,0,0.12)" }}
485
+
onClick={() => setComposerPost({ kind: 'root' })}
486
+
type="button"
487
+
aria-label="Create Post"
488
+
>
489
+
<IconMdiPencilOutline
490
+
width={24}
491
+
height={24}
492
+
className="text-gray-600 dark:text-gray-400"
493
+
/>
494
+
</button>
495
+
)}
496
+
497
+
<main className="w-full max-w-[600px] sm:border-x border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-950 pb-16 lg:pb-0 overflow-x-clip">
342
498
{children}
343
499
</main>
344
500
345
501
<aside className="hidden lg:flex h-screen w-[250px] sticky top-0 self-start flex-col">
502
+
<div className="px-4 pt-4"><Import /></div>
346
503
<Login />
347
504
348
505
<div className="flex-1"></div>
349
506
<p className="text-xs text-gray-400 dark:text-gray-500 text-justify mx-4 mb-4">
350
-
Red Dwarf is a bluesky client that uses Constellation and
351
-
direct PDS queries. Skylite would be a
352
-
self-hosted bluesky "instance". Stay tuned for the release of Skylite.
507
+
Red Dwarf is a Bluesky client that does not rely on any Bluesky API App Servers. Instead, it uses Microcosm to fetch records directly from each users' PDS (via Slingshot) and connect them using backlinks (via Constellation)
353
508
</p>
354
509
</aside>
355
510
</div>
356
511
357
-
<nav className="lg:hidden fixed bottom-0 left-0 right-0 bg-white dark:bg-gray-950 border-t border-gray-200 dark:border-gray-700 z-40">
358
-
<div className="flex justify-around items-center py-2">
359
-
<Link
360
-
to="/"
361
-
className={`flex flex-col items-center py-2 px-3 rounded-lg transition-colors flex-1 ${
362
-
isHome
363
-
? "text-gray-900 dark:text-gray-100"
364
-
: "text-gray-600 dark:text-gray-400"
365
-
}`}
366
-
>
367
-
{isHome ? (
368
-
<TablerHomeFilled width={24} height={24} />
369
-
) : (
370
-
<TablerHome width={24} height={24} />
371
-
)}
372
-
<span className="text-xs mt-1">Home</span>
373
-
</Link>
374
-
<Link
375
-
to="/search"
376
-
className={`flex flex-col items-center py-2 px-3 rounded-lg transition-colors flex-1 ${
377
-
location.pathname.startsWith("/search")
378
-
? "text-gray-900 dark:text-gray-100"
379
-
: "text-gray-600 dark:text-gray-400"
380
-
}`}
381
-
>
382
-
{location.pathname.startsWith("/search") ? (
383
-
<TablerSearchFilled width={24} height={24} />
384
-
) : (
385
-
<TablerSearch width={24} height={24} />
386
-
)}
387
-
<span className="text-xs mt-1">Search</span>
388
-
</Link>
389
-
<Link
390
-
to="/notifications"
391
-
className={`flex flex-col items-center py-2 px-3 rounded-lg transition-colors flex-1 ${
392
-
isNotifications
393
-
? "text-gray-900 dark:text-gray-100"
394
-
: "text-gray-600 dark:text-gray-400"
395
-
}`}
396
-
>
397
-
{isNotifications ? (
398
-
<TablerBellFilled width={24} height={24} />
399
-
) : (
400
-
<TablerBell width={24} height={24} />
401
-
)}
402
-
<span className="text-xs mt-1">Notifications</span>
403
-
</Link>
404
-
<button
405
-
className={`flex flex-col items-center py-2 px-3 rounded-lg transition-colors flex-1 ${
406
-
isProfile
407
-
? "text-gray-900 dark:text-gray-100"
408
-
: "text-gray-600 dark:text-gray-400"
409
-
}`}
410
-
onClick={() => {
411
-
if (authed && agent && agent.assertDid) {
412
-
window.location.href = `/profile/${agent.assertDid}`;
512
+
{agent?.did ? (
513
+
<nav className="sm:hidden fixed bottom-0 left-0 right-0 bg-gray-50 dark:bg-gray-900 border-0 shadow border-gray-200 dark:border-gray-700 z-40">
514
+
<div className="flex justify-around items-center p-2">
515
+
<MaterialNavItem
516
+
small
517
+
InactiveIcon={
518
+
<IconMaterialSymbolsHomeOutline className="w-6 h-6" />
519
+
}
520
+
ActiveIcon={<IconMaterialSymbolsHome className="w-6 h-6" />}
521
+
active={locationEnum === "home"}
522
+
onClickCallbback={() =>
523
+
navigate({
524
+
to: "/",
525
+
//params: { did: agent.assertDid },
526
+
})
527
+
}
528
+
text="Home"
529
+
/>
530
+
{/* <Link
531
+
to="/"
532
+
className={`flex flex-col items-center py-2 px-3 rounded-lg transition-colors flex-1 ${
533
+
isHome
534
+
? "text-gray-900 dark:text-gray-100"
535
+
: "text-gray-600 dark:text-gray-400"
536
+
}`}
537
+
>
538
+
{!isHome ? (
539
+
<IconMaterialSymbolsHomeOutline width={24} height={24} />
540
+
) : (
541
+
<IconMaterialSymbolsHome width={24} height={24} />
542
+
)}
543
+
<span className="text-xs mt-1">Home</span>
544
+
</Link> */}
545
+
<MaterialNavItem
546
+
small
547
+
InactiveIcon={<IconMaterialSymbolsSearch className="w-6 h-6" />}
548
+
ActiveIcon={<IconMaterialSymbolsSearch className="w-6 h-6" />}
549
+
active={locationEnum === "search"}
550
+
onClickCallbback={() =>
551
+
navigate({
552
+
to: "/search",
553
+
//params: { did: agent.assertDid },
554
+
})
555
+
}
556
+
text="Explore"
557
+
/>
558
+
{/* <Link
559
+
to="/search"
560
+
className={`flex flex-col items-center py-2 px-3 rounded-lg transition-colors flex-1 ${
561
+
location.pathname.startsWith("/search")
562
+
? "text-gray-900 dark:text-gray-100"
563
+
: "text-gray-600 dark:text-gray-400"
564
+
}`}
565
+
>
566
+
{!location.pathname.startsWith("/search") ? (
567
+
<IconMaterialSymbolsSearch width={24} height={24} />
568
+
) : (
569
+
<IconMaterialSymbolsSearch width={24} height={24} />
570
+
)}
571
+
<span className="text-xs mt-1">Search</span>
572
+
</Link> */}
573
+
<MaterialNavItem
574
+
small
575
+
InactiveIcon={
576
+
<IconMaterialSymbolsNotificationsOutline className="w-6 h-6" />
577
+
}
578
+
ActiveIcon={
579
+
<IconMaterialSymbolsNotifications className="w-6 h-6" />
580
+
}
581
+
active={locationEnum === "notifications"}
582
+
onClickCallbback={() =>
583
+
navigate({
584
+
to: "/notifications",
585
+
//params: { did: agent.assertDid },
586
+
})
587
+
}
588
+
text="Notifications"
589
+
/>
590
+
{/* <Link
591
+
to="/notifications"
592
+
className={`flex flex-col items-center py-2 px-3 rounded-lg transition-colors flex-1 ${
593
+
isNotifications
594
+
? "text-gray-900 dark:text-gray-100"
595
+
: "text-gray-600 dark:text-gray-400"
596
+
}`}
597
+
>
598
+
{!isNotifications ? (
599
+
<IconMaterialSymbolsNotificationsOutline
600
+
width={24}
601
+
height={24}
602
+
/>
603
+
) : (
604
+
<IconMaterialSymbolsNotifications width={24} height={24} />
605
+
)}
606
+
<span className="text-xs mt-1">Notifications</span>
607
+
</Link> */}
608
+
<MaterialNavItem
609
+
small
610
+
InactiveIcon={
611
+
<IconMaterialSymbolsAccountCircleOutline className="w-6 h-6" />
612
+
}
613
+
ActiveIcon={
614
+
<IconMaterialSymbolsAccountCircle className="w-6 h-6" />
615
+
}
616
+
active={locationEnum === "profile"}
617
+
onClickCallbback={() => {
618
+
if (authed && agent && agent.assertDid) {
619
+
//window.location.href = `/profile/${agent.assertDid}`;
620
+
navigate({
621
+
to: "/profile/$did",
622
+
params: { did: agent.assertDid },
623
+
});
624
+
}
625
+
}}
626
+
text="Profile"
627
+
/>
628
+
{/* <button
629
+
className={`flex flex-col items-center py-2 px-3 rounded-lg transition-colors flex-1 ${
630
+
isProfile
631
+
? "text-gray-900 dark:text-gray-100"
632
+
: "text-gray-600 dark:text-gray-400"
633
+
}`}
634
+
onClick={() => {
635
+
if (authed && agent && agent.assertDid) {
636
+
//window.location.href = `/profile/${agent.assertDid}`;
637
+
navigate({
638
+
to: "/profile/$did",
639
+
params: { did: agent.assertDid },
640
+
});
641
+
}
642
+
}}
643
+
type="button"
644
+
>
645
+
<IconMaterialSymbolsAccountCircleOutline width={24} height={24} />
646
+
<span className="text-xs mt-1">Profile</span>
647
+
</button> */}
648
+
<MaterialNavItem
649
+
small
650
+
InactiveIcon={
651
+
<IconMaterialSymbolsSettingsOutline className="w-6 h-6" />
652
+
}
653
+
ActiveIcon={<IconMaterialSymbolsSettings className="w-6 h-6" />}
654
+
active={locationEnum === "settings"}
655
+
onClickCallbback={() =>
656
+
navigate({
657
+
to: "/settings",
658
+
//params: { did: agent.assertDid },
659
+
})
413
660
}
414
-
}}
415
-
type="button"
416
-
>
417
-
<TablerUserCircle width={24} height={24} />
418
-
<span className="text-xs mt-1">Profile</span>
419
-
</button>
420
-
<Link
421
-
to="/settings"
422
-
className={`flex flex-col items-center py-2 px-3 rounded-lg transition-colors flex-1 ${
423
-
location.pathname.startsWith("/settings")
424
-
? "text-gray-900 dark:text-gray-100"
425
-
: "text-gray-600 dark:text-gray-400"
426
-
}`}
427
-
>
428
-
{location.pathname.startsWith("/settings") ? (
429
-
<IonSettingsSharp width={24} height={24} />
430
-
) : (
431
-
<IonSettings width={24} height={24} />
432
-
)}
433
-
<span className="text-xs mt-1">Settings</span>
434
-
</Link>
661
+
text="Settings"
662
+
/>
663
+
{/* <Link
664
+
to="/settings"
665
+
className={`flex flex-col items-center py-2 px-3 rounded-lg transition-colors flex-1 ${
666
+
location.pathname.startsWith("/settings")
667
+
? "text-gray-900 dark:text-gray-100"
668
+
: "text-gray-600 dark:text-gray-400"
669
+
}`}
670
+
>
671
+
{!location.pathname.startsWith("/settings") ? (
672
+
<IconMaterialSymbolsSettingsOutline width={24} height={24} />
673
+
) : (
674
+
<IconMaterialSymbolsSettings width={24} height={24} />
675
+
)}
676
+
<span className="text-xs mt-1">Settings</span>
677
+
</Link> */}
678
+
</div>
679
+
</nav>
680
+
) : (
681
+
<div className="lg:hidden flex items-center fixed bottom-0 left-0 right-0 justify-between px-4 py-3 border-0 shadow border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-900 z-10">
682
+
<div className="flex items-center gap-2">
683
+
<FluentEmojiHighContrastGlowingStar className="h-6 w-6" style={{color: "oklch(0.6616 0.2249 calc(25.88 + (var(--safe-hue) - 28))"}} />
684
+
<span className="font-bold text-lg text-gray-900 dark:text-gray-100">
685
+
Red Dwarf{" "}
686
+
{/* <span className="text-gray-500 dark:text-gray-400 text-sm">
687
+
lite
688
+
</span> */}
689
+
</span>
690
+
</div>
691
+
<div className="flex items-center gap-2">
692
+
<Login compact={true} popup={true} />
693
+
</div>
435
694
</div>
436
-
</nav>
695
+
)}
437
696
438
-
<TanStackRouterDevtools position="bottom-right" />
697
+
<TanStackRouterDevtools position="bottom-left" />
439
698
<Scripts />
440
699
</>
441
700
);
442
701
}
443
-
export function TablerHashtag(props: SVGProps<SVGSVGElement>) {
444
-
return (
445
-
<svg
446
-
xmlns="http://www.w3.org/2000/svg"
447
-
width={24}
448
-
height={24}
449
-
viewBox="0 0 24 24"
450
-
{...props}
451
-
>
452
-
<path
453
-
fill="none"
454
-
stroke="currentColor"
455
-
strokeLinecap="round"
456
-
strokeLinejoin="round"
457
-
strokeWidth={2}
458
-
d="M5 9h14M5 15h14M11 4L7 20M17 4l-4 16"
459
-
></path>
460
-
</svg>
461
-
);
462
-
}
463
702
464
-
export function TablerHashtagFilled(props: SVGProps<SVGSVGElement>) {
465
-
return (
466
-
<svg
467
-
xmlns="http://www.w3.org/2000/svg"
468
-
width={24}
469
-
height={24}
470
-
viewBox="0 0 24 24"
471
-
{...props}
472
-
>
473
-
<path
474
-
fill="none"
475
-
stroke="currentColor"
476
-
strokeLinecap="round"
477
-
strokeLinejoin="round"
478
-
strokeWidth={3}
479
-
d="M5 9h14M5 15h14M11 4L7 20M17 4l-4 16"
480
-
></path>
481
-
</svg>
482
-
);
483
-
}
484
-
export function TablerEdit(props: SVGProps<SVGSVGElement>) {
485
-
return (
486
-
<svg
487
-
xmlns="http://www.w3.org/2000/svg"
488
-
width={24}
489
-
height={24}
490
-
viewBox="0 0 24 24"
491
-
className="text-white"
492
-
{...props}
493
-
>
494
-
<g
495
-
fill="none"
496
-
stroke="currentColor"
497
-
strokeLinecap="round"
498
-
strokeLinejoin="round"
499
-
strokeWidth={2}
703
+
function MaterialNavItem({
704
+
InactiveIcon,
705
+
ActiveIcon,
706
+
text,
707
+
active,
708
+
onClickCallbback,
709
+
small,
710
+
}: {
711
+
InactiveIcon: React.ReactElement;
712
+
ActiveIcon: React.ReactElement;
713
+
text: string;
714
+
active: boolean;
715
+
onClickCallbback: () => void;
716
+
small?: boolean | string;
717
+
}) {
718
+
if (small)
719
+
return (
720
+
<button
721
+
className={`flex flex-col items-center rounded-lg transition-colors ${small} gap-1 ${
722
+
active
723
+
? "text-gray-900 dark:text-gray-100"
724
+
: "text-gray-600 dark:text-gray-400"
725
+
}`}
726
+
onClick={() => {
727
+
onClickCallbback();
728
+
}}
500
729
>
501
-
<path d="M16.475 5.408a2.36 2.36 0 1 1 3.34 3.34L7.5 21H3v-4.5z"></path>
502
-
</g>
503
-
</svg>
504
-
);
505
-
}
506
-
export function TablerHome(props: SVGProps<SVGSVGElement>) {
507
-
return (
508
-
<svg
509
-
xmlns="http://www.w3.org/2000/svg"
510
-
width={24}
511
-
height={24}
512
-
viewBox="0 0 24 24"
513
-
className="text-gray-900 dark:text-gray-100 hover:text-gray-700 dark:hover:text-gray-300 transition-colors"
514
-
{...props}
515
-
>
516
-
<g
517
-
stroke="currentColor"
518
-
strokeLinecap="round"
519
-
strokeLinejoin="round"
520
-
strokeWidth={2}
521
-
fill="none"
522
-
>
523
-
<path d="M5 12H3l9-9l9 9h-2M5 12v7a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-7"></path>
524
-
<path d="M9 21v-6a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v6"></path>
525
-
</g>
526
-
</svg>
527
-
);
528
-
}
529
-
export function TablerHomeFilled(props: SVGProps<SVGSVGElement>) {
530
-
return (
531
-
<svg
532
-
xmlns="http://www.w3.org/2000/svg"
533
-
width={24}
534
-
height={24}
535
-
viewBox="0 0 24 24"
536
-
className="text-gray-900 dark:text-gray-100 hover:text-gray-700 dark:hover:text-gray-300 transition-colors"
537
-
{...props}
538
-
>
539
-
<path
540
-
fill="currentColor"
541
-
d="m12.707 2.293l9 9c.63.63.184 1.707-.707 1.707h-1v6a3 3 0 0 1-3 3h-1v-7a3 3 0 0 0-2.824-2.995L13 12h-2a3 3 0 0 0-3 3v7H7a3 3 0 0 1-3-3v-6H3c-.89 0-1.337-1.077-.707-1.707l9-9a1 1 0 0 1 1.414 0M13 14a1 1 0 0 1 1 1v7h-4v-7a1 1 0 0 1 .883-.993L11 14z"
542
-
></path>
543
-
</svg>
544
-
);
545
-
}
546
-
547
-
export function TablerBell(props: SVGProps<SVGSVGElement>) {
548
-
return (
549
-
<svg
550
-
xmlns="http://www.w3.org/2000/svg"
551
-
width={24}
552
-
height={24}
553
-
viewBox="0 0 24 24"
554
-
{...props}
555
-
>
556
-
<path
557
-
className="text-gray-900 dark:text-gray-100 hover:text-gray-700 dark:hover:text-gray-300 transition-colors"
558
-
stroke="currentColor"
559
-
strokeLinecap="round"
560
-
strokeLinejoin="round"
561
-
strokeWidth={2}
562
-
d="M10 5a2 2 0 1 1 4 0a7 7 0 0 1 4 6v3a4 4 0 0 0 2 3H4a4 4 0 0 0 2-3v-3a7 7 0 0 1 4-6M9 17v1a3 3 0 0 0 6 0v-1"
563
-
></path>
564
-
</svg>
565
-
);
566
-
}
567
-
export function TablerBellFilled(props: SVGProps<SVGSVGElement>) {
568
-
return (
569
-
<svg
570
-
xmlns="http://www.w3.org/2000/svg"
571
-
width={24}
572
-
height={24}
573
-
viewBox="0 0 24 24"
574
-
className="text-gray-900 dark:text-gray-100 hover:text-gray-700 dark:hover:text-gray-300 transition-colors"
575
-
{...props}
576
-
>
577
-
<path
578
-
fill="currentColor"
579
-
stroke="currentColor"
580
-
d="M14.235 19c.865 0 1.322 1.024.745 1.668A4 4 0 0 1 12 22a4 4 0 0 1-2.98-1.332c-.552-.616-.158-1.579.634-1.661l.11-.006zM12 2c1.358 0 2.506.903 2.875 2.141l.046.171l.008.043a8.01 8.01 0 0 1 4.024 6.069l.028.287L19 11v2.931l.021.136a3 3 0 0 0 1.143 1.847l.167.117l.162.099c.86.487.56 1.766-.377 1.864L20 18H4c-1.028 0-1.387-1.364-.493-1.87a3 3 0 0 0 1.472-2.063L5 13.924l.001-2.97A8 8 0 0 1 8.822 4.5l.248-.146l.01-.043a3 3 0 0 1 2.562-2.29l.182-.017z"
581
-
></path>
582
-
</svg>
583
-
);
584
-
}
585
-
586
-
export function TablerUserCircle(props: SVGProps<SVGSVGElement>) {
587
-
return (
588
-
<svg
589
-
xmlns="http://www.w3.org/2000/svg"
590
-
width={24}
591
-
height={24}
592
-
viewBox="0 0 24 24"
593
-
className="text-gray-900 dark:text-gray-100 hover:text-gray-700 dark:hover:text-gray-300 transition-colors"
594
-
{...props}
595
-
>
596
-
<g
597
-
fill="none"
598
-
stroke="currentColor"
599
-
strokeLinecap="round"
600
-
strokeLinejoin="round"
601
-
strokeWidth={2}
602
-
>
603
-
<path d="M3 12a9 9 0 1 0 18 0a9 9 0 1 0-18 0"></path>
604
-
<path d="M9 10a3 3 0 1 0 6 0a3 3 0 1 0-6 0m-2.832 8.849A4 4 0 0 1 10 16h4a4 4 0 0 1 3.834 2.855"></path>
605
-
</g>
606
-
</svg>
607
-
);
608
-
}
730
+
<div
731
+
className={`px-4 py-1 rounded-full flex items-center justify-center ${active ? " bg-gray-100 dark:bg-gray-800 hover:bg-gray-200 hover:dark:bg-gray-700" : "hover:bg-gray-50 hover:dark:bg-gray-900"}`}
732
+
>
733
+
{active ? ActiveIcon : InactiveIcon}
734
+
</div>
735
+
<span
736
+
className={`text-[12.8px] text-roboto ${active ? "font-medium" : ""}`}
737
+
>
738
+
{text}
739
+
</span>
740
+
</button>
741
+
);
609
742
610
-
export function TablerSearch(props: SVGProps<SVGSVGElement>) {
611
743
return (
612
-
<svg
613
-
xmlns="http://www.w3.org/2000/svg"
614
-
width={24}
615
-
height={24}
616
-
viewBox="0 0 24 24"
617
-
//className="text-gray-400 dark:text-gray-500"
618
-
{...props}
619
-
>
620
-
<g
621
-
fill="none"
622
-
stroke="currentColor"
623
-
strokeLinecap="round"
624
-
strokeLinejoin="round"
625
-
strokeWidth={2}
626
-
>
627
-
<path d="M3 10a7 7 0 1 0 14 0a7 7 0 1 0-14 0"></path>
628
-
<path d="m21 21l-6-6"></path>
629
-
</g>
630
-
</svg>
631
-
);
632
-
}
633
-
export function TablerSearchFilled(props: SVGProps<SVGSVGElement>) {
634
-
return (
635
-
<svg
636
-
xmlns="http://www.w3.org/2000/svg"
637
-
width={24}
638
-
height={24}
639
-
viewBox="0 0 24 24"
640
-
//className="text-gray-400 dark:text-gray-500"
641
-
{...props}
744
+
<button
745
+
className={`flex flex-row h-12 min-h-12 max-h-12 px-4 py-0.5 w-full items-center rounded-full transition-colors flex-1 gap-1 ${
746
+
active
747
+
? "text-gray-900 dark:text-gray-100 hover:bg-gray-300 dark:bg-gray-800 bg-gray-200 hover:dark:bg-gray-700"
748
+
: "text-gray-600 dark:text-gray-400 hover:bg-gray-100 hover:dark:bg-gray-900"
749
+
}`}
750
+
onClick={() => {
751
+
onClickCallbback();
752
+
}}
642
753
>
643
-
<g
644
-
fill="none"
645
-
stroke="currentColor"
646
-
strokeLinecap="round"
647
-
strokeLinejoin="round"
648
-
strokeWidth={3}
754
+
<div className={`mr-4 ${active ? " " : " "}`}>
755
+
{active ? ActiveIcon : InactiveIcon}
756
+
</div>
757
+
<span
758
+
className={`text-[17px] text-roboto ${active ? "font-medium" : ""}`}
649
759
>
650
-
<path d="M3 10a7 7 0 1 0 14 0a7 7 0 1 0-14 0"></path>
651
-
<path d="m21 21l-6-6"></path>
652
-
</g>
653
-
</svg>
760
+
{text}
761
+
</span>
762
+
</button>
654
763
);
655
764
}
656
765
657
-
export function IonSettings(props: SVGProps<SVGSVGElement>) {
658
-
return (
659
-
<svg
660
-
xmlns="http://www.w3.org/2000/svg"
661
-
width={24}
662
-
height={24}
663
-
viewBox="0 0 512 512"
664
-
{...props}
665
-
>
666
-
<path
667
-
fill="none"
668
-
stroke="currentColor"
669
-
strokeLinecap="round"
670
-
strokeLinejoin="round"
671
-
strokeWidth={32}
672
-
d="M262.29 192.31a64 64 0 1 0 57.4 57.4a64.13 64.13 0 0 0-57.4-57.4M416.39 256a154 154 0 0 1-1.53 20.79l45.21 35.46a10.81 10.81 0 0 1 2.45 13.75l-42.77 74a10.81 10.81 0 0 1-13.14 4.59l-44.9-18.08a16.11 16.11 0 0 0-15.17 1.75A164.5 164.5 0 0 1 325 400.8a15.94 15.94 0 0 0-8.82 12.14l-6.73 47.89a11.08 11.08 0 0 1-10.68 9.17h-85.54a11.11 11.11 0 0 1-10.69-8.87l-6.72-47.82a16.07 16.07 0 0 0-9-12.22a155 155 0 0 1-21.46-12.57a16 16 0 0 0-15.11-1.71l-44.89 18.07a10.81 10.81 0 0 1-13.14-4.58l-42.77-74a10.8 10.8 0 0 1 2.45-13.75l38.21-30a16.05 16.05 0 0 0 6-14.08c-.36-4.17-.58-8.33-.58-12.5s.21-8.27.58-12.35a16 16 0 0 0-6.07-13.94l-38.19-30A10.81 10.81 0 0 1 49.48 186l42.77-74a10.81 10.81 0 0 1 13.14-4.59l44.9 18.08a16.11 16.11 0 0 0 15.17-1.75A164.5 164.5 0 0 1 187 111.2a15.94 15.94 0 0 0 8.82-12.14l6.73-47.89A11.08 11.08 0 0 1 213.23 42h85.54a11.11 11.11 0 0 1 10.69 8.87l6.72 47.82a16.07 16.07 0 0 0 9 12.22a155 155 0 0 1 21.46 12.57a16 16 0 0 0 15.11 1.71l44.89-18.07a10.81 10.81 0 0 1 13.14 4.58l42.77 74a10.8 10.8 0 0 1-2.45 13.75l-38.21 30a16.05 16.05 0 0 0-6.05 14.08c.33 4.14.55 8.3.55 12.47"
673
-
></path>
674
-
</svg>
675
-
);
676
-
}
677
-
export function IonSettingsSharp(props: SVGProps<SVGSVGElement>) {
766
+
function MaterialPillButton({
767
+
InactiveIcon,
768
+
ActiveIcon,
769
+
text,
770
+
//active,
771
+
onClickCallbback,
772
+
small,
773
+
}: {
774
+
InactiveIcon: React.ReactElement;
775
+
ActiveIcon: React.ReactElement;
776
+
text: string;
777
+
//active: boolean;
778
+
onClickCallbback: () => void;
779
+
small?: boolean | string;
780
+
}) {
781
+
const active = false;
678
782
return (
679
-
<svg
680
-
xmlns="http://www.w3.org/2000/svg"
681
-
width={24}
682
-
height={24}
683
-
viewBox="0 0 512 512"
684
-
{...props}
783
+
<button
784
+
className={`flex border border-gray-400 dark:border-gray-400 flex-row h-12 min-h-12 max-h-12 ${small ? "p-3 w-12" : "px-4 py-0.5"} items-center rounded-full transition-colors gap-1 ${
785
+
active
786
+
? "text-gray-900 dark:text-gray-100 hover:bg-gray-300 dark:bg-gray-700 bg-gray-200 hover:dark:bg-gray-600"
787
+
: "text-gray-600 dark:text-gray-400 hover:bg-gray-100 hover:dark:bg-gray-800"
788
+
}`}
789
+
onClick={() => {
790
+
onClickCallbback();
791
+
}}
685
792
>
686
-
<path
687
-
fill="currentColor"
688
-
d="M256 176a80 80 0 1 0 80 80a80.24 80.24 0 0 0-80-80m172.72 80a165.5 165.5 0 0 1-1.64 22.34l48.69 38.12a11.59 11.59 0 0 1 2.63 14.78l-46.06 79.52a11.64 11.64 0 0 1-14.14 4.93l-57.25-23a176.6 176.6 0 0 1-38.82 22.67l-8.56 60.78a11.93 11.93 0 0 1-11.51 9.86h-92.12a12 12 0 0 1-11.51-9.53l-8.56-60.78A169.3 169.3 0 0 1 151.05 393L93.8 416a11.64 11.64 0 0 1-14.14-4.92L33.6 331.57a11.59 11.59 0 0 1 2.63-14.78l48.69-38.12A175 175 0 0 1 83.28 256a165.5 165.5 0 0 1 1.64-22.34l-48.69-38.12a11.59 11.59 0 0 1-2.63-14.78l46.06-79.52a11.64 11.64 0 0 1 14.14-4.93l57.25 23a176.6 176.6 0 0 1 38.82-22.67l8.56-60.78A11.93 11.93 0 0 1 209.94 26h92.12a12 12 0 0 1 11.51 9.53l8.56 60.78A169.3 169.3 0 0 1 361 119l57.2-23a11.64 11.64 0 0 1 14.14 4.92l46.06 79.52a11.59 11.59 0 0 1-2.63 14.78l-48.69 38.12a175 175 0 0 1 1.64 22.66"
689
-
></path>
690
-
</svg>
793
+
<div className={`${!small && "mr-2"} ${active ? " " : " "}`}>
794
+
{active ? ActiveIcon : InactiveIcon}
795
+
</div>
796
+
{!small && (
797
+
<span
798
+
className={`text-[17px] text-roboto ${active ? "font-medium" : ""}`}
799
+
>
800
+
{text}
801
+
</span>
802
+
)}
803
+
</button>
691
804
);
692
805
}
+13
src/routes/callback/index.tsx
+13
src/routes/callback/index.tsx
···
1
+
import { createFileRoute, useNavigate } from '@tanstack/react-router'
2
+
3
+
export const Route = createFileRoute('/callback/')({
4
+
component: RouteComponent,
5
+
})
6
+
7
+
function RouteComponent() {
8
+
const navigate = useNavigate()
9
+
const redirectPath = sessionStorage.getItem('postLoginRedirect') || '/';
10
+
navigate({to:redirectPath})
11
+
sessionStorage.removeItem('postLoginRedirect');
12
+
return <div>Hello "/callback/"!</div>
13
+
}
+449
-223
src/routes/index.tsx
+449
-223
src/routes/index.tsx
···
1
1
import { createFileRoute } from "@tanstack/react-router";
2
-
import {
3
-
CACHE_TIMEOUT,
4
-
cachedGetRecord,
5
-
cachedResolveIdentity,
6
-
UniversalPostRendererATURILoader,
7
-
} from "~/components/UniversalPostRenderer";
2
+
import { useAtom } from "jotai";
8
3
import * as React from "react";
9
-
import { useAuth } from "~/providers/PassAuthProvider";
10
-
import { usePersistentStore } from "~/providers/PersistentStoreProvider";
4
+
import { useLayoutEffect, useState } from "react";
5
+
6
+
import { Header } from "~/components/Header";
7
+
import { InfiniteCustomFeed } from "~/components/InfiniteCustomFeed";
8
+
import { useAuth } from "~/providers/UnifiedAuthProvider";
9
+
import {
10
+
feedScrollPositionsAtom,
11
+
isAtTopAtom,
12
+
quickAuthAtom,
13
+
selectedFeedUriAtom,
14
+
} from "~/utils/atoms";
15
+
//import { usePersistentStore } from "~/providers/PersistentStoreProvider";
16
+
import {
17
+
//constructArbitraryQuery,
18
+
//constructIdentityQuery,
19
+
//constructInfiniteFeedSkeletonQuery,
20
+
//constructPostQuery,
21
+
useQueryArbitrary,
22
+
useQueryIdentity,
23
+
useQueryPreferences,
24
+
} from "~/utils/useQuery";
11
25
12
26
export const Route = createFileRoute("/")({
27
+
// loader: async ({ context }) => {
28
+
// const { queryClient } = context;
29
+
// const atomauth = store.get(authedAtom);
30
+
// const atomagent = store.get(agentAtom);
31
+
32
+
// let identitypds: string | undefined;
33
+
// const initialselectedfeed = store.get(selectedFeedUriAtom);
34
+
// if (atomagent && atomauth && atomagent?.did) {
35
+
// const identityopts = constructIdentityQuery(atomagent.did);
36
+
// const identityresultmaybe =
37
+
// await queryClient.ensureQueryData(identityopts);
38
+
// identitypds = identityresultmaybe?.pds;
39
+
// }
40
+
41
+
// const arbitraryopts = constructArbitraryQuery(
42
+
// initialselectedfeed ??
43
+
// "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot"
44
+
// );
45
+
// const feedGengetrecordquery =
46
+
// await queryClient.ensureQueryData(arbitraryopts);
47
+
// const feedServiceDid = (feedGengetrecordquery?.value as any)?.did;
48
+
// //queryClient.ensureInfiniteQueryData()
49
+
50
+
// const { queryKey, queryFn } = constructInfiniteFeedSkeletonQuery({
51
+
// feedUri:
52
+
// initialselectedfeed ??
53
+
// "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot",
54
+
// agent: atomagent ?? undefined,
55
+
// isAuthed: atomauth ?? false,
56
+
// pdsUrl: identitypds,
57
+
// feedServiceDid: feedServiceDid,
58
+
// });
59
+
60
+
// const res = await queryClient.ensureInfiniteQueryData({
61
+
// queryKey,
62
+
// queryFn,
63
+
// initialPageParam: undefined as never,
64
+
// getNextPageParam: (lastPage: any) => lastPage.cursor as null | undefined,
65
+
// staleTime: Infinity,
66
+
// //refetchOnWindowFocus: false,
67
+
// //enabled: true,
68
+
// });
69
+
// await Promise.all(
70
+
// res.pages.map(async (page) => {
71
+
// await Promise.all(
72
+
// page.feed.map(async (feedviewpost) => {
73
+
// if (!feedviewpost.post) return;
74
+
// // /*mass comment*/ console.log("preloading: ", feedviewpost.post);
75
+
// const opts = constructPostQuery(feedviewpost.post);
76
+
// try {
77
+
// await queryClient.ensureQueryData(opts);
78
+
// } catch (e) {
79
+
// // /*mass comment*/ console.log(" failed:", e);
80
+
// }
81
+
// })
82
+
// );
83
+
// })
84
+
// );
85
+
// },
13
86
component: Home,
87
+
pendingComponent: PendingHome, // PendingHome,
88
+
staticData: { keepAlive: true },
14
89
});
90
+
function PendingHome() {
91
+
return <div>loading... (prefetching your timeline)</div>;
92
+
}
15
93
16
-
function Home() {
94
+
//function Homer() {
95
+
// return <div></div>
96
+
//}
97
+
export function Home({ hidden = false }: { hidden?: boolean }) {
17
98
const {
18
99
agent,
19
-
loginStatus,
20
-
login,
100
+
status,
101
+
authMethod,
102
+
loginWithPassword,
103
+
loginWithOAuth,
21
104
logout,
22
-
loading: loadering,
23
-
authed,
24
105
} = useAuth();
25
-
const { get, set } = usePersistentStore();
26
-
const [feed, setFeed] = React.useState<any[]>([]);
27
-
const [loading, setLoading] = React.useState(true);
28
-
const [error, setError] = React.useState<string | null>(null);
106
+
const authed = !!agent?.did;
29
107
30
-
const [prefs, setPrefs] = React.useState<any>({});
31
-
React.useEffect(() => {
32
-
if (!loadering && authed && agent && agent.did) {
33
-
const run = async () => {
34
-
try {
35
-
if (!agent.did) return;
36
-
const prefs = await cachedGetPrefs({
37
-
did: agent.did,
38
-
agent,
39
-
get,
40
-
set,
41
-
});
108
+
// i dont remember why this is even here
109
+
// useEffect(() => {
110
+
// if (agent?.did) {
111
+
// store.set(authedAtom, true);
112
+
// } else {
113
+
// store.set(authedAtom, false);
114
+
// }
115
+
// }, [status, agent, authed]);
116
+
// useEffect(() => {
117
+
// if (agent) {
118
+
// // eslint-disable-next-line @typescript-eslint/ban-ts-comment
119
+
// // @ts-ignore is it just me or is the type really weird here it should be Agent not AtpAgent
120
+
// store.set(agentAtom, agent);
121
+
// } else {
122
+
// store.set(agentAtom, null);
123
+
// }
124
+
// }, [status, agent, authed]);
42
125
43
-
console.log("alistoffeeds", prefs);
44
-
setPrefs(prefs || {});
45
-
} catch (err) {
46
-
console.error("alistoffeeds Fetch error in preferences effect:", err);
47
-
}
48
-
};
126
+
//const { get, set } = usePersistentStore();
127
+
// const [feed, setFeed] = React.useState<any[]>([]);
128
+
// const [loading, setLoading] = React.useState(true);
129
+
// const [error, setError] = React.useState<string | null>(null);
49
130
50
-
run();
51
-
}
52
-
}, [loadering, authed, agent]);
131
+
// const [prefs, setPrefs] = React.useState<any>({});
132
+
// React.useEffect(() => {
133
+
// if (!loadering && authed && agent && agent.did) {
134
+
// const run = async () => {
135
+
// try {
136
+
// if (!agent.did) return;
137
+
// const prefs = await cachedGetPrefs({
138
+
// did: agent.did,
139
+
// agent,
140
+
// get,
141
+
// set,
142
+
// });
53
143
54
-
const savedFeedsPref = React.useMemo(() => {
55
-
if (!prefs?.preferences) return null;
56
-
return prefs.preferences.find(
57
-
(p: any) => p?.$type === "app.bsky.actor.defs#savedFeedsPrefV2",
144
+
// // /*mass comment*/ console.log("alistoffeeds", prefs);
145
+
// setPrefs(prefs || {});
146
+
// } catch (err) {
147
+
// console.error("alistoffeeds Fetch error in preferences effect:", err);
148
+
// }
149
+
// };
150
+
151
+
// run();
152
+
// }
153
+
// }, [loadering, authed, agent]);
154
+
155
+
// const savedFeedsPref = React.useMemo(() => {
156
+
// if (!prefs?.preferences) return null;
157
+
// return prefs.preferences.find(
158
+
// (p: any) => p?.$type === "app.bsky.actor.defs#savedFeedsPrefV2",
159
+
// );
160
+
// }, [prefs]);
161
+
162
+
// const savedFeeds = savedFeedsPref?.items || [];
163
+
164
+
const [quickAuth, setQuickAuth] = useAtom(quickAuthAtom);
165
+
const isAuthRestoring = quickAuth ? status === "loading" : false;
166
+
167
+
const identityresultmaybe = useQueryIdentity(!isAuthRestoring ? agent?.did : undefined);
168
+
const identity = identityresultmaybe?.data;
169
+
170
+
const prefsresultmaybe = useQueryPreferences({
171
+
agent: !isAuthRestoring ? (agent ?? undefined) : undefined,
172
+
pdsUrl: !isAuthRestoring ? (identity?.pds) : undefined,
173
+
});
174
+
const prefs = prefsresultmaybe?.data;
175
+
176
+
const savedFeeds = React.useMemo(() => {
177
+
const savedFeedsPref = prefs?.preferences?.find(
178
+
(p: any) => p?.$type === "app.bsky.actor.defs#savedFeedsPrefV2"
58
179
);
180
+
return savedFeedsPref?.items || [];
59
181
}, [prefs]);
60
182
61
-
const savedFeeds = savedFeedsPref?.items || [];
62
-
63
-
const [selectedFeed, setSelectedFeed] = React.useState<string | null>(null);
183
+
const [persistentSelectedFeed, setPersistentSelectedFeed] = useAtom(selectedFeedUriAtom);
184
+
const [unauthedSelectedFeed, setUnauthedSelectedFeed] = useState(persistentSelectedFeed);
185
+
const selectedFeed = agent?.did
186
+
? persistentSelectedFeed
187
+
: unauthedSelectedFeed;
188
+
const setSelectedFeed = agent?.did
189
+
? setPersistentSelectedFeed
190
+
: setUnauthedSelectedFeed;
64
191
192
+
// /*mass comment*/ console.log("my selectedFeed is: ", selectedFeed);
65
193
React.useEffect(() => {
66
194
const fallbackFeed =
67
-
"at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/wh-hot";
195
+
"at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot";
68
196
if (authed) {
197
+
if (selectedFeed) return;
69
198
if (savedFeeds.length > 0) {
70
199
setSelectedFeed((prev) =>
71
200
prev && savedFeeds.some((f: any) => f.value === prev)
72
201
? prev
73
-
: savedFeeds[0].value,
202
+
: savedFeeds[0].value
74
203
);
75
204
} else {
205
+
if (selectedFeed) return;
76
206
setSelectedFeed(fallbackFeed);
77
207
}
78
208
} else {
209
+
if (selectedFeed) return;
79
210
setSelectedFeed(fallbackFeed);
80
211
}
81
-
}, [savedFeeds, authed]);
212
+
}, [savedFeeds, authed, setSelectedFeed]);
82
213
83
-
React.useEffect(() => {
84
-
if (loadering || !selectedFeed) return;
214
+
// React.useEffect(() => {
215
+
// if (loadering || !selectedFeed) return;
85
216
86
-
let ignore = false;
217
+
// let ignore = false;
87
218
88
-
const run = async () => {
89
-
setLoading(true);
90
-
setError(null);
219
+
// const run = async () => {
220
+
// setLoading(true);
221
+
// setError(null);
91
222
92
-
try {
93
-
if (authed && agent) {
94
-
if (!agent.did) return;
223
+
// try {
224
+
// if (authed && agent) {
225
+
// if (!agent.did) return;
95
226
96
-
const pdsurl = await cachedResolveIdentity({
97
-
didOrHandle: agent.did,
98
-
get,
99
-
set,
100
-
});
227
+
// const pdsurl = await cachedResolveIdentity({
228
+
// didOrHandle: agent.did,
229
+
// get,
230
+
// set,
231
+
// });
101
232
102
-
const fetchstringcomplex = `${pdsurl.pdsUrl}/xrpc/app.bsky.feed.getFeedSkeleton?feed=${selectedFeed}`;
103
-
console.log("fetching feed authed: " + fetchstringcomplex);
233
+
// const fetchstringcomplex = `${pdsurl.pdsUrl}/xrpc/app.bsky.feed.getFeedSkeleton?feed=${selectedFeed}`;
234
+
// // /*mass comment*/ console.log("fetching feed authed: " + fetchstringcomplex);
104
235
105
-
const feeddef = await cachedGetRecord({
106
-
atUri: selectedFeed,
107
-
get,
108
-
set,
109
-
});
236
+
// const feeddef = await cachedGetRecord({
237
+
// atUri: selectedFeed,
238
+
// get,
239
+
// set,
240
+
// });
110
241
111
-
const feedservicedid = feeddef.value.did;
242
+
// const feedservicedid = feeddef.value.did;
112
243
113
-
const res = await agent.fetchHandler(fetchstringcomplex, {
114
-
method: "GET",
115
-
headers: {
116
-
"atproto-proxy": `${feedservicedid}#bsky_fg`,
117
-
"Content-Type": "application/json",
118
-
},
119
-
});
244
+
// const res = await agent.fetchHandler(fetchstringcomplex, {
245
+
// method: "GET",
246
+
// headers: {
247
+
// "atproto-proxy": `${feedservicedid}#bsky_fg`,
248
+
// "Content-Type": "application/json",
249
+
// },
250
+
// });
120
251
121
-
if (!res.ok) throw new Error("Failed to fetch feed");
122
-
const data = await res.json();
252
+
// if (!res.ok) throw new Error("Failed to fetch feed");
253
+
// const data = await res.json();
123
254
124
-
if (!ignore) setFeed(data.feed || []);
125
-
} else {
126
-
console.log("falling back");
127
-
// always use fallback feed for not logged in
128
-
const fallbackFeed =
129
-
"at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot";
130
-
// const feeddef = await cachedGetRecord({
131
-
// atUri: fallbackFeed,
132
-
// get,
133
-
// set,
134
-
// });
255
+
// if (!ignore) setFeed(data.feed || []);
256
+
// } else {
257
+
// // /*mass comment*/ console.log("falling back");
258
+
// // always use fallback feed for not logged in
259
+
// const fallbackFeed =
260
+
// "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot";
261
+
// // const feeddef = await cachedGetRecord({
262
+
// // atUri: fallbackFeed,
263
+
// // get,
264
+
// // set,
265
+
// // });
135
266
136
-
//const feedservicedid = "did:web:discover.bsky.app" //feeddef.did;
137
-
const fetchstringsimple = `https://discover.bsky.app/xrpc/app.bsky.feed.getFeedSkeleton?feed=${fallbackFeed}`;
138
-
console.log("fetching feed unauthed: " + fetchstringsimple);
267
+
// //const feedservicedid = "did:web:discover.bsky.app" //feeddef.did;
268
+
// const fetchstringsimple = `https://discover.bsky.app/xrpc/app.bsky.feed.getFeedSkeleton?feed=${fallbackFeed}`;
269
+
// // /*mass comment*/ console.log("fetching feed unauthed: " + fetchstringsimple);
139
270
140
-
const res = await fetch(fetchstringsimple);
141
-
if (!res.ok) throw new Error("Failed to fetch feed");
142
-
const data = await res.json();
271
+
// const res = await fetch(fetchstringsimple);
272
+
// if (!res.ok) throw new Error("Failed to fetch feed");
273
+
// const data = await res.json();
143
274
144
-
if (!ignore) setFeed(data.feed || []);
145
-
}
146
-
} catch (e) {
147
-
if (!ignore) {
148
-
if (e instanceof Error) {
149
-
setError(e.message);
150
-
} else {
151
-
setError("Unknown error");
152
-
}
153
-
}
154
-
} finally {
155
-
if (!ignore) setLoading(false);
156
-
}
157
-
};
275
+
// if (!ignore) setFeed(data.feed || []);
276
+
// }
277
+
// } catch (e) {
278
+
// if (!ignore) {
279
+
// if (e instanceof Error) {
280
+
// setError(e.message);
281
+
// } else {
282
+
// setError("Unknown error");
283
+
// }
284
+
// }
285
+
// } finally {
286
+
// if (!ignore) setLoading(false);
287
+
// }
288
+
// };
158
289
159
-
run();
290
+
// run();
160
291
292
+
// return () => {
293
+
// ignore = true;
294
+
// };
295
+
// }, [authed, agent, loadering, selectedFeed, get, set]);
296
+
297
+
const [scrollPositions, setScrollPositions] = useAtom(
298
+
feedScrollPositionsAtom
299
+
);
300
+
301
+
const scrollPositionsRef = React.useRef(scrollPositions);
302
+
303
+
React.useEffect(() => {
304
+
scrollPositionsRef.current = scrollPositions;
305
+
}, [scrollPositions]);
306
+
307
+
useLayoutEffect(() => {
308
+
if (isAuthRestoring) return;
309
+
const savedPosition = scrollPositions[selectedFeed ?? "null"] ?? 0;
310
+
311
+
window.scrollTo({ top: savedPosition, behavior: "instant" });
312
+
// eslint-disable-next-line react-hooks/exhaustive-deps
313
+
}, [selectedFeed, isAuthRestoring]);
314
+
315
+
useLayoutEffect(() => {
316
+
if (!selectedFeed || isAuthRestoring) return;
317
+
318
+
const handleScroll = () => {
319
+
scrollPositionsRef.current = {
320
+
...scrollPositionsRef.current,
321
+
[selectedFeed]: window.scrollY,
322
+
};
323
+
};
324
+
325
+
window.addEventListener("scroll", handleScroll, { passive: true });
161
326
return () => {
162
-
ignore = true;
327
+
window.removeEventListener("scroll", handleScroll);
328
+
329
+
setScrollPositions(scrollPositionsRef.current);
163
330
};
164
-
}, [authed, agent, loadering, selectedFeed, get, set]);
331
+
}, [isAuthRestoring, selectedFeed, setScrollPositions]);
332
+
333
+
const feedGengetrecordquery = useQueryArbitrary(!isAuthRestoring ? selectedFeed ?? undefined : undefined);
334
+
const feedServiceDid = !isAuthRestoring ? (feedGengetrecordquery?.data?.value as any)?.did as string | undefined : undefined;
335
+
336
+
// const {
337
+
// data: feedData,
338
+
// isLoading: isFeedLoading,
339
+
// error: feedError,
340
+
// } = useQueryFeedSkeleton({
341
+
// feedUri: selectedFeed!,
342
+
// agent: agent ?? undefined,
343
+
// isAuthed: authed ?? false,
344
+
// pdsUrl: identity?.pds,
345
+
// feedServiceDid: feedServiceDid,
346
+
// });
347
+
348
+
// const feed = feedData?.feed || [];
349
+
350
+
const isReadyForAuthedFeed = !isAuthRestoring && authed && agent && identity?.pds && feedServiceDid;
351
+
const isReadyForUnauthedFeed = !isAuthRestoring && !authed && selectedFeed;
352
+
353
+
354
+
const [isAtTop] = useAtom(isAtTopAtom);
165
355
166
356
return (
167
-
<div className="flex flex-col divide-y divide-gray-200 dark:divide-gray-800">
168
-
<div className="flex items-center gap-2 px-4 py-2 h-[52px] sticky top-0 bg-white dark:bg-gray-950 z-10 border-b border-gray-200 dark:border-gray-700 overflow-x-auto overflow-y-hidden scroll-thin">
169
-
{savedFeeds.length > 0 ? (
170
-
savedFeeds.map((item: any, idx: number) => {
357
+
<div
358
+
className={`relative flex flex-col divide-y divide-gray-200 dark:divide-gray-800 ${hidden && "hidden"}`}
359
+
>
360
+
{!isAuthRestoring && savedFeeds.length > 0 ? (
361
+
<div className={`flex items-center px-4 py-2 h-[52px] sticky top-0 bg-[var(--header-bg-light)] dark:bg-[var(--header-bg-dark)] ${!isAtTop && "shadow-sm"} sm:shadow-none sm:bg-white sm:dark:bg-gray-950 z-10 border-0 sm:border-b border-gray-200 dark:border-gray-700 overflow-x-auto overflow-y-hidden scroll-thin`}>
362
+
{savedFeeds.map((item: any, idx: number) => {
171
363
const label = item.value.split("/").pop() || item.value;
172
364
const isActive = selectedFeed === item.value;
173
365
return (
···
175
367
key={item.value || idx}
176
368
className={`px-3 py-1 rounded-full whitespace-nowrap font-medium transition-colors ${
177
369
isActive
178
-
? "bg-gray-600 text-white"
179
-
: item.pinned
180
-
? "bg-gray-200 text-gray-700 dark:bg-gray-700 dark:text-gray-200"
181
-
: "bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-200"
370
+
? "text-gray-900 dark:text-gray-100 hover:bg-gray-300 dark:bg-gray-700 bg-gray-200 hover:dark:bg-gray-600"
371
+
: "text-gray-600 dark:text-gray-400 hover:bg-gray-100 hover:dark:bg-gray-800"
372
+
// ? "bg-gray-500 text-white"
373
+
// : item.pinned
374
+
// ? "bg-gray-200 text-gray-700 dark:bg-gray-700 dark:text-gray-200"
375
+
// : "bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-200"
182
376
}`}
183
377
onClick={() => setSelectedFeed(item.value)}
184
378
title={item.value}
185
379
>
186
380
{label}
187
381
{item.pinned && (
188
-
<span className="ml-1 text-xs text-gray-700 dark:text-gray-200">
382
+
<span
383
+
className={`ml-1 text-xs ${
384
+
isActive
385
+
? "text-gray-900 dark:text-gray-100"
386
+
: "text-gray-600 dark:text-gray-400"
387
+
}`}
388
+
>
189
389
โ
190
390
</span>
191
391
)}
192
392
</button>
193
393
);
194
-
})
195
-
) : (
196
-
<span className="text-xl font-bold ml-2">Home</span>
197
-
)}
198
-
</div>
199
-
{loading && <div className="p-4 text-gray-500">Loading...</div>}
200
-
{error && <div className="p-4 text-red-500">{error}</div>}
201
-
{!loading && !error && feed.length === 0 && (
202
-
<div className="p-4 text-gray-500">No posts found.</div>
394
+
})}
395
+
</div>
396
+
) : (
397
+
// <span className="text-xl font-bold ml-2">Home</span>
398
+
<Header title="Home" />
203
399
)}
204
-
{feed.map((item, i) => (
400
+
{/* {isFeedLoading && <div className="p-4 text-gray-500">Loading...</div>}
401
+
{feedError && <div className="p-4 text-red-500">{feedError.message}</div>}
402
+
{!isFeedLoading && !feedError && feed.length === 0 && (
403
+
<div className="p-4 text-gray-500">No posts found.</div>
404
+
)} */}
405
+
{/* {feed.map((item, i) => (
205
406
<UniversalPostRendererATURILoader
206
407
key={item.post || i}
207
408
atUri={item.post}
208
409
/>
209
-
))}
410
+
))} */}
411
+
412
+
{isAuthRestoring || authed && (!identity?.pds || !feedServiceDid) && (
413
+
<div className="p-4 text-center text-gray-500">
414
+
Preparing your feed...
415
+
</div>
416
+
)}
417
+
418
+
{!isAuthRestoring && (isReadyForAuthedFeed || isReadyForUnauthedFeed) ? (
419
+
<InfiniteCustomFeed
420
+
key={selectedFeed!}
421
+
feedUri={selectedFeed!}
422
+
pdsUrl={identity?.pds}
423
+
feedServiceDid={feedServiceDid}
424
+
/>
425
+
) : (
426
+
<div className="p-4 text-center text-gray-500">
427
+
Loading.......
428
+
</div>
429
+
)}
430
+
{/* {false && restoringScrollPosition && (
431
+
<div className="fixed top-1/2 left-1/2 right-1/2">
432
+
restoringScrollPosition
433
+
</div>
434
+
)} */}
210
435
</div>
211
436
);
212
437
}
438
+
// not even used lmaooo
213
439
214
-
export async function cachedResolveDIDWEBDOC({
215
-
didweb,
216
-
cacheTimeout = CACHE_TIMEOUT,
217
-
get,
218
-
set,
219
-
}: {
220
-
didweb: string;
221
-
cacheTimeout?: number;
222
-
get: (key: string) => any;
223
-
set: (key: string, value: string) => void;
224
-
}): Promise<any> {
225
-
const isDidInput = didweb.startsWith("did:web:");
226
-
const cacheKey = `didwebdoc:${didweb}`;
227
-
const now = Date.now();
228
-
const cached = get(cacheKey);
229
-
if (
230
-
cached &&
231
-
cached.value &&
232
-
cached.time &&
233
-
now - cached.time < cacheTimeout
234
-
) {
235
-
try {
236
-
return JSON.parse(cached.value);
237
-
} catch {}
238
-
}
239
-
const url = `https://free-fly-24.deno.dev/resolve-did-web?did=${encodeURIComponent(
240
-
didweb,
241
-
)}`;
242
-
const res = await fetch(url);
243
-
if (!res.ok) throw new Error("Failed to resolve didwebdoc");
244
-
const data = await res.json();
245
-
set(cacheKey, JSON.stringify(data));
246
-
if (!isDidInput && data.did) {
247
-
set(`didwebdoc:${data.did}`, JSON.stringify(data));
248
-
}
249
-
return data;
250
-
}
440
+
// export async function cachedResolveDIDWEBDOC({
441
+
// didweb,
442
+
// cacheTimeout = CACHE_TIMEOUT,
443
+
// get,
444
+
// set,
445
+
// }: {
446
+
// didweb: string;
447
+
// cacheTimeout?: number;
448
+
// get: (key: string) => any;
449
+
// set: (key: string, value: string) => void;
450
+
// }): Promise<any> {
451
+
// const isDidInput = didweb.startsWith("did:web:");
452
+
// const cacheKey = `didwebdoc:${didweb}`;
453
+
// const now = Date.now();
454
+
// const cached = get(cacheKey);
455
+
// if (
456
+
// cached &&
457
+
// cached.value &&
458
+
// cached.time &&
459
+
// now - cached.time < cacheTimeout
460
+
// ) {
461
+
// try {
462
+
// return JSON.parse(cached.value);
463
+
// } catch (_e) {/* whatever*/ }
464
+
// }
465
+
// const url = `https://free-fly-24.deno.dev/resolve-did-web?did=${encodeURIComponent(
466
+
// didweb
467
+
// )}`;
468
+
// const res = await fetch(url);
469
+
// if (!res.ok) throw new Error("Failed to resolve didwebdoc");
470
+
// const data = await res.json();
471
+
// set(cacheKey, JSON.stringify(data));
472
+
// if (!isDidInput && data.did) {
473
+
// set(`didwebdoc:${data.did}`, JSON.stringify(data));
474
+
// }
475
+
// return data;
476
+
// }
251
477
252
-
export async function cachedGetPrefs({
253
-
did,
254
-
agent,
255
-
get,
256
-
set,
257
-
cacheTimeout = CACHE_TIMEOUT,
258
-
}: {
259
-
did: string;
260
-
agent: any; // or type properly if available
261
-
get: (key: string) => any;
262
-
set: (key: string, value: string) => void;
263
-
cacheTimeout?: number;
264
-
}): Promise<any> {
265
-
const cacheKey = `prefs:${did}`;
266
-
const cached = get(cacheKey);
267
-
const now = Date.now();
478
+
// export async function cachedGetPrefs({
479
+
// did,
480
+
// agent,
481
+
// get,
482
+
// set,
483
+
// cacheTimeout = CACHE_TIMEOUT,
484
+
// }: {
485
+
// did: string;
486
+
// agent: any; // or type properly if available
487
+
// get: (key: string) => any;
488
+
// set: (key: string, value: string) => void;
489
+
// cacheTimeout?: number;
490
+
// }): Promise<any> {
491
+
// const cacheKey = `prefs:${did}`;
492
+
// const cached = get(cacheKey);
493
+
// const now = Date.now();
268
494
269
-
if (
270
-
cached &&
271
-
cached.value &&
272
-
cached.time &&
273
-
now - cached.time < cacheTimeout
274
-
) {
275
-
try {
276
-
return JSON.parse(cached.value);
277
-
} catch {
278
-
// fall through to fetch
279
-
}
280
-
}
495
+
// if (
496
+
// cached &&
497
+
// cached.value &&
498
+
// cached.time &&
499
+
// now - cached.time < cacheTimeout
500
+
// ) {
501
+
// try {
502
+
// return JSON.parse(cached.value);
503
+
// } catch {
504
+
// // fall through to fetch
505
+
// }
506
+
// }
281
507
282
-
const resolved = await cachedResolveIdentity({
283
-
didOrHandle: did,
284
-
get,
285
-
set,
286
-
});
508
+
// const resolved = await cachedResolveIdentity({
509
+
// didOrHandle: did,
510
+
// get,
511
+
// set,
512
+
// });
287
513
288
-
if (!resolved?.pdsUrl) throw new Error("Missing resolved PDS info");
514
+
// if (!resolved?.pdsUrl) throw new Error("Missing resolved PDS info");
289
515
290
-
const fetchUrl = `${resolved.pdsUrl}/xrpc/app.bsky.actor.getPreferences`;
516
+
// const fetchUrl = `${resolved.pdsUrl}/xrpc/app.bsky.actor.getPreferences`;
291
517
292
-
const res = await agent.fetchHandler(fetchUrl, {
293
-
method: "GET",
294
-
headers: {
295
-
"Content-Type": "application/json",
296
-
},
297
-
});
518
+
// const res = await agent.fetchHandler(fetchUrl, {
519
+
// method: "GET",
520
+
// headers: {
521
+
// "Content-Type": "application/json",
522
+
// },
523
+
// });
298
524
299
-
if (!res.ok) throw new Error(`Failed to fetch preferences: ${res.status}`);
525
+
// if (!res.ok) throw new Error(`Failed to fetch preferences: ${res.status}`);
300
526
301
-
const text = await res.text();
527
+
// const text = await res.text();
302
528
303
-
let data: any;
304
-
try {
305
-
data = JSON.parse(text);
306
-
} catch (err) {
307
-
console.error("Failed to parse preferences JSON:", err);
308
-
throw err;
309
-
}
529
+
// let data: any;
530
+
// try {
531
+
// data = JSON.parse(text);
532
+
// } catch (err) {
533
+
// console.error("Failed to parse preferences JSON:", err);
534
+
// throw err;
535
+
// }
310
536
311
-
set(cacheKey, JSON.stringify(data));
312
-
return data;
313
-
}
537
+
// set(cacheKey, JSON.stringify(data));
538
+
// return data;
539
+
// }
+31
-26
src/routes/notifications.tsx
+31
-26
src/routes/notifications.tsx
···
1
1
import { createFileRoute } from "@tanstack/react-router";
2
-
import React, { useEffect, useState, useRef } from "react";
3
-
import { useAuth } from "~/providers/PassAuthProvider";
4
-
import { usePersistentStore } from "~/providers/PersistentStoreProvider";
2
+
import { useAtom } from "jotai";
3
+
import React, { useEffect, useRef,useState } from "react";
4
+
5
+
import { useAuth } from "~/providers/UnifiedAuthProvider";
6
+
import { constellationURLAtom } from "~/utils/atoms";
5
7
6
8
const HANDLE_DID_CACHE_TIMEOUT = 60 * 60 * 1000; // 1 hour
7
9
···
10
12
});
11
13
12
14
function NotificationsComponent() {
13
-
console.log("NotificationsComponent render");
14
-
const { agent, authed, loading: authLoading } = useAuth();
15
-
const { get, set } = usePersistentStore();
15
+
// /*mass comment*/ console.log("NotificationsComponent render");
16
+
const { agent, status } = useAuth();
17
+
const authed = !!agent?.did;
18
+
const authLoading = status === "loading";
16
19
const [did, setDid] = useState<string | null>(null);
17
20
const [resolving, setResolving] = useState(false);
18
21
const [error, setError] = useState<string | null>(null);
···
28
31
}, [authed, agent, authLoading]);
29
32
30
33
async function handleSubmit() {
31
-
console.log("handleSubmit called");
34
+
// /*mass comment*/ console.log("handleSubmit called");
32
35
setError(null);
33
36
setResponses([null, null, null]);
34
37
const value = inputRef.current?.value?.trim() || "";
···
41
44
setResolving(true);
42
45
const cacheKey = `handleDid:${value}`;
43
46
const now = Date.now();
44
-
const cached = await get(cacheKey);
45
-
if (
46
-
cached &&
47
-
cached.value &&
48
-
cached.time &&
49
-
now - cached.time < HANDLE_DID_CACHE_TIMEOUT
50
-
) {
51
-
try {
52
-
const data = JSON.parse(cached.value);
53
-
setDid(data.did);
54
-
setResolving(false);
55
-
return;
56
-
} catch {}
57
-
}
47
+
const cached = undefined // await get(cacheKey);
48
+
// if (
49
+
// cached &&
50
+
// cached.value &&
51
+
// cached.time &&
52
+
// now - cached.time < HANDLE_DID_CACHE_TIMEOUT
53
+
// ) {
54
+
// try {
55
+
// const data = JSON.parse(cached.value);
56
+
// setDid(data.did);
57
+
// setResolving(false);
58
+
// return;
59
+
// } catch {}
60
+
// }
58
61
try {
59
62
const url = `https://free-fly-24.deno.dev/?handle=${encodeURIComponent(value)}`;
60
63
const res = await fetch(url);
61
64
if (!res.ok) throw new Error("Failed to resolve handle");
62
65
const data = await res.json();
63
-
set(cacheKey, JSON.stringify(data));
66
+
//set(cacheKey, JSON.stringify(data));
64
67
setDid(data.did);
65
68
} catch (e: any) {
66
69
setError("Failed to resolve handle: " + (e?.message || e));
···
69
72
}
70
73
}
71
74
75
+
const [constellationURL] = useAtom(constellationURLAtom)
76
+
72
77
useEffect(() => {
73
78
if (!did) return;
74
79
setLoading(true);
75
80
setError(null);
76
81
const urls = [
77
-
`https://constellation.microcosm.blue/links?target=${encodeURIComponent(did)}&collection=app.bsky.feed.post&path=.facets[app.bsky.richtext.facet].features[app.bsky.richtext.facet%23mention].did`,
78
-
`https://constellation.microcosm.blue/links?target=${encodeURIComponent(did)}&collection=app.bsky.feed.post&path=.facets[].features[app.bsky.richtext.facet%23mention].did`,
79
-
`https://constellation.microcosm.blue/links?target=${encodeURIComponent(did)}&collection=app.bsky.graph.follow&path=.subject`,
82
+
`https://${constellationURL}/links?target=${encodeURIComponent(did)}&collection=app.bsky.feed.post&path=.facets[app.bsky.richtext.facet].features[app.bsky.richtext.facet%23mention].did`,
83
+
`https://${constellationURL}/links?target=${encodeURIComponent(did)}&collection=app.bsky.feed.post&path=.facets[].features[app.bsky.richtext.facet%23mention].did`,
84
+
`https://${constellationURL}/links?target=${encodeURIComponent(did)}&collection=app.bsky.graph.follow&path=.subject`,
80
85
];
81
86
let ignore = false;
82
87
Promise.all(
···
94
99
} catch (e: any) {
95
100
return { error: e?.message || String(e) };
96
101
}
97
-
}),
102
+
})
98
103
)
99
104
.then((results) => {
100
105
if (!ignore) setResponses(results);
+310
-368
src/routes/profile.$did/index.tsx
+310
-368
src/routes/profile.$did/index.tsx
···
1
-
import { createFileRoute, Link } from "@tanstack/react-router";
2
-
import React from "react";
3
-
import { UniversalPostRendererATURILoader } from "~/components/UniversalPostRenderer";
4
-
import { usePersistentStore } from "~/providers/PersistentStoreProvider";
1
+
import { RichText } from "@atproto/api";
2
+
import { useQueryClient } from "@tanstack/react-query";
3
+
import { createFileRoute, useNavigate } from "@tanstack/react-router";
4
+
import { useAtom } from "jotai";
5
+
import React, { type ReactNode, useEffect, useState } from "react";
5
6
6
-
const HANDLE_DID_CACHE_TIMEOUT = 60 * 60 * 1000; // 1 hour
7
-
const CACHE_TIMEOUT = 5 * 60 * 1000; // 5 minutes
7
+
import { Header } from "~/components/Header";
8
+
import { Button } from "~/components/radix-m3-rd/Button";
9
+
import {
10
+
renderTextWithFacets,
11
+
UniversalPostRendererATURILoader,
12
+
} from "~/components/UniversalPostRenderer";
13
+
import { useAuth } from "~/providers/UnifiedAuthProvider";
14
+
import { imgCDNAtom } from "~/utils/atoms";
15
+
import {
16
+
toggleFollow,
17
+
useGetFollowState,
18
+
useGetOneToOneState,
19
+
} from "~/utils/followState";
20
+
import {
21
+
useInfiniteQueryAuthorFeed,
22
+
useQueryIdentity,
23
+
useQueryProfile,
24
+
} from "~/utils/useQuery";
8
25
9
26
export const Route = createFileRoute("/profile/$did/")({
10
27
component: ProfileComponent,
11
28
});
12
29
13
30
function ProfileComponent() {
31
+
// booo bad this is not always the did it might be a handle, use identity.did instead
14
32
const { did } = Route.useParams();
15
-
const { get, set } = usePersistentStore();
16
-
const [resolvedDid, setResolvedDid] = React.useState<string | null>(null);
17
-
const [resolvedHandle, setResolvedHandle] = React.useState<string | null>(
18
-
null,
19
-
);
20
-
const [loading, setLoading] = React.useState(false);
21
-
const [error, setError] = React.useState<string | null>(null);
22
-
const [profile, setProfile] = React.useState<any>(null);
23
-
const [posts, setPosts] = React.useState<any[]>([]);
24
-
const [postsLoading, setPostsLoading] = React.useState(false);
25
-
const [cursor, setCursor] = React.useState<string | null>(null);
26
-
const [hasMore, setHasMore] = React.useState(true);
27
-
const [postsCached, setPostsCached] = React.useState(false);
33
+
const navigate = useNavigate();
34
+
const queryClient = useQueryClient();
35
+
const {
36
+
data: identity,
37
+
isLoading: isIdentityLoading,
38
+
error: identityError,
39
+
} = useQueryIdentity(did);
28
40
29
-
React.useEffect(() => {
30
-
let ignore = false;
31
-
async function resolveDidIfNeeded() {
32
-
if (!did) {
33
-
setResolvedDid(null);
34
-
setResolvedHandle(null);
35
-
return;
36
-
}
37
-
if (did.startsWith("did:")) {
38
-
setResolvedDid(did);
39
-
setLoading(true);
40
-
setError(null);
41
-
const cacheKey = `handleDid:${did}`;
42
-
const now = Date.now();
43
-
const cached = await get(cacheKey);
44
-
if (
45
-
cached &&
46
-
cached.value &&
47
-
cached.time &&
48
-
now - cached.time < HANDLE_DID_CACHE_TIMEOUT
49
-
) {
50
-
try {
51
-
const data = JSON.parse(cached.value);
52
-
if (!ignore) {
53
-
setResolvedDid(data.did);
54
-
setResolvedHandle(data.handle || null);
55
-
}
56
-
setLoading(false);
57
-
return;
58
-
} catch {}
59
-
}
60
-
try {
61
-
const url = `https://free-fly-24.deno.dev/?did=${encodeURIComponent(did)}`;
62
-
const res = await fetch(url);
63
-
if (!res.ok) throw new Error("Failed to resolve DID");
64
-
const data = await res.json();
65
-
set(cacheKey, JSON.stringify(data));
66
-
if (!ignore) {
67
-
setResolvedDid(data.did);
68
-
setResolvedHandle(data.handle || null);
69
-
}
70
-
} catch (e: any) {
71
-
if (!ignore)
72
-
setError("Failed to resolve handle: " + (e?.message || e));
73
-
} finally {
74
-
setLoading(false);
75
-
}
76
-
return;
77
-
}
78
-
setLoading(true);
79
-
setError(null);
80
-
const cacheKey = `handleDid:${did}`;
81
-
const now = Date.now();
82
-
const cached = await get(cacheKey);
83
-
if (
84
-
cached &&
85
-
cached.value &&
86
-
cached.time &&
87
-
now - cached.time < HANDLE_DID_CACHE_TIMEOUT
88
-
) {
89
-
try {
90
-
const data = JSON.parse(cached.value);
91
-
if (!ignore) {
92
-
setResolvedDid(data.did);
93
-
setResolvedHandle(data.handle || did);
94
-
}
95
-
setLoading(false);
96
-
return;
97
-
} catch {}
98
-
}
99
-
try {
100
-
const url = `https://free-fly-24.deno.dev/?handle=${encodeURIComponent(did)}`;
101
-
const res = await fetch(url);
102
-
if (!res.ok) throw new Error("Failed to resolve handle");
103
-
const data = await res.json();
104
-
set(cacheKey, JSON.stringify(data));
105
-
if (!ignore) {
106
-
setResolvedDid(data.did);
107
-
setResolvedHandle(data.handle || did);
108
-
}
109
-
} catch (e: any) {
110
-
if (!ignore) setError("Failed to resolve handle: " + (e?.message || e));
111
-
} finally {
112
-
setLoading(false);
113
-
}
114
-
}
115
-
resolveDidIfNeeded();
116
-
return () => {
117
-
ignore = true;
118
-
};
119
-
}, [did, get, set]);
41
+
const resolvedDid = did.startsWith("did:") ? did : identity?.did;
42
+
const resolvedHandle = did.startsWith("did:") ? identity?.handle : did;
43
+
const pdsUrl = identity?.pds;
120
44
121
-
React.useEffect(() => {
122
-
if (!resolvedDid) return;
123
-
let ignore = false;
124
-
async function fetchProfile() {
125
-
const cacheKey = `profile:${resolvedDid}`;
126
-
const now = Date.now();
127
-
const cached = await get(cacheKey);
128
-
if (
129
-
cached &&
130
-
cached.value &&
131
-
cached.time &&
132
-
now - cached.time < CACHE_TIMEOUT
133
-
) {
134
-
try {
135
-
if (!ignore) setProfile(JSON.parse(cached.value));
136
-
return;
137
-
} catch {}
138
-
}
139
-
try {
140
-
if (!resolvedDid) return;
141
-
let resolvedRaw = await get(`handleDid:${resolvedDid}`);
142
-
let resolved: any = null;
143
-
if (
144
-
resolvedRaw &&
145
-
resolvedRaw.value &&
146
-
resolvedRaw.time &&
147
-
now - resolvedRaw.time < HANDLE_DID_CACHE_TIMEOUT
148
-
) {
149
-
try {
150
-
resolved = JSON.parse(resolvedRaw.value);
151
-
} catch {
152
-
resolved = null;
153
-
}
154
-
} else {
155
-
const url = `https://free-fly-24.deno.dev/?did=${encodeURIComponent(resolvedDid)}`;
156
-
const res = await fetch(url);
157
-
if (!res.ok) throw new Error("Failed to resolve DID");
158
-
resolved = await res.json();
159
-
set(`handleDid:${resolvedDid}`, JSON.stringify(resolved));
160
-
}
161
-
if (!resolved || !resolved.pdsUrl)
162
-
throw new Error("DID resolution failed or missing pdsUrl");
45
+
const profileUri = resolvedDid
46
+
? `at://${resolvedDid}/app.bsky.actor.profile/self`
47
+
: undefined;
48
+
const { data: profileRecord } = useQueryProfile(profileUri);
49
+
const profile = profileRecord?.value;
163
50
164
-
const profileUrl = `${resolved.pdsUrl}/xrpc/com.atproto.repo.getRecord?repo=${encodeURIComponent(resolvedDid)}&collection=app.bsky.actor.profile&rkey=self`;
165
-
const profileRes = await fetch(profileUrl);
166
-
if (!profileRes.ok) throw new Error("Failed to fetch profile");
167
-
const profileData = await profileRes.json();
168
-
if (!ignore) {
169
-
setProfile(profileData);
170
-
set(cacheKey, JSON.stringify(profileData));
171
-
}
172
-
} catch (e: any) {
173
-
if (!ignore) setError("Failed to fetch profile: " + (e?.message || e));
174
-
}
175
-
}
176
-
fetchProfile();
177
-
return () => {
178
-
ignore = true;
179
-
};
180
-
}, [resolvedDid, get, set]);
51
+
const {
52
+
data: postsData,
53
+
fetchNextPage,
54
+
hasNextPage,
55
+
isFetchingNextPage,
56
+
isLoading: arePostsLoading,
57
+
} = useInfiniteQueryAuthorFeed(resolvedDid, pdsUrl);
181
58
182
59
React.useEffect(() => {
183
-
if (!resolvedDid) return;
184
-
let ignore = false;
185
-
async function fetchPosts() {
186
-
setPostsLoading(true);
187
-
setPostsCached(false);
188
-
try {
189
-
if (!resolvedDid) return;
190
-
let resolvedRaw = await get(`handleDid:${resolvedDid}`);
191
-
let resolved: any = null;
192
-
const now = Date.now();
193
-
if (
194
-
resolvedRaw &&
195
-
resolvedRaw.value &&
196
-
resolvedRaw.time &&
197
-
now - resolvedRaw.time < HANDLE_DID_CACHE_TIMEOUT
198
-
) {
199
-
try {
200
-
resolved = JSON.parse(resolvedRaw.value);
201
-
} catch {
202
-
resolved = null;
60
+
if (postsData) {
61
+
postsData.pages.forEach((page) => {
62
+
page.records.forEach((record) => {
63
+
if (!queryClient.getQueryData(["post", record.uri])) {
64
+
queryClient.setQueryData(["post", record.uri], record);
203
65
}
204
-
} else {
205
-
const url = `https://free-fly-24.deno.dev/?did=${encodeURIComponent(resolvedDid)}`;
206
-
const res = await fetch(url);
207
-
if (!res.ok) throw new Error("Failed to resolve DID");
208
-
resolved = await res.json();
209
-
set(`handleDid:${resolvedDid}`, JSON.stringify(resolved));
210
-
}
211
-
if (!resolved || !resolved.pdsUrl)
212
-
throw new Error("DID resolution failed or missing pdsUrl");
66
+
});
67
+
});
68
+
}
69
+
}, [postsData, queryClient]);
213
70
214
-
const postsUrl = `${resolved.pdsUrl}/xrpc/com.atproto.repo.listRecords?repo=${resolvedDid}&collection=app.bsky.feed.post${cursor && false ? `&cursor=${cursor}` : ""}&limit=20`;
215
-
const postsRes = await fetch(postsUrl);
216
-
if (!postsRes.ok) throw new Error("Failed to fetch posts");
217
-
const postsData = await postsRes.json();
218
-
219
-
if (postsData.records) {
220
-
await Promise.all(
221
-
postsData.records.map(async (post: any) => {
222
-
if (post.uri && post.value) {
223
-
const postCacheKey = `record:${post.uri}`;
224
-
console.log(
225
-
"caching post",
226
-
postCacheKey,
227
-
JSON.stringify(post, null, 2),
228
-
);
229
-
await set(postCacheKey, JSON.stringify(post));
230
-
}
231
-
}),
232
-
);
233
-
}
71
+
const posts = React.useMemo(
72
+
() => postsData?.pages.flatMap((page) => page.records) ?? [],
73
+
[postsData]
74
+
);
234
75
235
-
if (!ignore) {
236
-
setPosts((prev) =>
237
-
cursor ? [...prev, ...postsData.records] : postsData.records,
238
-
);
239
-
setCursor(postsData.cursor || null);
240
-
setHasMore(postsData.records.length === 20);
241
-
setPostsCached(true);
242
-
}
243
-
} catch (e: any) {
244
-
if (!ignore) setError("Failed to fetch posts: " + (e?.message || e));
245
-
} finally {
246
-
if (!ignore) setPostsLoading(false);
247
-
}
248
-
}
249
-
fetchPosts();
250
-
return () => {
251
-
ignore = true;
252
-
};
253
-
}, [resolvedDid, cursor, get, set]);
76
+
const [imgcdn] = useAtom(imgCDNAtom);
254
77
255
-
function getAvatarUrl(profile: any) {
256
-
const link = profile?.value?.avatar?.ref?.["$link"];
78
+
function getAvatarUrl(p: typeof profile) {
79
+
const link = p?.avatar?.ref?.["$link"];
257
80
if (!link || !resolvedDid) return null;
258
-
return `https://cdn.bsky.app/img/avatar/plain/${resolvedDid}/${link}@jpeg`;
81
+
return `https://${imgcdn}/img/avatar/plain/${resolvedDid}/${link}@jpeg`;
259
82
}
260
-
function getBannerUrl(profile: any) {
261
-
const link = profile?.value?.banner?.ref?.["$link"];
83
+
function getBannerUrl(p: typeof profile) {
84
+
const link = p?.banner?.ref?.["$link"];
262
85
if (!link || !resolvedDid) return null;
263
-
return `https://cdn.bsky.app/img/banner/plain/${resolvedDid}/${link}@jpeg`;
86
+
return `https://${imgcdn}/img/banner/plain/${resolvedDid}/${link}@jpeg`;
264
87
}
265
88
266
89
const displayName =
267
-
profile?.value?.displayName ||
268
-
(resolvedHandle ? `@${resolvedHandle}` : did);
269
-
let handle: string;
270
-
if (resolvedHandle) {
271
-
handle = `@${resolvedHandle}`;
272
-
} else if (did && !did.startsWith("did:")) {
273
-
handle = `@${did}`;
274
-
} else {
275
-
handle = resolvedDid || did;
90
+
profile?.displayName || (resolvedHandle ? `@${resolvedHandle}` : did);
91
+
const handle = resolvedHandle ? `@${resolvedHandle}` : resolvedDid || did;
92
+
const description = profile?.description || "";
93
+
94
+
if (isIdentityLoading) {
95
+
return (
96
+
<div className="p-4 text-center text-gray-500">Resolving profile...</div>
97
+
);
276
98
}
277
-
const description = profile?.value?.description || "";
278
99
279
-
if (!did) return <div>Invalid profile</div>;
280
-
if (loading) return <div>Resolving handle...</div>;
281
-
if (error) return <div style={{ color: "red" }}>{error}</div>;
282
-
if (!resolvedDid) return <div>Invalid profile</div>;
100
+
if (identityError) {
101
+
return (
102
+
<div className="p-4 text-center text-red-500">
103
+
Error: {identityError.message}
104
+
</div>
105
+
);
106
+
}
107
+
108
+
if (!resolvedDid) {
109
+
return (
110
+
<div className="p-4 text-center text-gray-500">Profile not found.</div>
111
+
);
112
+
}
283
113
284
114
return (
285
115
<>
286
-
<div className="flex items-center gap-2 px-4 py-2 h-[52px] sticky top-0 bg-white dark:bg-gray-950 z-10 border-b border-gray-200 dark:border-gray-700">
116
+
<Header
117
+
title={`Profile`}
118
+
backButtonCallback={() => {
119
+
if (window.history.length > 1) {
120
+
window.history.back();
121
+
} else {
122
+
window.location.assign("/");
123
+
}
124
+
}}
125
+
/>
126
+
{/* <div className="flex gap-2 px-4 py-2 h-[52px] sticky top-0 bg-white dark:bg-gray-950 z-10 border-b border-gray-200 dark:border-gray-700">
287
127
<Link
288
128
to=".."
289
129
className="px-3 py-1 rounded hover:bg-gray-100 dark:hover:bg-gray-900 font-bold text-lg"
290
130
onClick={(e) => {
291
131
e.preventDefault();
292
-
window.history.length > 1
293
-
? window.history.back()
294
-
: window.location.assign("/");
132
+
if (window.history.length > 1) {
133
+
window.history.back()
134
+
} else {
135
+
window.location.assign("/");
136
+
}
295
137
}}
296
138
aria-label="Go back"
297
139
>
298
140
โ
299
141
</Link>
300
142
<span className="text-xl font-bold ml-2">Profile</span>
301
-
</div>
143
+
</div> */}
302
144
303
145
{/* Profile Header */}
304
-
<div
305
-
style={{
306
-
width: "100%",
307
-
maxWidth: 600,
308
-
margin: "0 auto",
309
-
boxShadow: "0 2px 12px #0002",
310
-
padding: 0,
311
-
color: "#eee",
312
-
fontFamily: "system-ui, sans-serif",
313
-
// marginTop: 20,
314
-
//background: '#181a20',
315
-
borderRadius: 16,
316
-
overflow: "hidden",
317
-
position: "relative",
318
-
}}
319
-
className="bg-gray-200 dark:bg-gray-900"
320
-
>
146
+
<div className="w-full max-w-2xl mx-auto overflow-hidden relative bg-gray-100 dark:bg-gray-900">
321
147
{/* Banner */}
322
148
<div
149
+
className="w-full h-40 bg-gray-300 dark:bg-gray-700"
323
150
style={{
324
-
width: "100%",
325
-
height: 160,
326
-
background: `#222 url(${getBannerUrl(profile)}) center/cover no-repeat`,
327
-
position: "relative",
151
+
backgroundImage: `url(${getBannerUrl(profile)})`,
152
+
backgroundSize: "cover",
153
+
backgroundPosition: "center",
328
154
}}
329
155
/>
156
+
330
157
{/* Avatar (PFP) */}
331
-
<div
332
-
style={{
333
-
position: "absolute",
334
-
left: "50%",
335
-
top: 120,
336
-
transform: "translateX(-50%)",
337
-
zIndex: 2,
338
-
borderRadius: "50%",
339
-
border: "4px solid #181a20",
340
-
boxShadow: "0 2px 8px #0006",
341
-
background: "#222",
342
-
}}
343
-
>
158
+
<div className="absolute left-[16px] top-[100px] ">
344
159
<img
345
160
src={getAvatarUrl(profile) || "/favicon.png"}
346
161
alt="avatar"
347
-
style={{
348
-
width: 112,
349
-
height: 112,
350
-
borderRadius: "50%",
351
-
objectFit: "cover",
352
-
display: "block",
353
-
}}
162
+
className="w-28 h-28 rounded-full object-cover border-4 border-white dark:border-gray-950 bg-gray-300 dark:bg-gray-700"
354
163
/>
355
164
</div>
165
+
166
+
<div className="absolute right-[16px] top-[170px] flex flex-row gap-2.5">
167
+
{/*
168
+
todo: full follow and unfollow backfill (along with partial likes backfill,
169
+
just enough for it to be useful)
170
+
also delay the backfill to be on demand because it would be pretty intense
171
+
also save it persistently
172
+
*/}
173
+
<FollowButton targetdidorhandle={did} />
174
+
<Button className="rounded-full" variant={"secondary"}>
175
+
... {/* todo: icon */}
176
+
</Button>
177
+
</div>
178
+
356
179
{/* Info Card */}
357
-
<div
358
-
style={{
359
-
marginTop: 72,
360
-
padding: "0 24px 24px 24px",
361
-
textAlign: "center",
362
-
}}
363
-
>
364
-
<div style={{ fontWeight: 700, fontSize: 24, marginBottom: 4 }}>
365
-
{displayName}
366
-
</div>
367
-
<div style={{ color: "#aaa", fontSize: 16, marginBottom: 12 }}>
180
+
<div className="mt-16 pb-2 px-4 text-gray-900 dark:text-gray-100">
181
+
<div className="font-bold text-2xl">{displayName}</div>
182
+
<div className="text-gray-500 dark:text-gray-400 text-base mb-3 flex flex-row gap-1">
183
+
<Mutual targetdidorhandle={did} />
368
184
{handle}
369
185
</div>
370
186
{description && (
371
-
<div
372
-
style={{
373
-
fontSize: 16,
374
-
lineHeight: 1.5,
375
-
color: "#ddd",
376
-
marginBottom: 20,
377
-
}}
378
-
>
379
-
{description}
187
+
<div className="text-base leading-relaxed text-gray-800 dark:text-gray-300 mb-5 whitespace-pre-wrap break-words text-[15px]">
188
+
{/* {description} */}
189
+
<RichTextRenderer key={did} description={description} />
380
190
</div>
381
191
)}
382
-
{!profile && !error && (
383
-
<div style={{ color: "#888", padding: 16 }}>Loading profile...</div>
384
-
)}
385
192
</div>
386
193
</div>
387
194
388
-
{/* Posts */}
389
-
<div style={{ maxWidth: 600, margin: "0px auto 0", padding: 0 }}>
390
-
<div
391
-
className="text-gray-500 dark:text-gray-400 text-sm font-bold"
392
-
style={{
393
-
fontSize: 18,
394
-
margin: "12px 16px 12px 16px",
395
-
fontWeight: 600,
396
-
}}
397
-
>
195
+
{/* Posts Section */}
196
+
<div className="max-w-2xl mx-auto">
197
+
<div className="text-gray-500 dark:text-gray-400 text-lg font-semibold my-3 mx-4">
398
198
Posts
399
199
</div>
400
-
<div style={{ display: "flex", flexDirection: "column", gap: 0 }}>
401
-
{postsCached &&
402
-
posts.map((post) => {
403
-
return (
404
-
<UniversalPostRendererATURILoader
405
-
key={post.uri}
406
-
atUri={post.uri}
407
-
feedviewpost={true}
408
-
/>
409
-
);
410
-
})}
200
+
<div>
201
+
{posts.map((post) => (
202
+
<UniversalPostRendererATURILoader
203
+
key={post.uri}
204
+
atUri={post.uri}
205
+
feedviewpost={true}
206
+
/>
207
+
))}
411
208
</div>
412
-
{postsLoading && (
413
-
<div style={{ color: "#888", padding: 16, textAlign: "center" }}>
414
-
Loading posts...
415
-
</div>
209
+
210
+
{/* Loading and "Load More" states */}
211
+
{arePostsLoading && posts.length === 0 && (
212
+
<div className="p-4 text-center text-gray-500">Loading posts...</div>
213
+
)}
214
+
{isFetchingNextPage && (
215
+
<div className="p-4 text-center text-gray-500">Loading more...</div>
416
216
)}
417
-
{hasMore && !postsLoading && (
217
+
{hasNextPage && !isFetchingNextPage && (
418
218
<button
419
-
onClick={() => setCursor(cursor)}
420
-
style={{
421
-
width: "100%",
422
-
padding: 12,
423
-
background: "#222",
424
-
color: "#eee",
425
-
border: "none",
426
-
borderRadius: 8,
427
-
cursor: "pointer",
428
-
fontSize: 16,
429
-
marginTop: 16,
430
-
}}
219
+
onClick={() => fetchNextPage()}
220
+
className="w-[calc(100%-2rem)] mx-4 my-4 px-4 py-2 bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-gray-200 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-700 font-semibold"
431
221
>
432
222
Load More Posts
433
223
</button>
434
224
)}
435
-
{posts.length === 0 && !postsLoading && !error && (
436
-
<div style={{ color: "#888", padding: 16, textAlign: "center" }}>
437
-
No posts found
438
-
</div>
225
+
{posts.length === 0 && !arePostsLoading && (
226
+
<div className="p-4 text-center text-gray-500">No posts found.</div>
439
227
)}
440
228
</div>
441
229
</>
442
230
);
443
231
}
232
+
233
+
export function FollowButton({
234
+
targetdidorhandle,
235
+
}: {
236
+
targetdidorhandle: string;
237
+
}) {
238
+
const { agent } = useAuth();
239
+
const { data: identity } = useQueryIdentity(targetdidorhandle);
240
+
const queryClient = useQueryClient();
241
+
242
+
const followRecords = useGetFollowState({
243
+
target: identity?.did ?? targetdidorhandle,
244
+
user: agent?.did,
245
+
});
246
+
247
+
return (
248
+
<>
249
+
{identity?.did !== agent?.did ? (
250
+
<>
251
+
{!(followRecords?.length && followRecords?.length > 0) ? (
252
+
<Button
253
+
onClick={(e) => {
254
+
e.stopPropagation();
255
+
toggleFollow({
256
+
agent: agent || undefined,
257
+
targetDid: identity?.did,
258
+
followRecords: followRecords,
259
+
queryClient: queryClient,
260
+
});
261
+
}}
262
+
>
263
+
Follow
264
+
</Button>
265
+
) : (
266
+
<Button
267
+
onClick={(e) => {
268
+
e.stopPropagation();
269
+
toggleFollow({
270
+
agent: agent || undefined,
271
+
targetDid: identity?.did,
272
+
followRecords: followRecords,
273
+
queryClient: queryClient,
274
+
});
275
+
}}
276
+
>
277
+
Unfollow
278
+
</Button>
279
+
)}
280
+
</>
281
+
) : (
282
+
<Button variant={"secondary"}>Edit Profile</Button>
283
+
)}
284
+
</>
285
+
);
286
+
}
287
+
288
+
export function Mutual({ targetdidorhandle }: { targetdidorhandle: string }) {
289
+
const { agent } = useAuth();
290
+
const { data: identity } = useQueryIdentity(targetdidorhandle);
291
+
292
+
const theyFollowYouRes = useGetOneToOneState(
293
+
agent?.did
294
+
? {
295
+
target: agent?.did,
296
+
user: identity?.did ?? targetdidorhandle,
297
+
collection: "app.bsky.graph.follow",
298
+
path: ".subject",
299
+
}
300
+
: undefined
301
+
);
302
+
303
+
const youFollowThemRes = useGetFollowState({
304
+
target: identity?.did ?? targetdidorhandle,
305
+
user: agent?.did,
306
+
});
307
+
308
+
const theyFollowYou: boolean =
309
+
!!theyFollowYouRes?.length && theyFollowYouRes.length > 0;
310
+
const youFollowThem: boolean =
311
+
!!youFollowThemRes?.length && youFollowThemRes.length > 0;
312
+
313
+
return (
314
+
<>
315
+
{/* if not self */}
316
+
{identity?.did !== agent?.did ? (
317
+
<>
318
+
{theyFollowYou ? (
319
+
<>
320
+
{youFollowThem ? (
321
+
<div className=" text-sm px-1.5 py-0.5 text-gray-500 bg-gray-200 dark:text-gray-400 dark:bg-gray-800 rounded-lg flex flex-row items-center justify-center">
322
+
mutuals
323
+
</div>
324
+
) : (
325
+
<div className=" text-sm px-1.5 py-0.5 text-gray-500 bg-gray-200 dark:text-gray-400 dark:bg-gray-800 rounded-lg flex flex-row items-center justify-center">
326
+
follows you
327
+
</div>
328
+
)}
329
+
</>
330
+
) : (
331
+
<></>
332
+
)}
333
+
</>
334
+
) : (
335
+
// lmao can someone be mutuals with themselves ??
336
+
<></>
337
+
)}
338
+
</>
339
+
);
340
+
}
341
+
342
+
export function RichTextRenderer({ description }: { description: string }) {
343
+
const [richDescription, setRichDescription] = useState<string | ReactNode[]>(
344
+
description
345
+
);
346
+
const { agent } = useAuth();
347
+
const navigate = useNavigate();
348
+
349
+
useEffect(() => {
350
+
let mounted = true;
351
+
352
+
// setRichDescription(description);
353
+
354
+
async function processRichText() {
355
+
try {
356
+
if (!agent?.did) return;
357
+
const rt = new RichText({ text: description });
358
+
await rt.detectFacets(agent);
359
+
360
+
if (!mounted) return;
361
+
362
+
if (rt.facets) {
363
+
setRichDescription(
364
+
renderTextWithFacets({ text: rt.text, facets: rt.facets, navigate })
365
+
);
366
+
} else {
367
+
setRichDescription(rt.text);
368
+
}
369
+
} catch (error) {
370
+
console.error("Failed to detect facets:", error);
371
+
if (mounted) {
372
+
setRichDescription(description);
373
+
}
374
+
}
375
+
}
376
+
377
+
processRichText();
378
+
379
+
return () => {
380
+
mounted = false;
381
+
};
382
+
}, [description, agent, navigate]);
383
+
384
+
return <>{richDescription}</>;
385
+
}
+165
src/routes/profile.$did/post.$rkey.image.$i.tsx
+165
src/routes/profile.$did/post.$rkey.image.$i.tsx
···
1
+
import {
2
+
createFileRoute,
3
+
useNavigate,
4
+
type UseNavigateResult,
5
+
} from "@tanstack/react-router";
6
+
import { useEffect, useState } from "react";
7
+
import { createPortal } from "react-dom";
8
+
9
+
import { ProfilePostComponent } from "./post.$rkey";
10
+
11
+
export const Route = createFileRoute("/profile/$did/post/$rkey/image/$i")({
12
+
component: Lightbox,
13
+
});
14
+
15
+
export type LightboxProps = {
16
+
images: { src: string; alt?: string }[];
17
+
};
18
+
19
+
function nextprev({
20
+
index,
21
+
images,
22
+
navigate,
23
+
did,
24
+
rkey,
25
+
prev,
26
+
}: {
27
+
index?: number;
28
+
images?: LightboxProps["images"];
29
+
navigate: UseNavigateResult<string>;
30
+
did: string;
31
+
rkey: string;
32
+
prev?: boolean;
33
+
}) {
34
+
const len = images?.length ?? 0;
35
+
if (len === 0) return;
36
+
37
+
const nextIndex = ((index ?? 0) + (prev ? -1 : 1) + len) % len;
38
+
39
+
navigate({
40
+
to: "/profile/$did/post/$rkey/image/$i",
41
+
params: {
42
+
did,
43
+
rkey,
44
+
i: nextIndex.toString(),
45
+
},
46
+
replace: true,
47
+
});
48
+
}
49
+
50
+
export function Lightbox() {
51
+
console.log("hey the $i route is loaded w!!!");
52
+
const { did, rkey, i } = Route.useParams();
53
+
const [images, setImages] = useState<LightboxProps["images"] | undefined>(
54
+
undefined
55
+
);
56
+
const index = Number(i);
57
+
const navigate = useNavigate();
58
+
const post = true;
59
+
const image = images?.[index] ?? undefined;
60
+
61
+
function lightboxCallback(d: LightboxProps) {
62
+
console.log("callback actually called!");
63
+
setImages(d.images);
64
+
}
65
+
66
+
useEffect(() => {
67
+
function handleKey(e: KeyboardEvent) {
68
+
if (e.key === "Escape") window.history.back();
69
+
if (e.key === "ArrowRight")
70
+
nextprev({ index, images, navigate, did, rkey });
71
+
//onNavigate((index + 1) % images.length);
72
+
if (e.key === "ArrowLeft")
73
+
nextprev({ index, images, navigate, did, rkey, prev: true });
74
+
//onNavigate((index - 1 + images.length) % images.length);
75
+
}
76
+
window.addEventListener("keydown", handleKey);
77
+
return () => window.removeEventListener("keydown", handleKey);
78
+
}, [index, navigate, did, rkey, images]);
79
+
80
+
return createPortal(
81
+
<>
82
+
{post && (
83
+
<div
84
+
onClick={(e) => {
85
+
e.stopPropagation();
86
+
e.nativeEvent.stopImmediatePropagation();
87
+
}}
88
+
className="lightbox-sidebar hidden lg:flex overscroll-none disablegutter disablescroll border-l dark:border-gray-800 was7 border-gray-300 fixed z-50 top-0 right-0 flex-col max-w-[350px] min-w-[350px] max-h-screen overflow-y-scroll dark:bg-gray-950 bg-white"
89
+
>
90
+
<ProfilePostComponent
91
+
key={`/profile/${did}/post/${rkey}`}
92
+
did={did}
93
+
rkey={rkey}
94
+
nopics
95
+
lightboxCallback={lightboxCallback}
96
+
/>
97
+
</div>
98
+
)}
99
+
<div
100
+
className="lightbox fixed inset-0 z-50 flex items-center justify-center bg-black/80 w-screen lg:w-[calc(100vw-350px)] lg:max-w-[calc(100vw-350px)]"
101
+
onClick={(e) => {
102
+
e.stopPropagation();
103
+
window.history.back();
104
+
}}
105
+
>
106
+
<img
107
+
src={image?.src}
108
+
alt={image?.alt}
109
+
className="max-h-[90%] max-w-[90%] object-contain rounded-lg shadow-lg"
110
+
onClick={(e) => e.stopPropagation()}
111
+
/>
112
+
113
+
{(images?.length ?? 0) > 1 && (
114
+
<>
115
+
<button
116
+
onClick={(e) => {
117
+
e.stopPropagation();
118
+
nextprev({ index, images, navigate, did, rkey, prev: true });
119
+
}}
120
+
className="absolute left-4 top-1/2 -translate-y-1/2 text-white text-4xl h-8 w-8 rounded-full bg-gray-900 flex items-center justify-center"
121
+
>
122
+
<svg
123
+
xmlns="http://www.w3.org/2000/svg"
124
+
width={28}
125
+
height={28}
126
+
viewBox="0 0 24 24"
127
+
>
128
+
<g fill="none" fillRule="evenodd">
129
+
<path d="M24 0v24H0V0zM12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.019-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"></path>
130
+
<path
131
+
fill="currentColor"
132
+
d="M8.293 12.707a1 1 0 0 1 0-1.414l5.657-5.657a1 1 0 1 1 1.414 1.414L10.414 12l4.95 4.95a1 1 0 0 1-1.414 1.414z"
133
+
></path>
134
+
</g>
135
+
</svg>
136
+
</button>
137
+
<button
138
+
onClick={(e) => {
139
+
e.stopPropagation();
140
+
nextprev({ index, images, navigate, did, rkey });
141
+
}}
142
+
className="absolute right-4 top-1/2 -translate-y-1/2 text-white text-4xl h-8 w-8 rounded-full bg-gray-900 flex items-center justify-center"
143
+
>
144
+
<svg
145
+
xmlns="http://www.w3.org/2000/svg"
146
+
width={28}
147
+
height={28}
148
+
viewBox="0 0 24 24"
149
+
>
150
+
<g fill="none" fillRule="evenodd">
151
+
<path d="M24 0v24H0V0zM12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.019-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"></path>
152
+
<path
153
+
fill="currentColor"
154
+
d="M15.707 11.293a1 1 0 0 1 0 1.414l-5.657 5.657a1 1 0 1 1-1.414-1.414l4.95-4.95l-4.95-4.95a1 1 0 0 1 1.414-1.414z"
155
+
></path>
156
+
</g>
157
+
</svg>
158
+
</button>
159
+
</>
160
+
)}
161
+
</div>
162
+
</>,
163
+
document.body
164
+
);
165
+
}
+482
-143
src/routes/profile.$did/post.$rkey.tsx
+482
-143
src/routes/profile.$did/post.$rkey.tsx
···
1
-
import { createFileRoute, Link } from '@tanstack/react-router';
2
-
import React from 'react';
3
-
import { UniversalPostRendererATURILoader, cachedGetRecord } from '~/components/UniversalPostRenderer';
4
-
import { usePersistentStore } from '~/providers/PersistentStoreProvider';
1
+
import { AtUri } from "@atproto/api";
2
+
import { useInfiniteQuery, useQueryClient } from "@tanstack/react-query";
3
+
import { createFileRoute, Outlet } from "@tanstack/react-router";
4
+
import { useAtom } from "jotai";
5
+
import React, { useLayoutEffect } from "react";
5
6
6
-
const HANDLE_DID_CACHE_TIMEOUT = 60 * 60 * 1000; // 1 hour
7
+
import { Header } from "~/components/Header";
8
+
import { UniversalPostRendererATURILoader } from "~/components/UniversalPostRenderer";
9
+
import { constellationURLAtom, slingshotURLAtom } from "~/utils/atoms";
10
+
//import { usePersistentStore } from '~/providers/PersistentStoreProvider';
11
+
import {
12
+
constructPostQuery,
13
+
type linksAllResponse,
14
+
type linksRecordsResponse,
15
+
useQueryConstellation,
16
+
useQueryIdentity,
17
+
useQueryPost,
18
+
yknowIReallyHateThisButWhateverGuardedConstructConstellationInfiniteQueryLinks,
19
+
} from "~/utils/useQuery";
7
20
8
-
export const Route = createFileRoute('/profile/$did/post/$rkey')({
21
+
import type { LightboxProps } from "./post.$rkey.image.$i";
22
+
23
+
//const HANDLE_DID_CACHE_TIMEOUT = 60 * 60 * 1000; // 1 hour
24
+
25
+
export const Route = createFileRoute("/profile/$did/post/$rkey")({
9
26
component: RouterWrapper,
10
27
});
11
28
12
29
function RouterWrapper() {
13
30
const { did, rkey } = Route.useParams();
14
31
15
-
return <ProfilePostComponent key={`/profile/${did}/post/${rkey}`} did={did} rkey={rkey} />;
32
+
return (
33
+
<>
34
+
<ProfilePostComponent
35
+
key={`/profile/${did}/post/${rkey}`}
36
+
did={did}
37
+
rkey={rkey}
38
+
/>
39
+
{/* <ShrinkingBox /> */}
40
+
</>
41
+
);
16
42
}
17
43
18
-
function ProfilePostComponent({ did, rkey }: { did: string; rkey: string }) {
19
-
const { get, set } = usePersistentStore();
20
-
const [resolvedDid, setResolvedDid] = React.useState<string | null>(null);
21
-
const [loading, setLoading] = React.useState(false);
22
-
const [error, setError] = React.useState<string | null>(null);
44
+
export function ProfilePostComponent({
45
+
did,
46
+
rkey,
47
+
nopics,
48
+
lightboxCallback,
49
+
}: {
50
+
did: string;
51
+
rkey: string;
52
+
nopics?: boolean;
53
+
lightboxCallback?: (d: LightboxProps) => void;
54
+
}) {
55
+
//const { get, set } = usePersistentStore();
56
+
const queryClient = useQueryClient();
57
+
// const [resolvedDid, setResolvedDid] = React.useState<string | null>(null);
58
+
// const [loading, setLoading] = React.useState(false);
59
+
// const [error, setError] = React.useState<string | null>(null);
60
+
61
+
// const [mainPost, setMainPost] = React.useState<any | null>(null);
62
+
// const [parents, setParents] = React.useState<any[]>([]);
63
+
// const [parentsLoading, setParentsLoading] = React.useState(false);
64
+
// const [replies, setReplies] = React.useState<any[]>([]);
65
+
66
+
// React.useEffect(() => {
67
+
// let ignore = false;
68
+
// async function resolveDidIfNeeded() {
69
+
// if (!did) {
70
+
// setResolvedDid(null);
71
+
// return;
72
+
// }
73
+
// if (did.startsWith('did:')) {
74
+
// setResolvedDid(did);
75
+
// return;
76
+
// }
77
+
// setLoading(true);
78
+
// setError(null);
79
+
// const cacheKey = `handleDid:${did}`;
80
+
// const now = Date.now();
81
+
// const cached = await get(cacheKey); // <-- await here
82
+
// if (cached && cached.value && cached.time && now - cached.time < HANDLE_DID_CACHE_TIMEOUT) {
83
+
// try {
84
+
// const data = JSON.parse(cached.value);
85
+
// if (!ignore) setResolvedDid(data.did);
86
+
// setLoading(false);
87
+
// return;
88
+
// } catch {}
89
+
// }
90
+
// try {
91
+
// const url = `https://free-fly-24.deno.dev/?handle=${encodeURIComponent(did)}`;
92
+
// const res = await fetch(url);
93
+
// if (!res.ok) throw new Error('Failed to resolve handle');
94
+
// const data = await res.json();
95
+
// await set(cacheKey, JSON.stringify(data)); // <-- await here
96
+
// if (!ignore) setResolvedDid(data.did);
97
+
// } catch (e: any) {
98
+
// if (!ignore) setError('Failed to resolve handle: ' + (e?.message || e));
99
+
// } finally {
100
+
// setLoading(false);
101
+
// }
102
+
// }
103
+
// resolveDidIfNeeded();
104
+
// return () => {
105
+
// ignore = true;
106
+
// };
107
+
// }, [did, get, set]);
108
+
109
+
// const atUri = resolvedDid && rkey ? `at://${decodeURIComponent(resolvedDid)}/app.bsky.feed.post/${rkey}` : '';
110
+
111
+
// React.useEffect(() => {
112
+
// if (!atUri) return;
113
+
// let ignore = false;
114
+
// async function fetchMainPost() {
115
+
// try {
116
+
// const postData = await cachedGetRecord({ atUri, get, set });
117
+
// if (!ignore) {
118
+
// setMainPost(postData);
119
+
// }
120
+
// } catch (e) {
121
+
// console.error('Failed to fetch main post record:', e);
122
+
// }
123
+
// }
124
+
// fetchMainPost();
125
+
// return () => {
126
+
// ignore = true;
127
+
// };
128
+
// }, [atUri, get, set]);
129
+
130
+
// React.useEffect(() => {
131
+
// if (!mainPost) return;
132
+
// let ignore = false;
133
+
// async function fetchParents() {
134
+
// setParentsLoading(true);
135
+
// const parentChain: any[] = [];
136
+
// let currentParentUri = mainPost.value?.reply?.parent?.uri;
137
+
// const MAX_PARENTS = 25; // Important to know theres a limit
138
+
// let safetyCounter = 0;
139
+
140
+
// while (currentParentUri && safetyCounter < MAX_PARENTS) {
141
+
// try {
142
+
// const parentPost = await cachedGetRecord({ atUri: currentParentUri, get, set });
143
+
// if (!parentPost) break;
144
+
// parentChain.push(parentPost);
145
+
// currentParentUri = parentPost.value?.reply?.parent?.uri;
146
+
// safetyCounter++;
147
+
// } catch (error) {
148
+
// console.error('Failed to fetch a parent post:', error);
149
+
// break;
150
+
// }
151
+
// }
152
+
153
+
// if (!ignore) {
154
+
// setParents(parentChain.reverse());
155
+
// setParentsLoading(false);
156
+
// }
157
+
// }
158
+
159
+
// fetchParents();
160
+
// return () => {
161
+
// ignore = true;
162
+
// };
163
+
// }, [mainPost, get, set]);
23
164
24
-
const [mainPost, setMainPost] = React.useState<any | null>(null);
25
-
const [parents, setParents] = React.useState<any[]>([]);
26
-
const [parentsLoading, setParentsLoading] = React.useState(false);
27
-
const [replies, setReplies] = React.useState<any[]>([]);
165
+
// React.useEffect(() => {
166
+
// if (!atUri) return;
167
+
// let ignore = false;
168
+
// async function fetchReplies() {
169
+
// try {
170
+
// const url = `https://constellation.microcosm.blue/links?target=${encodeURIComponent(
171
+
// atUri,
172
+
// )}&collection=app.bsky.feed.post&path=.reply.parent.uri`;
173
+
// const res = await fetch(url);
174
+
// if (!res.ok) throw new Error('Failed to fetch replies');
175
+
// const data = await res.json();
176
+
// if (!ignore && data.linking_records) {
177
+
// setReplies(data.linking_records.slice(0, 50));
178
+
// }
179
+
// } catch (e) {
180
+
// if (!ignore) setReplies([]);
181
+
// }
182
+
// }
183
+
// fetchReplies();
184
+
// return () => {
185
+
// ignore = true;
186
+
// };
187
+
// }, [atUri]);
188
+
189
+
const {
190
+
data: identity,
191
+
isLoading: isIdentityLoading,
192
+
error: identityError,
193
+
} = useQueryIdentity(did);
194
+
195
+
const resolvedDid = did.startsWith("did:") ? did : identity?.did;
196
+
197
+
const atUri = React.useMemo(
198
+
() =>
199
+
resolvedDid
200
+
? `at://${decodeURIComponent(resolvedDid)}/app.bsky.feed.post/${rkey}`
201
+
: undefined,
202
+
[resolvedDid, rkey]
203
+
);
204
+
205
+
const { data: mainPost } = useQueryPost(atUri);
206
+
207
+
console.log("atUri",atUri)
208
+
209
+
const opdid = React.useMemo(
210
+
() =>
211
+
atUri
212
+
? new AtUri(atUri).host
213
+
: undefined,
214
+
[atUri]
215
+
);
216
+
217
+
// @ts-expect-error i hate overloads
218
+
const { data: links } = useQueryConstellation(atUri?{
219
+
method: "/links/all",
220
+
target: atUri,
221
+
} : {
222
+
method: "undefined",
223
+
target: ""
224
+
})as { data: linksAllResponse | undefined };
225
+
226
+
//const [likes, setLikes] = React.useState<number | null>(null);
227
+
//const [reposts, setReposts] = React.useState<number | null>(null);
228
+
const [replyCount, setReplyCount] = React.useState<number | null>(null);
28
229
29
230
React.useEffect(() => {
30
-
let ignore = false;
31
-
async function resolveDidIfNeeded() {
32
-
if (!did) {
33
-
setResolvedDid(null);
34
-
return;
231
+
// /*mass comment*/ console.log(JSON.stringify(links, null, 2));
232
+
// setLikes(
233
+
// links
234
+
// ? links?.links?.["app.bsky.feed.like"]?.[".subject.uri"]?.records || 0
235
+
// : null
236
+
// );
237
+
// setReposts(
238
+
// links
239
+
// ? links?.links?.["app.bsky.feed.repost"]?.[".subject.uri"]?.records || 0
240
+
// : null
241
+
// );
242
+
setReplyCount(
243
+
links
244
+
? links?.links?.["app.bsky.feed.post"]?.[".reply.parent.uri"]
245
+
?.records || 0
246
+
: null
247
+
);
248
+
}, [links]);
249
+
250
+
const { data: opreplies } = useQueryConstellation(
251
+
!!opdid && replyCount && replyCount >= 25
252
+
? {
253
+
method: "/links",
254
+
target: atUri,
255
+
// @ts-expect-error overloading sucks so much
256
+
collection: "app.bsky.feed.post",
257
+
path: ".reply.parent.uri",
258
+
//cursor?: string;
259
+
dids: [opdid],
260
+
}
261
+
: {
262
+
method: "undefined",
263
+
target: "",
264
+
}
265
+
) as { data: linksRecordsResponse | undefined };
266
+
267
+
const opReplyAturis =
268
+
opreplies?.linking_records.map(
269
+
(r) => `at://${r.did}/${r.collection}/${r.rkey}`,
270
+
) ?? [];
271
+
272
+
273
+
// const { data: repliesData } = useQueryConstellation({
274
+
// method: "/links",
275
+
// target: atUri,
276
+
// collection: "app.bsky.feed.post",
277
+
// path: ".reply.parent.uri",
278
+
// });
279
+
// const replies = repliesData?.linking_records.slice(0, 50) ?? [];
280
+
const [constellationurl] = useAtom(constellationURLAtom)
281
+
282
+
const infinitequeryresults = useInfiniteQuery({
283
+
...yknowIReallyHateThisButWhateverGuardedConstructConstellationInfiniteQueryLinks(
284
+
{
285
+
constellation: constellationurl,
286
+
method: "/links",
287
+
target: atUri,
288
+
collection: "app.bsky.feed.post",
289
+
path: ".reply.parent.uri",
35
290
}
36
-
if (did.startsWith('did:')) {
37
-
setResolvedDid(did);
38
-
return;
39
-
}
40
-
setLoading(true);
41
-
setError(null);
42
-
const cacheKey = `handleDid:${did}`;
43
-
const now = Date.now();
44
-
const cached = await get(cacheKey); // <-- await here
45
-
if (cached && cached.value && cached.time && now - cached.time < HANDLE_DID_CACHE_TIMEOUT) {
46
-
try {
47
-
const data = JSON.parse(cached.value);
48
-
if (!ignore) setResolvedDid(data.did);
49
-
setLoading(false);
50
-
return;
51
-
} catch {}
291
+
),
292
+
enabled: !!atUri,
293
+
});
294
+
295
+
const {
296
+
data: infiniteRepliesData,
297
+
fetchNextPage,
298
+
hasNextPage,
299
+
isFetchingNextPage,
300
+
} = infinitequeryresults;
301
+
302
+
// // auto-fetch all pages
303
+
// useEffect(() => {
304
+
// if (
305
+
// infinitequeryresults.hasNextPage &&
306
+
// !infinitequeryresults.isFetchingNextPage
307
+
// ) {
308
+
// console.log("Fetching the next page...");
309
+
// infinitequeryresults.fetchNextPage();
310
+
// }
311
+
// }, [infinitequeryresults]);
312
+
313
+
// const replyAturis = repliesData
314
+
// ? repliesData.pages.flatMap((page) =>
315
+
// page
316
+
// ? page.linking_records.map((record) => {
317
+
// const aturi = `at://${record.did}/${record.collection}/${record.rkey}`;
318
+
// return aturi;
319
+
// })
320
+
// : []
321
+
// )
322
+
// : [];
323
+
324
+
const replyAturis = React.useMemo(() => {
325
+
// Get all replies from the standard infinite query
326
+
const allReplies =
327
+
infiniteRepliesData?.pages.flatMap(
328
+
(page) =>
329
+
page?.linking_records.map(
330
+
(r) => `at://${r.did}/${r.collection}/${r.rkey}`,
331
+
) ?? [],
332
+
) ?? [];
333
+
334
+
if (replyCount && (replyCount < 25)) {
335
+
// If count is low, just use the standard list and find the oldest OP reply to move to the top
336
+
const opdidFromUri = atUri ? new AtUri(atUri).host : undefined;
337
+
const oldestOpsIndex = allReplies.findIndex(
338
+
(aturi) => new AtUri(aturi).host === opdidFromUri,
339
+
);
340
+
if (oldestOpsIndex > 0) {
341
+
const [oldestOpsReply] = allReplies.splice(oldestOpsIndex, 1);
342
+
allReplies.unshift(oldestOpsReply);
52
343
}
53
-
try {
54
-
const url = `https://free-fly-24.deno.dev/?handle=${encodeURIComponent(did)}`;
55
-
const res = await fetch(url);
56
-
if (!res.ok) throw new Error('Failed to resolve handle');
57
-
const data = await res.json();
58
-
await set(cacheKey, JSON.stringify(data)); // <-- await here
59
-
if (!ignore) setResolvedDid(data.did);
60
-
} catch (e: any) {
61
-
if (!ignore) setError('Failed to resolve handle: ' + (e?.message || e));
62
-
} finally {
63
-
setLoading(false);
344
+
return allReplies;
345
+
} else {
346
+
// If count is high, prioritize OP replies from the special query
347
+
// and filter them out from the main list to avoid duplication.
348
+
const opReplySet = new Set(opReplyAturis);
349
+
const otherReplies = allReplies.filter((uri) => !opReplySet.has(uri));
350
+
return [...opReplyAturis, ...otherReplies];
351
+
}
352
+
}, [infiniteRepliesData, opReplyAturis, replyCount, atUri]);
353
+
354
+
// Find oldest OP reply
355
+
const oldestOpsIndex = replyAturis.findIndex(
356
+
(aturi) => new AtUri(aturi).host === opdid
357
+
);
358
+
359
+
// Reorder: move oldest OP reply to the front
360
+
if (oldestOpsIndex > 0) {
361
+
const [oldestOpsReply] = replyAturis.splice(oldestOpsIndex, 1);
362
+
replyAturis.unshift(oldestOpsReply);
363
+
}
364
+
365
+
const [parents, setParents] = React.useState<any[]>([]);
366
+
const [parentsLoading, setParentsLoading] = React.useState(false);
367
+
368
+
const mainPostRef = React.useRef<HTMLDivElement>(null);
369
+
const hasPerformedInitialLayout = React.useRef(false);
370
+
371
+
const [layoutReady, setLayoutReady] = React.useState(false);
372
+
373
+
useLayoutEffect(() => {
374
+
if (parents.length > 0 && !layoutReady && mainPostRef.current) {
375
+
const mainPostElement = mainPostRef.current;
376
+
377
+
if (window.scrollY === 0 && !hasPerformedInitialLayout.current) {
378
+
const elementTop = mainPostElement.getBoundingClientRect().top;
379
+
const headerOffset = 70;
380
+
381
+
const targetScrollY = elementTop - headerOffset;
382
+
383
+
window.scrollBy(0, targetScrollY);
384
+
385
+
hasPerformedInitialLayout.current = true;
64
386
}
387
+
388
+
// todo idk what to do with this
389
+
// eslint-disable-next-line react-hooks/set-state-in-effect
390
+
setLayoutReady(true);
65
391
}
66
-
resolveDidIfNeeded();
67
-
return () => {
68
-
ignore = true;
69
-
};
70
-
}, [did, get, set]);
392
+
}, [parents, layoutReady]);
71
393
72
-
const atUri = resolvedDid && rkey ? `at://${decodeURIComponent(resolvedDid)}/app.bsky.feed.post/${rkey}` : '';
73
394
395
+
const [slingshoturl] = useAtom(slingshotURLAtom)
396
+
74
397
React.useEffect(() => {
75
-
if (!atUri) return;
76
-
let ignore = false;
77
-
async function fetchMainPost() {
78
-
try {
79
-
const postData = await cachedGetRecord({ atUri, get, set });
80
-
if (!ignore) {
81
-
setMainPost(postData);
82
-
}
83
-
} catch (e) {
84
-
console.error('Failed to fetch main post record:', e);
85
-
}
398
+
if (parentsLoading) {
399
+
setLayoutReady(false);
86
400
}
87
-
fetchMainPost();
88
-
return () => {
89
-
ignore = true;
90
-
};
91
-
}, [atUri, get, set]);
401
+
402
+
if (!mainPost?.value?.reply?.parent?.uri && !parentsLoading) {
403
+
setLayoutReady(true);
404
+
hasPerformedInitialLayout.current = true;
405
+
}
406
+
}, [parentsLoading, mainPost]);
92
407
93
408
React.useEffect(() => {
94
-
if (!mainPost) return;
409
+
if (!mainPost?.value?.reply?.parent?.uri) {
410
+
setParents([]);
411
+
return;
412
+
}
413
+
95
414
let ignore = false;
96
-
async function fetchParents() {
415
+
const fetchParents = async () => {
97
416
setParentsLoading(true);
98
417
const parentChain: any[] = [];
99
-
let currentParentUri = mainPost.value?.reply?.parent?.uri;
100
-
const MAX_PARENTS = 25; // Important to know theres a limit
418
+
let currentParentUri = mainPost?.value.reply?.parent.uri;
419
+
const MAX_PARENTS = 25;
101
420
let safetyCounter = 0;
102
421
103
422
while (currentParentUri && safetyCounter < MAX_PARENTS) {
104
423
try {
105
-
const parentPost = await cachedGetRecord({ atUri: currentParentUri, get, set });
424
+
const parentPost = await queryClient.fetchQuery(
425
+
constructPostQuery(currentParentUri, slingshoturl)
426
+
);
106
427
if (!parentPost) break;
107
428
parentChain.push(parentPost);
108
429
currentParentUri = parentPost.value?.reply?.parent?.uri;
109
-
safetyCounter++;
110
430
} catch (error) {
111
-
console.error('Failed to fetch a parent post:', error);
431
+
console.error("Failed to fetch a parent post:", error);
112
432
break;
113
433
}
434
+
safetyCounter++;
114
435
}
115
436
116
437
if (!ignore) {
117
438
setParents(parentChain.reverse());
118
439
setParentsLoading(false);
119
440
}
120
-
}
441
+
};
121
442
122
443
fetchParents();
123
444
return () => {
124
445
ignore = true;
125
446
};
126
-
}, [mainPost, get, set]);
127
-
128
-
React.useEffect(() => {
129
-
if (!atUri) return;
130
-
let ignore = false;
131
-
async function fetchReplies() {
132
-
try {
133
-
const url = `https://constellation.microcosm.blue/links?target=${encodeURIComponent(
134
-
atUri,
135
-
)}&collection=app.bsky.feed.post&path=.reply.parent.uri`;
136
-
const res = await fetch(url);
137
-
if (!res.ok) throw new Error('Failed to fetch replies');
138
-
const data = await res.json();
139
-
if (!ignore && data.linking_records) {
140
-
setReplies(data.linking_records.slice(0, 50));
141
-
}
142
-
} catch (e) {
143
-
if (!ignore) setReplies([]);
144
-
}
145
-
}
146
-
fetchReplies();
147
-
return () => {
148
-
ignore = true;
149
-
};
150
-
}, [atUri]);
447
+
}, [mainPost, queryClient]);
151
448
152
449
if (!did || !rkey) return <div>Invalid post URI</div>;
153
-
if (loading) return <div>Resolving handle...</div>;
154
-
if (error) return <div style={{ color: 'red' }}>{error}</div>;
155
-
if (!atUri) return <div>Invalid post URI</div>;
450
+
if (isIdentityLoading) return <div>Resolving handle...</div>;
451
+
if (identityError)
452
+
return <div style={{ color: "red" }}>{identityError.message}</div>;
453
+
if (!atUri) return <div>Could not construct post URI.</div>;
156
454
157
455
return (
158
456
<>
159
-
<div className="flex items-center gap-2 px-4 py-2 h-[52px] sticky top-0 bg-white dark:bg-gray-950 z-10 border-b border-gray-200 dark:border-gray-700">
160
-
<Link
161
-
to=".."
162
-
className="px-3 py-1 rounded hover:bg-gray-100 dark:hover:bg-gray-900 font-bold text-lg"
163
-
onClick={e => {
164
-
e.preventDefault();
165
-
window.history.length > 1 ? window.history.back() : window.location.assign('/');
166
-
}}
167
-
aria-label="Go back"
168
-
>
169
-
โ
170
-
</Link>
171
-
<span className="text-xl font-bold ml-2">Post</span>
172
-
</div>
457
+
<Outlet />
458
+
<Header
459
+
title={`Post`}
460
+
backButtonCallback={() => {
461
+
if (window.history.length > 1) {
462
+
window.history.back();
463
+
} else {
464
+
window.location.assign("/");
465
+
}
466
+
}}
467
+
/>
173
468
174
-
{parentsLoading && <div className="p-4 text-center text-gray-500 dark:text-gray-400">Loading conversation...</div>}
469
+
{parentsLoading && (
470
+
<div className="text-center text-gray-500 dark:text-gray-400 flex flex-row">
471
+
<div className="ml-4 w-[42px] flex justify-center">
472
+
<div
473
+
style={{ width: 2, height: "100%", opacity: 0.5 }}
474
+
className="bg-gray-500 dark:bg-gray-400"
475
+
></div>
476
+
</div>
477
+
Loading conversation...
478
+
</div>
479
+
)}
175
480
176
481
{/* we should use the reply lines here thats provided by UPR*/}
177
-
<div style={{ maxWidth: 600, margin: '0px auto 0', padding: 0 }}>
482
+
<div style={{ maxWidth: 600, padding: 0 }}>
178
483
{parents.map((parent, index) => (
179
-
<UniversalPostRendererATURILoader key={parent.uri} atUri={parent.uri}
180
-
topReplyLine={index > 0}
484
+
<UniversalPostRendererATURILoader
485
+
key={parent.uri}
486
+
atUri={parent.uri}
487
+
topReplyLine={index > 0}
181
488
bottomReplyLine={true}
182
489
bottomBorder={false}
183
-
/>
490
+
/>
184
491
))}
185
492
</div>
186
-
187
-
<UniversalPostRendererATURILoader atUri={atUri} detailed={true} topReplyLine={parents.length > 0} />
188
-
189
-
{replies.length > 0 && (
190
-
<div style={{ maxWidth: 600, margin: '0px auto 0', padding: 0 }}>
191
-
<div
192
-
className="text-gray-500 dark:text-gray-400 text-sm font-bold"
193
-
style={{ fontSize: 18, margin: '12px 16px 12px 16px', fontWeight: 600 }}
194
-
>
195
-
Replies
196
-
</div>
197
-
<div style={{ display: 'flex', flexDirection: 'column', gap: 0 }}>
198
-
{replies.map(reply => {
199
-
const replyAtUri = `at://${reply.did}/app.bsky.feed.post/${reply.rkey}`;
200
-
return <UniversalPostRendererATURILoader key={replyAtUri} atUri={replyAtUri} />;
493
+
<div ref={mainPostRef}>
494
+
<UniversalPostRendererATURILoader
495
+
atUri={atUri}
496
+
detailed={true}
497
+
topReplyLine={parentsLoading || parents.length > 0}
498
+
nopics={!!nopics}
499
+
lightboxCallback={lightboxCallback}
500
+
/>
501
+
</div>
502
+
<div
503
+
style={{
504
+
maxWidth: 600,
505
+
//margin: "0px auto 0",
506
+
padding: 0,
507
+
minHeight: "80dvh",
508
+
paddingBottom: "20dvh",
509
+
}}
510
+
>
511
+
<div
512
+
className="text-gray-500 dark:text-gray-400 text-sm font-bold"
513
+
style={{
514
+
fontSize: 18,
515
+
margin: "12px 16px 12px 16px",
516
+
fontWeight: 600,
517
+
}}
518
+
>
519
+
Replies
520
+
</div>
521
+
<div style={{ display: "flex", flexDirection: "column", gap: 0 }}>
522
+
{replyAturis.length > 0 &&
523
+
replyAturis.map((reply) => {
524
+
//const replyAtUri = `at://${reply.did}/app.bsky.feed.post/${reply.rkey}`;
525
+
return (
526
+
<UniversalPostRendererATURILoader
527
+
key={reply}
528
+
atUri={reply}
529
+
maxReplies={4}
530
+
/>
531
+
);
201
532
})}
202
-
</div>
533
+
{hasNextPage && (
534
+
<button
535
+
onClick={() => fetchNextPage()}
536
+
disabled={isFetchingNextPage}
537
+
className="w-[calc(100%-2rem)] mx-4 my-4 px-4 py-2 bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-gray-200 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-700 font-semibold disabled:opacity-50"
538
+
>
539
+
{isFetchingNextPage ? "Loading..." : "Load More"}
540
+
</button>
541
+
)}
203
542
</div>
204
-
)}
543
+
</div>
205
544
</>
206
545
);
207
-
}
546
+
}
+50
-1
src/routes/search.tsx
+50
-1
src/routes/search.tsx
···
1
1
import { createFileRoute } from "@tanstack/react-router";
2
2
3
+
import { Header } from "~/components/Header";
4
+
import { Import } from "~/components/Import";
5
+
3
6
export const Route = createFileRoute("/search")({
4
7
component: Search,
5
8
});
6
9
7
10
export function Search() {
8
-
return <div className="p-6">Search page (coming soon)</div>;
11
+
return (
12
+
<>
13
+
<Header
14
+
title="Explore"
15
+
backButtonCallback={() => {
16
+
if (window.history.length > 1) {
17
+
window.history.back();
18
+
} else {
19
+
window.location.assign("/");
20
+
}
21
+
}}
22
+
/>
23
+
<div className=" flex flex-col items-center mt-4 mx-4 gap-4">
24
+
<Import />
25
+
<div className="flex flex-col">
26
+
<p className="text-gray-600 dark:text-gray-400">
27
+
Sorry we dont have search. But instead, you can load some of these
28
+
types of content into Red Dwarf:
29
+
</p>
30
+
<ul className="list-disc list-inside mt-2 text-gray-600 dark:text-gray-400">
31
+
<li>
32
+
Bluesky URLs from supported clients (like{" "}
33
+
<code className="text-sm">bsky.app</code> or{" "}
34
+
<code className="text-sm">deer.social</code>).
35
+
</li>
36
+
<li>
37
+
AT-URIs (e.g.,{" "}
38
+
<code className="text-sm">at://did:example/collection/item</code>
39
+
).
40
+
</li>
41
+
<li>
42
+
Plain handles (like{" "}
43
+
<code className="text-sm">@username.bsky.social</code>).
44
+
</li>
45
+
<li>
46
+
Direct DIDs (Decentralized Identifiers, starting with{" "}
47
+
<code className="text-sm">did:</code>).
48
+
</li>
49
+
</ul>
50
+
<p className="mt-2 text-gray-600 dark:text-gray-400">
51
+
Simply paste one of these into the import field above and press
52
+
Enter to load the content.
53
+
</p>
54
+
</div>
55
+
</div>
56
+
</>
57
+
);
9
58
}
+181
-1
src/routes/settings.tsx
+181
-1
src/routes/settings.tsx
···
1
1
import { createFileRoute } from "@tanstack/react-router";
2
+
import { useAtom } from "jotai";
3
+
import { Slider } from "radix-ui";
4
+
5
+
import { Header } from "~/components/Header";
6
+
import Login from "~/components/Login";
7
+
import {
8
+
constellationURLAtom,
9
+
defaultconstellationURL,
10
+
defaulthue,
11
+
defaultImgCDN,
12
+
defaultslingshotURL,
13
+
defaultVideoCDN,
14
+
hueAtom,
15
+
imgCDNAtom,
16
+
slingshotURLAtom,
17
+
videoCDNAtom,
18
+
} from "~/utils/atoms";
2
19
3
20
export const Route = createFileRoute("/settings")({
4
21
component: Settings,
5
22
});
6
23
7
24
export function Settings() {
8
-
return <div className="p-6">Settings page (coming soon)</div>;
25
+
return (
26
+
<>
27
+
<Header
28
+
title="Settings"
29
+
backButtonCallback={() => {
30
+
if (window.history.length > 1) {
31
+
window.history.back();
32
+
} else {
33
+
window.location.assign("/");
34
+
}
35
+
}}
36
+
/>
37
+
<div className="lg:hidden">
38
+
<Login />
39
+
</div>
40
+
<div className="h-4" />
41
+
<TextInputSetting
42
+
atom={constellationURLAtom}
43
+
title={"Constellation"}
44
+
description={
45
+
"Customize the Constellation instance to be used by Red Dwarf"
46
+
}
47
+
init={defaultconstellationURL}
48
+
/>
49
+
<TextInputSetting
50
+
atom={slingshotURLAtom}
51
+
title={"Slingshot"}
52
+
description={"Customize the Slingshot instance to be used by Red Dwarf"}
53
+
init={defaultslingshotURL}
54
+
/>
55
+
<TextInputSetting
56
+
atom={imgCDNAtom}
57
+
title={"Image CDN"}
58
+
description={
59
+
"Customize the Constellation instance to be used by Red Dwarf"
60
+
}
61
+
init={defaultImgCDN}
62
+
/>
63
+
<TextInputSetting
64
+
atom={videoCDNAtom}
65
+
title={"Video CDN"}
66
+
description={"Customize the Slingshot instance to be used by Red Dwarf"}
67
+
init={defaultVideoCDN}
68
+
/>
69
+
70
+
<Hue />
71
+
<p className="text-gray-500 dark:text-gray-400 py-4 px-6 text-sm">
72
+
please restart/refresh the app if changes arent applying correctly
73
+
</p>
74
+
</>
75
+
);
76
+
}
77
+
function Hue() {
78
+
const [hue, setHue] = useAtom(hueAtom);
79
+
return (
80
+
<div className="flex flex-col px-4 mt-4 ">
81
+
<span className="z-10">Hue</span>
82
+
<div className="flex flex-row items-center gap-4">
83
+
<SliderComponent
84
+
atom={hueAtom}
85
+
max={360}
86
+
/>
87
+
<button
88
+
onClick={() => setHue(defaulthue ?? 28)}
89
+
className="px-6 py-2 h-12 rounded-full bg-gray-100 dark:bg-gray-800
90
+
text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-700 transition"
91
+
>
92
+
Reset
93
+
</button>
94
+
</div>
95
+
</div>
96
+
);
9
97
}
98
+
99
+
export function TextInputSetting({
100
+
atom,
101
+
title,
102
+
description,
103
+
init,
104
+
}: {
105
+
atom: typeof constellationURLAtom;
106
+
title?: string;
107
+
description?: string;
108
+
init?: string;
109
+
}) {
110
+
const [value, setValue] = useAtom(atom);
111
+
return (
112
+
<div className="flex flex-col gap-2 px-4 py-2">
113
+
{/* <div>
114
+
{title && (
115
+
<h3 className="text-sm font-medium text-gray-900 dark:text-gray-100">
116
+
{title}
117
+
</h3>
118
+
)}
119
+
{description && (
120
+
<p className="text-sm text-gray-500 dark:text-gray-400">
121
+
{description}
122
+
</p>
123
+
)}
124
+
</div> */}
125
+
126
+
<div className="flex flex-row gap-2 items-center">
127
+
<div className="m3input-field m3input-label m3input-border size-md flex-1">
128
+
<input
129
+
type="text"
130
+
placeholder=" "
131
+
value={value}
132
+
onChange={(e) => setValue(e.target.value)}
133
+
/>
134
+
<label>{title}</label>
135
+
</div>
136
+
{/* <input
137
+
type="text"
138
+
value={value}
139
+
onChange={(e) => setValue(e.target.value)}
140
+
className="flex-1 px-3 py-2 rounded-lg bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-700
141
+
text-gray-900 dark:text-gray-100 placeholder:text-gray-500 dark:placeholder:text-gray-400
142
+
focus:outline-none focus:ring-2 focus:ring-gray-400 dark:focus:ring-gray-600"
143
+
placeholder="Enter value..."
144
+
/> */}
145
+
<button
146
+
onClick={() => setValue(init ?? "")}
147
+
className="px-6 py-2 h-12 rounded-full bg-gray-100 dark:bg-gray-800
148
+
text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-700 transition"
149
+
>
150
+
Reset
151
+
</button>
152
+
</div>
153
+
</div>
154
+
);
155
+
}
156
+
157
+
158
+
interface SliderProps {
159
+
atom: typeof hueAtom;
160
+
min?: number;
161
+
max?: number;
162
+
step?: number;
163
+
}
164
+
165
+
export const SliderComponent: React.FC<SliderProps> = ({
166
+
atom,
167
+
min = 0,
168
+
max = 100,
169
+
step = 1,
170
+
}) => {
171
+
172
+
const [value, setValue] = useAtom(atom)
173
+
174
+
return (
175
+
<Slider.Root
176
+
className="relative flex items-center w-full h-4"
177
+
value={[value]}
178
+
min={min}
179
+
max={max}
180
+
step={step}
181
+
onValueChange={(v: number[]) => setValue(v[0])}
182
+
>
183
+
<Slider.Track className="relative flex-grow h-4 bg-gray-300 dark:bg-gray-700 rounded-full">
184
+
<Slider.Range className="absolute h-full bg-gray-500 dark:bg-gray-400 rounded-l-full rounded-r-none" />
185
+
</Slider.Track>
186
+
<Slider.Thumb className="shadow-[0_0_0_8px_var(--color-white)] dark:shadow-[0_0_0_8px_var(--color-gray-950)] block w-[3px] h-12 bg-gray-500 dark:bg-gray-400 rounded-md focus:outline-none" />
187
+
</Slider.Root>
188
+
);
189
+
};
+184
-13
src/styles/app.css
+184
-13
src/styles/app.css
···
1
+
@import url('https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&family=Roboto:ital,wght@0,100..900;1,100..900&family=Spectral+SC:wght@500&display=swap');
1
2
@import "tailwindcss";
2
3
3
4
/* @theme {
···
14
15
--color-gray-950: oklch(0.129 0.050 222.000);
15
16
} */
16
17
18
+
:root {
19
+
--safe-hue: var(--tw-gray-hue, 28)
20
+
}
21
+
17
22
@theme {
18
-
--color-gray-50: oklch(0.984 0.012 28);
19
-
--color-gray-100: oklch(0.968 0.017 28);
20
-
--color-gray-200: oklch(0.929 0.025 28);
21
-
--color-gray-300: oklch(0.869 0.035 28);
22
-
--color-gray-400: oklch(0.704 0.05 28);
23
-
--color-gray-500: oklch(0.554 0.06 28);
24
-
--color-gray-600: oklch(0.446 0.058 28);
25
-
--color-gray-700: oklch(0.372 0.058 28);
26
-
--color-gray-800: oklch(0.279 0.055 28);
27
-
--color-gray-900: oklch(0.208 0.055 28);
28
-
--color-gray-950: oklch(0.129 0.055 28);
23
+
--color-gray-50: oklch(0.984 0.012 var(--safe-hue));
24
+
--color-gray-100: oklch(0.968 0.017 var(--safe-hue));
25
+
--color-gray-200: oklch(0.929 0.025 var(--safe-hue));
26
+
--color-gray-300: oklch(0.869 0.035 var(--safe-hue));
27
+
--color-gray-400: oklch(0.704 0.05 var(--safe-hue));
28
+
--color-gray-500: oklch(0.554 0.06 var(--safe-hue));
29
+
--color-gray-600: oklch(0.446 0.058 var(--safe-hue));
30
+
--color-gray-700: oklch(0.372 0.058 var(--safe-hue));
31
+
--color-gray-800: oklch(0.279 0.055 var(--safe-hue));
32
+
--color-gray-900: oklch(0.208 0.055 var(--safe-hue));
33
+
--color-gray-950: oklch(0.129 0.055 var(--safe-hue));
29
34
}
30
35
31
36
@layer base {
···
47
52
}
48
53
}
49
54
55
+
.gutter{
56
+
scrollbar-gutter: stable both-edges;
57
+
}
58
+
50
59
@media (width >= 64rem /* 1024px */) {
51
-
html,
52
-
body {
60
+
html:not(:has(.disablegutter)),
61
+
body:not(:has(.disablegutter)) {
53
62
scrollbar-gutter: stable both-edges !important;
54
63
}
64
+
html:has(.disablescroll),
65
+
body:has(.disablescroll) {
66
+
scrollbar-width: none;
67
+
overflow-y: hidden;
68
+
}
69
+
}
70
+
71
+
.lightbox:has(+.lightbox-sidebar){
72
+
opacity: 0;
55
73
}
74
+
56
75
.scroll-thin {
57
76
scrollbar-width: thin;
58
77
/*scrollbar-gutter: stable both-edges !important;*/
···
61
80
.scroll-none {
62
81
scrollbar-width: none;
63
82
}
83
+
84
+
.dangerousFediContent {
85
+
& a[href]{
86
+
text-decoration: none;
87
+
color: rgb(29, 122, 242);
88
+
word-break: break-all;
89
+
}
90
+
}
91
+
92
+
.font-inter {
93
+
font-family: "Inter", sans-serif;
94
+
}
95
+
.font-roboto {
96
+
font-family: "Roboto", sans-serif;
97
+
}
98
+
99
+
:root {
100
+
--header-bg-light: color-mix(in srgb, var(--color-white) calc(var(--is-top) * 100%), var(--color-gray-50));
101
+
--header-bg-dark: color-mix(in srgb, var(--color-gray-950) calc(var(--is-top) * 100%), var(--color-gray-900));
102
+
}
103
+
104
+
:root {
105
+
--header-bg: var(--header-bg-light);
106
+
}
107
+
@media (prefers-color-scheme: dark) {
108
+
:root {
109
+
--header-bg: var(--header-bg-dark);
110
+
}
111
+
}
112
+
113
+
:root {
114
+
--shadow-opacity: calc(1 - var(--is-top));
115
+
--tw-shadow-header: 0 2px 8px hsl(0 0% 0% / calc(var(--shadow-opacity) * 0.15));
116
+
}
117
+
118
+
119
+
/* m3 input */
120
+
:root {
121
+
--m3input-radius: 6px;
122
+
--m3input-border-width: .0625rem;
123
+
--m3input-font-size: 16px;
124
+
--m3input-transition: 150ms cubic-bezier(.2, .8, .2, 1);
125
+
/* light theme */
126
+
--m3input-bg: var(--color-gray-50);
127
+
--m3input-border-color: var(--color-gray-400);
128
+
--m3input-label-color: var(--color-gray-500);
129
+
--m3input-text-color: var(--color-gray-900);
130
+
--m3input-focus-color: var(--color-gray-600);
131
+
}
132
+
133
+
@media (prefers-color-scheme: dark) {
134
+
:root {
135
+
--m3input-bg: var(--color-gray-950);
136
+
--m3input-border-color: var(--color-gray-700);
137
+
--m3input-label-color: var(--color-gray-400);
138
+
--m3input-text-color: var(--color-gray-50);
139
+
--m3input-focus-color: var(--color-gray-400);
140
+
}
141
+
}
142
+
143
+
/* reset page *//*
144
+
html,
145
+
body {
146
+
background: var(--m3input-bg);
147
+
margin: 0;
148
+
padding: 1rem;
149
+
color: var(--m3input-text-color);
150
+
font-family: system-ui, sans-serif;
151
+
font-size: var(--m3input-font-size);
152
+
}*/
153
+
154
+
/* base wrapper */
155
+
.m3input-field.m3input-label.m3input-border {
156
+
position: relative;
157
+
display: inline-block;
158
+
width: 100%;
159
+
/*max-width: 400px;*/
160
+
}
161
+
162
+
/* size variants */
163
+
.m3input-field.size-sm {
164
+
--m3input-h: 40px;
165
+
}
166
+
167
+
.m3input-field.size-md {
168
+
--m3input-h: 48px;
169
+
}
170
+
171
+
.m3input-field.size-lg {
172
+
--m3input-h: 56px;
173
+
}
174
+
175
+
.m3input-field.size-xl {
176
+
--m3input-h: 64px;
177
+
}
178
+
179
+
.m3input-field.m3input-label.m3input-border:not(.size-sm):not(.size-md):not(.size-lg):not(.size-xl) {
180
+
--m3input-h: 48px;
181
+
}
182
+
183
+
/* outlined input */
184
+
.m3input-field.m3input-label.m3input-border input {
185
+
width: 100%;
186
+
height: var(--m3input-h);
187
+
border: var(--m3input-border-width) solid var(--m3input-border-color);
188
+
border-radius: var(--m3input-radius);
189
+
background: var(--m3input-bg);
190
+
color: var(--m3input-text-color);
191
+
font-size: var(--m3input-font-size);
192
+
padding: 0 12px;
193
+
box-sizing: border-box;
194
+
outline: none;
195
+
transition: border-color var(--m3input-transition), box-shadow var(--m3input-transition);
196
+
}
197
+
198
+
/* focus ring */
199
+
.m3input-field.m3input-label.m3input-border input:focus {
200
+
border-color: var(--m3input-focus-color);
201
+
/*box-shadow: 0 0 0 2px color-mix(in srgb, var(--focus-color) 20%, transparent);*/
202
+
}
203
+
204
+
/* label */
205
+
.m3input-field.m3input-label.m3input-border label {
206
+
position: absolute;
207
+
left: 12px;
208
+
top: 50%;
209
+
transform: translateY(-50%);
210
+
background: var(--m3input-bg);
211
+
padding: 0 .25em;
212
+
color: var(--m3input-label-color);
213
+
pointer-events: none;
214
+
transition: all var(--m3input-transition);
215
+
}
216
+
217
+
/* float on focus or when filled */
218
+
.m3input-field.m3input-label.m3input-border input:focus+label,
219
+
.m3input-field.m3input-label.m3input-border input:not(:placeholder-shown)+label {
220
+
top: 0;
221
+
transform: translateY(-50%) scale(.78);
222
+
left: 0;
223
+
color: var(--m3input-focus-color);
224
+
}
225
+
226
+
/* placeholder trick */
227
+
.m3input-field.m3input-label.m3input-border input::placeholder {
228
+
color: transparent;
229
+
}
230
+
231
+
/* radix i love you but like cmon man */
232
+
body[data-scroll-locked]{
233
+
margin-left: var(--removed-body-scroll-bar-size) !important;
234
+
}
+82
src/utils/atoms.ts
+82
src/utils/atoms.ts
···
1
+
import { atom, createStore, useAtomValue } from "jotai";
2
+
import { atomWithStorage } from "jotai/utils";
3
+
import { useEffect } from "react";
4
+
5
+
export const store = createStore();
6
+
7
+
export const quickAuthAtom = atomWithStorage<string | null>(
8
+
"quickAuth",
9
+
null
10
+
);
11
+
12
+
export const selectedFeedUriAtom = atomWithStorage<string | null>(
13
+
"selectedFeedUri",
14
+
null
15
+
);
16
+
17
+
//export const feedScrollPositionsAtom = atom<Record<string, number>>({});
18
+
19
+
export const feedScrollPositionsAtom = atomWithStorage<Record<string, number>>(
20
+
"feedscrollpositions",
21
+
{}
22
+
);
23
+
24
+
export const likedPostsAtom = atomWithStorage<Record<string, string>>(
25
+
"likedPosts",
26
+
{}
27
+
);
28
+
29
+
export const defaultconstellationURL = "constellation.microcosm.blue";
30
+
export const constellationURLAtom = atomWithStorage<string>(
31
+
"constellationURL",
32
+
defaultconstellationURL
33
+
);
34
+
export const defaultslingshotURL = "slingshot.microcosm.blue";
35
+
export const slingshotURLAtom = atomWithStorage<string>(
36
+
"slingshotURL",
37
+
defaultslingshotURL
38
+
);
39
+
export const defaultImgCDN = "cdn.bsky.app";
40
+
export const imgCDNAtom = atomWithStorage<string>("imgcdnurl", defaultImgCDN);
41
+
export const defaultVideoCDN = "video.bsky.app";
42
+
export const videoCDNAtom = atomWithStorage<string>(
43
+
"videocdnurl",
44
+
defaultVideoCDN
45
+
);
46
+
47
+
export const defaulthue = 28;
48
+
export const hueAtom = atomWithStorage<number>("hue", defaulthue);
49
+
50
+
export const isAtTopAtom = atom<boolean>(true);
51
+
52
+
type ComposerState =
53
+
| { kind: "closed" }
54
+
| { kind: "root" }
55
+
| { kind: "reply"; parent: string }
56
+
| { kind: "quote"; subject: string };
57
+
export const composerAtom = atom<ComposerState>({ kind: "closed" });
58
+
59
+
//export const agentAtom = atom<Agent | null>(null);
60
+
//export const authedAtom = atom<boolean>(false);
61
+
62
+
export function useAtomCssVar(atom: typeof hueAtom, cssVar: string) {
63
+
const value = useAtomValue(atom);
64
+
65
+
useEffect(() => {
66
+
document.documentElement.style.setProperty(cssVar, value.toString());
67
+
}, [value, cssVar]);
68
+
69
+
useEffect(() => {
70
+
document.documentElement.style.setProperty(cssVar, value.toString());
71
+
}, []);
72
+
}
73
+
74
+
hueAtom.onMount = (setAtom) => {
75
+
const stored = localStorage.getItem("hue");
76
+
if (stored != null) setAtom(Number(stored));
77
+
};
78
+
// export function initAtomToCssVar(atom: typeof hueAtom, cssVar: string) {
79
+
// const initial = store.get(atom);
80
+
// console.log("atom get ", initial);
81
+
// document.documentElement.style.setProperty(cssVar, initial.toString());
82
+
// }
+163
src/utils/followState.ts
+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
+14
src/utils/oauthClient.ts
···
1
+
import { BrowserOAuthClient, type ClientMetadata } from '@atproto/oauth-client-browser';
2
+
3
+
// i tried making this https://pds-nd.whey.party but cors is annoying as fuck
4
+
const handleResolverPDS = 'https://bsky.social';
5
+
6
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
7
+
// @ts-ignore this should be fine ? the vite plugin should generate this before errors
8
+
import clientMetadata from '../../public/client-metadata.json' with { type: 'json' };
9
+
10
+
export const oauthClient = new BrowserOAuthClient({
11
+
// The type assertion is needed because the static import isn't strictly typed
12
+
clientMetadata: clientMetadata as ClientMetadata,
13
+
handleResolver: handleResolverPDS,
14
+
});
+275
src/utils/useHydrated.ts
+275
src/utils/useHydrated.ts
···
1
+
import {
2
+
type $Typed,
3
+
AppBskyActorDefs,
4
+
AppBskyEmbedExternal,
5
+
AppBskyEmbedImages,
6
+
AppBskyEmbedRecord,
7
+
AppBskyEmbedRecordWithMedia,
8
+
AppBskyEmbedVideo,
9
+
AppBskyFeedPost,
10
+
AtUri,
11
+
} from "@atproto/api";
12
+
import { useAtom } from "jotai";
13
+
import { useMemo } from "react";
14
+
15
+
import { imgCDNAtom, videoCDNAtom } from "./atoms";
16
+
import { useQueryIdentity, useQueryPost, useQueryProfile } from "./useQuery";
17
+
18
+
type QueryResultData<T extends (...args: any) => any> =
19
+
ReturnType<T> extends { data: infer D } | undefined ? D : never;
20
+
21
+
function asTyped<T extends { $type: string }>(obj: T): $Typed<T> {
22
+
return obj as $Typed<T>;
23
+
}
24
+
25
+
export function hydrateEmbedImages(
26
+
embed: AppBskyEmbedImages.Main,
27
+
did: string,
28
+
cdn: string
29
+
): $Typed<AppBskyEmbedImages.View> {
30
+
return asTyped({
31
+
$type: "app.bsky.embed.images#view" as const,
32
+
images: embed.images
33
+
.map((img) => {
34
+
const link = img.image.ref?.["$link"];
35
+
if (!link) return null;
36
+
return {
37
+
thumb: `https://${cdn}/img/feed_thumbnail/plain/${did}/${link}@jpeg`,
38
+
fullsize: `https://${cdn}/img/feed_fullsize/plain/${did}/${link}@jpeg`,
39
+
alt: img.alt || "",
40
+
aspectRatio: img.aspectRatio,
41
+
};
42
+
})
43
+
.filter(Boolean) as AppBskyEmbedImages.ViewImage[],
44
+
});
45
+
}
46
+
47
+
export function hydrateEmbedExternal(
48
+
embed: AppBskyEmbedExternal.Main,
49
+
did: string,
50
+
cdn: string
51
+
): $Typed<AppBskyEmbedExternal.View> {
52
+
return asTyped({
53
+
$type: "app.bsky.embed.external#view" as const,
54
+
external: {
55
+
uri: embed.external.uri,
56
+
title: embed.external.title,
57
+
description: embed.external.description,
58
+
thumb: embed.external.thumb?.ref?.$link
59
+
? `https://${cdn}/img/feed_thumbnail/plain/${did}/${embed.external.thumb.ref.$link}@jpeg`
60
+
: undefined,
61
+
},
62
+
});
63
+
}
64
+
65
+
export function hydrateEmbedVideo(
66
+
embed: AppBskyEmbedVideo.Main,
67
+
did: string,
68
+
videocdn: string
69
+
): $Typed<AppBskyEmbedVideo.View> {
70
+
const videoLink = embed.video.ref.$link;
71
+
return asTyped({
72
+
$type: "app.bsky.embed.video#view" as const,
73
+
playlist: `https://${videocdn}/watch/${did}/${videoLink}/playlist.m3u8`,
74
+
thumbnail: `https://${videocdn}/watch/${did}/${videoLink}/thumbnail.jpg`,
75
+
aspectRatio: embed.aspectRatio,
76
+
cid: videoLink,
77
+
});
78
+
}
79
+
80
+
function hydrateEmbedRecord(
81
+
embed: AppBskyEmbedRecord.Main,
82
+
quotedPost: QueryResultData<typeof useQueryPost>,
83
+
quotedProfile: QueryResultData<typeof useQueryProfile>,
84
+
quotedIdentity: QueryResultData<typeof useQueryIdentity>,
85
+
cdn: string
86
+
): $Typed<AppBskyEmbedRecord.View> | undefined {
87
+
if (!quotedPost || !quotedProfile || !quotedIdentity) {
88
+
return undefined;
89
+
}
90
+
91
+
const author: $Typed<AppBskyActorDefs.ProfileViewBasic> = asTyped({
92
+
$type: "app.bsky.actor.defs#profileViewBasic" as const,
93
+
did: quotedIdentity.did,
94
+
handle: quotedIdentity.handle,
95
+
displayName: quotedProfile.value.displayName ?? quotedIdentity.handle,
96
+
avatar: quotedProfile.value.avatar?.ref?.$link
97
+
? `https://${cdn}/img/avatar/plain/${quotedIdentity.did}/${quotedProfile.value.avatar.ref.$link}@jpeg`
98
+
: undefined,
99
+
viewer: {},
100
+
labels: [],
101
+
});
102
+
103
+
const viewRecord: $Typed<AppBskyEmbedRecord.ViewRecord> = asTyped({
104
+
$type: "app.bsky.embed.record#viewRecord" as const,
105
+
uri: quotedPost.uri,
106
+
cid: quotedPost.cid,
107
+
author,
108
+
value: quotedPost.value,
109
+
indexedAt: quotedPost.value.createdAt,
110
+
embeds: quotedPost.value.embed ? [quotedPost.value.embed] : undefined,
111
+
});
112
+
113
+
return asTyped({
114
+
$type: "app.bsky.embed.record#view" as const,
115
+
record: viewRecord,
116
+
});
117
+
}
118
+
119
+
function hydrateEmbedRecordWithMedia(
120
+
embed: AppBskyEmbedRecordWithMedia.Main,
121
+
mediaHydratedEmbed:
122
+
| $Typed<AppBskyEmbedImages.View>
123
+
| $Typed<AppBskyEmbedVideo.View>
124
+
| $Typed<AppBskyEmbedExternal.View>,
125
+
quotedPost: QueryResultData<typeof useQueryPost>,
126
+
quotedProfile: QueryResultData<typeof useQueryProfile>,
127
+
quotedIdentity: QueryResultData<typeof useQueryIdentity>,
128
+
cdn: string
129
+
): $Typed<AppBskyEmbedRecordWithMedia.View> | undefined {
130
+
const hydratedRecord = hydrateEmbedRecord(
131
+
embed.record,
132
+
quotedPost,
133
+
quotedProfile,
134
+
quotedIdentity,
135
+
cdn
136
+
);
137
+
138
+
if (!hydratedRecord) return undefined;
139
+
140
+
return asTyped({
141
+
$type: "app.bsky.embed.recordWithMedia#view" as const,
142
+
record: hydratedRecord,
143
+
media: mediaHydratedEmbed,
144
+
});
145
+
}
146
+
147
+
type HydratedEmbedView =
148
+
| $Typed<AppBskyEmbedImages.View>
149
+
| $Typed<AppBskyEmbedExternal.View>
150
+
| $Typed<AppBskyEmbedVideo.View>
151
+
| $Typed<AppBskyEmbedRecord.View>
152
+
| $Typed<AppBskyEmbedRecordWithMedia.View>;
153
+
154
+
export function useHydratedEmbed(
155
+
embed: AppBskyFeedPost.Record["embed"],
156
+
postAuthorDid: string | undefined
157
+
) {
158
+
const recordInfo = useMemo(() => {
159
+
if (AppBskyEmbedRecordWithMedia.isMain(embed)) {
160
+
const recordUri = embed.record.record.uri;
161
+
const quotedAuthorDid = new AtUri(recordUri).hostname;
162
+
return { recordUri, quotedAuthorDid, isRecordType: true };
163
+
} else if (AppBskyEmbedRecord.isMain(embed)) {
164
+
const recordUri = embed.record.uri;
165
+
const quotedAuthorDid = new AtUri(recordUri).hostname;
166
+
return { recordUri, quotedAuthorDid, isRecordType: true };
167
+
}
168
+
return {
169
+
recordUri: undefined,
170
+
quotedAuthorDid: undefined,
171
+
isRecordType: false,
172
+
};
173
+
}, [embed]);
174
+
175
+
const { isRecordType, recordUri, quotedAuthorDid } = recordInfo;
176
+
177
+
const usequerypostresults = useQueryPost(recordUri);
178
+
179
+
const profileUri = quotedAuthorDid
180
+
? `at://${quotedAuthorDid}/app.bsky.actor.profile/self`
181
+
: undefined;
182
+
183
+
const {
184
+
data: quotedProfile,
185
+
isLoading: isLoadingProfile,
186
+
error: profileError,
187
+
} = useQueryProfile(profileUri);
188
+
189
+
const [imgcdn] = useAtom(imgCDNAtom);
190
+
const [videocdn] = useAtom(videoCDNAtom);
191
+
192
+
const queryidentityresult = useQueryIdentity(quotedAuthorDid);
193
+
194
+
const hydratedEmbed: HydratedEmbedView | undefined = (() => {
195
+
if (!embed || !postAuthorDid) return undefined;
196
+
197
+
if (
198
+
isRecordType &&
199
+
(!usequerypostresults?.data ||
200
+
!quotedProfile ||
201
+
!queryidentityresult?.data)
202
+
) {
203
+
return undefined;
204
+
}
205
+
206
+
try {
207
+
if (AppBskyEmbedImages.isMain(embed)) {
208
+
return hydrateEmbedImages(embed, postAuthorDid, imgcdn);
209
+
} else if (AppBskyEmbedExternal.isMain(embed)) {
210
+
return hydrateEmbedExternal(embed, postAuthorDid, imgcdn);
211
+
} else if (AppBskyEmbedVideo.isMain(embed)) {
212
+
return hydrateEmbedVideo(embed, postAuthorDid, videocdn);
213
+
} else if (AppBskyEmbedRecord.isMain(embed)) {
214
+
return hydrateEmbedRecord(
215
+
embed,
216
+
usequerypostresults?.data,
217
+
quotedProfile,
218
+
queryidentityresult?.data,
219
+
imgcdn
220
+
);
221
+
} else if (AppBskyEmbedRecordWithMedia.isMain(embed)) {
222
+
let hydratedMedia:
223
+
| $Typed<AppBskyEmbedImages.View>
224
+
| $Typed<AppBskyEmbedVideo.View>
225
+
| $Typed<AppBskyEmbedExternal.View>
226
+
| undefined;
227
+
228
+
if (AppBskyEmbedImages.isMain(embed.media)) {
229
+
hydratedMedia = hydrateEmbedImages(
230
+
embed.media,
231
+
postAuthorDid,
232
+
imgcdn
233
+
);
234
+
} else if (AppBskyEmbedExternal.isMain(embed.media)) {
235
+
hydratedMedia = hydrateEmbedExternal(
236
+
embed.media,
237
+
postAuthorDid,
238
+
imgcdn
239
+
);
240
+
} else if (AppBskyEmbedVideo.isMain(embed.media)) {
241
+
hydratedMedia = hydrateEmbedVideo(
242
+
embed.media,
243
+
postAuthorDid,
244
+
videocdn
245
+
);
246
+
}
247
+
248
+
if (hydratedMedia) {
249
+
return hydrateEmbedRecordWithMedia(
250
+
embed,
251
+
hydratedMedia,
252
+
usequerypostresults?.data,
253
+
quotedProfile,
254
+
queryidentityresult?.data,
255
+
imgcdn
256
+
);
257
+
}
258
+
}
259
+
} catch (e) {
260
+
console.error("Error hydrating embed", e);
261
+
return undefined;
262
+
}
263
+
})();
264
+
265
+
const isLoading = isRecordType
266
+
? usequerypostresults?.isLoading ||
267
+
isLoadingProfile ||
268
+
queryidentityresult?.isLoading
269
+
: false;
270
+
271
+
const error =
272
+
usequerypostresults?.error || profileError || queryidentityresult?.error;
273
+
274
+
return { data: hydratedEmbed, isLoading, error };
275
+
}
+681
src/utils/useQuery.ts
+681
src/utils/useQuery.ts
···
1
+
import * as ATPAPI from "@atproto/api";
2
+
import {
3
+
infiniteQueryOptions,
4
+
type QueryFunctionContext,
5
+
queryOptions,
6
+
useInfiniteQuery,
7
+
useQuery,
8
+
type UseQueryResult} from "@tanstack/react-query";
9
+
import { useAtom } from "jotai";
10
+
11
+
import { constellationURLAtom, slingshotURLAtom } from "./atoms";
12
+
13
+
export function constructIdentityQuery(didorhandle?: string, slingshoturl?: string) {
14
+
return queryOptions({
15
+
queryKey: ["identity", didorhandle],
16
+
queryFn: async () => {
17
+
if (!didorhandle) return undefined as undefined
18
+
const res = await fetch(
19
+
`https://${slingshoturl}/xrpc/com.bad-example.identity.resolveMiniDoc?identifier=${encodeURIComponent(didorhandle)}`
20
+
);
21
+
if (!res.ok) throw new Error("Failed to fetch post");
22
+
try {
23
+
return (await res.json()) as {
24
+
did: string;
25
+
handle: string;
26
+
pds: string;
27
+
signing_key: string;
28
+
};
29
+
} catch (_e) {
30
+
return undefined;
31
+
}
32
+
},
33
+
staleTime: /*0,//*/ 5 * 60 * 1000, // 5 minutes
34
+
gcTime: /*0//*/5 * 60 * 1000,
35
+
});
36
+
}
37
+
export function useQueryIdentity(didorhandle: string): UseQueryResult<
38
+
{
39
+
did: string;
40
+
handle: string;
41
+
pds: string;
42
+
signing_key: string;
43
+
},
44
+
Error
45
+
>;
46
+
export function useQueryIdentity(): UseQueryResult<
47
+
undefined,
48
+
Error
49
+
>
50
+
export function useQueryIdentity(didorhandle?: string):
51
+
UseQueryResult<
52
+
{
53
+
did: string;
54
+
handle: string;
55
+
pds: string;
56
+
signing_key: string;
57
+
} | undefined,
58
+
Error
59
+
>
60
+
export function useQueryIdentity(didorhandle?: string) {
61
+
const [slingshoturl] = useAtom(slingshotURLAtom)
62
+
return useQuery(constructIdentityQuery(didorhandle, slingshoturl));
63
+
}
64
+
65
+
export function constructPostQuery(uri?: string, slingshoturl?: string) {
66
+
return queryOptions({
67
+
queryKey: ["post", uri],
68
+
queryFn: async () => {
69
+
if (!uri) return undefined as undefined
70
+
const res = await fetch(
71
+
`https://${slingshoturl}/xrpc/com.bad-example.repo.getUriRecord?at_uri=${encodeURIComponent(uri)}`
72
+
);
73
+
let data: any;
74
+
try {
75
+
data = await res.json();
76
+
} catch {
77
+
return undefined;
78
+
}
79
+
if (res.status === 400) return undefined;
80
+
if (data?.error === "InvalidRequest" && data.message?.includes("Could not find repo")) {
81
+
return undefined; // cache โnot foundโ
82
+
}
83
+
try {
84
+
if (!res.ok) throw new Error("Failed to fetch post");
85
+
return (data) as {
86
+
uri: string;
87
+
cid: string;
88
+
value: any;
89
+
};
90
+
} catch (_e) {
91
+
return undefined;
92
+
}
93
+
},
94
+
retry: (failureCount, error) => {
95
+
// dont retry 400 errors
96
+
if ((error as any)?.message?.includes("400")) return false;
97
+
return failureCount < 2;
98
+
},
99
+
staleTime: /*0,//*/ 5 * 60 * 1000, // 5 minutes
100
+
gcTime: /*0//*/5 * 60 * 1000,
101
+
});
102
+
}
103
+
export function useQueryPost(uri: string): UseQueryResult<
104
+
{
105
+
uri: string;
106
+
cid: string;
107
+
value: ATPAPI.AppBskyFeedPost.Record;
108
+
},
109
+
Error
110
+
>;
111
+
export function useQueryPost(): UseQueryResult<
112
+
undefined,
113
+
Error
114
+
>
115
+
export function useQueryPost(uri?: string):
116
+
UseQueryResult<
117
+
{
118
+
uri: string;
119
+
cid: string;
120
+
value: ATPAPI.AppBskyFeedPost.Record;
121
+
} | undefined,
122
+
Error
123
+
>
124
+
export function useQueryPost(uri?: string) {
125
+
const [slingshoturl] = useAtom(slingshotURLAtom)
126
+
return useQuery(constructPostQuery(uri, slingshoturl));
127
+
}
128
+
129
+
export function constructProfileQuery(uri?: string, slingshoturl?: string) {
130
+
return queryOptions({
131
+
queryKey: ["profile", uri],
132
+
queryFn: async () => {
133
+
if (!uri) return undefined as undefined
134
+
const res = await fetch(
135
+
`https://${slingshoturl}/xrpc/com.bad-example.repo.getUriRecord?at_uri=${encodeURIComponent(uri)}`
136
+
);
137
+
let data: any;
138
+
try {
139
+
data = await res.json();
140
+
} catch {
141
+
return undefined;
142
+
}
143
+
if (res.status === 400) return undefined;
144
+
if (data?.error === "InvalidRequest" && data.message?.includes("Could not find repo")) {
145
+
return undefined; // cache โnot foundโ
146
+
}
147
+
try {
148
+
if (!res.ok) throw new Error("Failed to fetch post");
149
+
return (data) as {
150
+
uri: string;
151
+
cid: string;
152
+
value: any;
153
+
};
154
+
} catch (_e) {
155
+
return undefined;
156
+
}
157
+
},
158
+
retry: (failureCount, error) => {
159
+
// dont retry 400 errors
160
+
if ((error as any)?.message?.includes("400")) return false;
161
+
return failureCount < 2;
162
+
},
163
+
staleTime: /*0,//*/ 5 * 60 * 1000, // 5 minutes
164
+
gcTime: /*0//*/5 * 60 * 1000,
165
+
});
166
+
}
167
+
export function useQueryProfile(uri: string): UseQueryResult<
168
+
{
169
+
uri: string;
170
+
cid: string;
171
+
value: ATPAPI.AppBskyActorProfile.Record;
172
+
},
173
+
Error
174
+
>;
175
+
export function useQueryProfile(): UseQueryResult<
176
+
undefined,
177
+
Error
178
+
>;
179
+
export function useQueryProfile(uri?: string):
180
+
UseQueryResult<
181
+
{
182
+
uri: string;
183
+
cid: string;
184
+
value: ATPAPI.AppBskyActorProfile.Record;
185
+
} | undefined,
186
+
Error
187
+
>
188
+
export function useQueryProfile(uri?: string) {
189
+
const [slingshoturl] = useAtom(slingshotURLAtom)
190
+
return useQuery(constructProfileQuery(uri, slingshoturl));
191
+
}
192
+
193
+
// export function constructConstellationQuery(
194
+
// method: "/links",
195
+
// target: string,
196
+
// collection: string,
197
+
// path: string,
198
+
// cursor?: string
199
+
// ): QueryOptions<linksRecordsResponse, Error>;
200
+
// export function constructConstellationQuery(
201
+
// method: "/links/distinct-dids",
202
+
// target: string,
203
+
// collection: string,
204
+
// path: string,
205
+
// cursor?: string
206
+
// ): QueryOptions<linksDidsResponse, Error>;
207
+
// export function constructConstellationQuery(
208
+
// method: "/links/count",
209
+
// target: string,
210
+
// collection: string,
211
+
// path: string,
212
+
// cursor?: string
213
+
// ): QueryOptions<linksCountResponse, Error>;
214
+
// export function constructConstellationQuery(
215
+
// method: "/links/count/distinct-dids",
216
+
// target: string,
217
+
// collection: string,
218
+
// path: string,
219
+
// cursor?: string
220
+
// ): QueryOptions<linksCountResponse, Error>;
221
+
// export function constructConstellationQuery(
222
+
// method: "/links/all",
223
+
// target: string
224
+
// ): QueryOptions<linksAllResponse, Error>;
225
+
export function constructConstellationQuery(query?:{
226
+
constellation: string,
227
+
method:
228
+
| "/links"
229
+
| "/links/distinct-dids"
230
+
| "/links/count"
231
+
| "/links/count/distinct-dids"
232
+
| "/links/all"
233
+
| "undefined",
234
+
target: string,
235
+
collection?: string,
236
+
path?: string,
237
+
cursor?: string,
238
+
dids?: string[]
239
+
}
240
+
) {
241
+
// : QueryOptions<
242
+
// | linksRecordsResponse
243
+
// | linksDidsResponse
244
+
// | linksCountResponse
245
+
// | linksAllResponse
246
+
// | undefined,
247
+
// Error
248
+
// >
249
+
return queryOptions({
250
+
queryKey: ["constellation", query?.method, query?.target, query?.collection, query?.path, query?.cursor, query?.dids] as const,
251
+
queryFn: async () => {
252
+
if (!query || query.method === "undefined") return undefined as undefined
253
+
const method = query.method
254
+
const target = query.target
255
+
const collection = query?.collection
256
+
const path = query?.path
257
+
const cursor = query.cursor
258
+
const dids = query?.dids
259
+
const res = await fetch(
260
+
`https://${query.constellation}${method}?target=${encodeURIComponent(target)}${collection ? `&collection=${encodeURIComponent(collection)}` : ""}${path ? `&path=${encodeURIComponent(path)}` : ""}${cursor ? `&cursor=${encodeURIComponent(cursor)}` : ""}${dids ? dids.map((did) => `&did=${encodeURIComponent(did)}`).join("") : ""}`
261
+
);
262
+
if (!res.ok) throw new Error("Failed to fetch post");
263
+
try {
264
+
switch (method) {
265
+
case "/links":
266
+
return (await res.json()) as linksRecordsResponse;
267
+
case "/links/distinct-dids":
268
+
return (await res.json()) as linksDidsResponse;
269
+
case "/links/count":
270
+
return (await res.json()) as linksCountResponse;
271
+
case "/links/count/distinct-dids":
272
+
return (await res.json()) as linksCountResponse;
273
+
case "/links/all":
274
+
return (await res.json()) as linksAllResponse;
275
+
default:
276
+
return undefined;
277
+
}
278
+
} catch (_e) {
279
+
return undefined;
280
+
}
281
+
},
282
+
// enforce short lifespan
283
+
staleTime: /*0,//*/ 5 * 60 * 1000, // 5 minutes
284
+
gcTime: /*0//*/5 * 60 * 1000,
285
+
});
286
+
}
287
+
export function useQueryConstellation(query: {
288
+
method: "/links";
289
+
target: string;
290
+
collection: string;
291
+
path: string;
292
+
cursor?: string;
293
+
dids?: string[];
294
+
}): UseQueryResult<linksRecordsResponse, Error>;
295
+
export function useQueryConstellation(query: {
296
+
method: "/links/distinct-dids";
297
+
target: string;
298
+
collection: string;
299
+
path: string;
300
+
cursor?: string;
301
+
}): UseQueryResult<linksDidsResponse, Error>;
302
+
export function useQueryConstellation(query: {
303
+
method: "/links/count";
304
+
target: string;
305
+
collection: string;
306
+
path: string;
307
+
cursor?: string;
308
+
}): UseQueryResult<linksCountResponse, Error>;
309
+
export function useQueryConstellation(query: {
310
+
method: "/links/count/distinct-dids";
311
+
target: string;
312
+
collection: string;
313
+
path: string;
314
+
cursor?: string;
315
+
}): UseQueryResult<linksCountResponse, Error>;
316
+
export function useQueryConstellation(query: {
317
+
method: "/links/all";
318
+
target: string;
319
+
}): UseQueryResult<linksAllResponse, Error>;
320
+
export function useQueryConstellation(): undefined;
321
+
export function useQueryConstellation(query: {
322
+
method: "undefined";
323
+
target: string;
324
+
}): undefined;
325
+
export function useQueryConstellation(query?: {
326
+
method:
327
+
| "/links"
328
+
| "/links/distinct-dids"
329
+
| "/links/count"
330
+
| "/links/count/distinct-dids"
331
+
| "/links/all"
332
+
| "undefined";
333
+
target: string;
334
+
collection?: string;
335
+
path?: string;
336
+
cursor?: string;
337
+
dids?: string[];
338
+
}):
339
+
| UseQueryResult<
340
+
| linksRecordsResponse
341
+
| linksDidsResponse
342
+
| linksCountResponse
343
+
| linksAllResponse
344
+
| undefined,
345
+
Error
346
+
>
347
+
| undefined {
348
+
//if (!query) return;
349
+
const [constellationurl] = useAtom(constellationURLAtom)
350
+
return useQuery(
351
+
constructConstellationQuery(query && {constellation: constellationurl, ...query})
352
+
);
353
+
}
354
+
355
+
type linksRecord = {
356
+
did: string;
357
+
collection: string;
358
+
rkey: string;
359
+
};
360
+
export type linksRecordsResponse = {
361
+
total: string;
362
+
linking_records: linksRecord[];
363
+
cursor?: string;
364
+
};
365
+
type linksDidsResponse = {
366
+
total: string;
367
+
linking_dids: string[];
368
+
cursor?: string;
369
+
};
370
+
type linksCountResponse = {
371
+
total: string;
372
+
};
373
+
export type linksAllResponse = {
374
+
links: Record<
375
+
string,
376
+
Record<
377
+
string,
378
+
{
379
+
records: number;
380
+
distinct_dids: number;
381
+
}
382
+
>
383
+
>;
384
+
};
385
+
386
+
export function constructFeedSkeletonQuery(options?: {
387
+
feedUri: string;
388
+
agent?: ATPAPI.Agent;
389
+
isAuthed: boolean;
390
+
pdsUrl?: string;
391
+
feedServiceDid?: string;
392
+
}) {
393
+
return queryOptions({
394
+
// The query key includes all dependencies to ensure it refetches when they change
395
+
queryKey: ["feedSkeleton", options?.feedUri, { isAuthed: options?.isAuthed, did: options?.agent?.did }],
396
+
queryFn: async () => {
397
+
if (!options) return undefined as undefined
398
+
const { feedUri, agent, isAuthed, pdsUrl, feedServiceDid } = options;
399
+
if (isAuthed) {
400
+
// Authenticated flow
401
+
if (!agent || !pdsUrl || !feedServiceDid) {
402
+
throw new Error("Missing required info for authenticated feed fetch.");
403
+
}
404
+
const url = `${pdsUrl}/xrpc/app.bsky.feed.getFeedSkeleton?feed=${encodeURIComponent(feedUri)}`;
405
+
const res = await agent.fetchHandler(url, {
406
+
method: "GET",
407
+
headers: {
408
+
"atproto-proxy": `${feedServiceDid}#bsky_fg`,
409
+
"Content-Type": "application/json",
410
+
},
411
+
});
412
+
if (!res.ok) throw new Error(`Authenticated feed fetch failed: ${res.statusText}`);
413
+
return (await res.json()) as ATPAPI.AppBskyFeedGetFeedSkeleton.OutputSchema;
414
+
} else {
415
+
// Unauthenticated flow (using a public PDS/AppView)
416
+
const url = `https://discover.bsky.app/xrpc/app.bsky.feed.getFeedSkeleton?feed=${encodeURIComponent(feedUri)}`;
417
+
const res = await fetch(url);
418
+
if (!res.ok) throw new Error(`Public feed fetch failed: ${res.statusText}`);
419
+
return (await res.json()) as ATPAPI.AppBskyFeedGetFeedSkeleton.OutputSchema;
420
+
}
421
+
},
422
+
//enabled: !!feedUri && (isAuthed ? !!agent && !!pdsUrl && !!feedServiceDid : true),
423
+
});
424
+
}
425
+
426
+
export function useQueryFeedSkeleton(options?: {
427
+
feedUri: string;
428
+
agent?: ATPAPI.Agent;
429
+
isAuthed: boolean;
430
+
pdsUrl?: string;
431
+
feedServiceDid?: string;
432
+
}) {
433
+
return useQuery(constructFeedSkeletonQuery(options));
434
+
}
435
+
436
+
export function constructPreferencesQuery(agent?: ATPAPI.Agent | undefined, pdsUrl?: string | undefined) {
437
+
return queryOptions({
438
+
queryKey: ['preferences', agent?.did],
439
+
queryFn: async () => {
440
+
if (!agent || !pdsUrl) throw new Error("Agent or PDS URL not available");
441
+
const url = `${pdsUrl}/xrpc/app.bsky.actor.getPreferences`;
442
+
const res = await agent.fetchHandler(url, { method: "GET" });
443
+
if (!res.ok) throw new Error("Failed to fetch preferences");
444
+
return res.json();
445
+
},
446
+
});
447
+
}
448
+
export function useQueryPreferences(options: {
449
+
agent?: ATPAPI.Agent | undefined, pdsUrl?: string | undefined
450
+
}) {
451
+
return useQuery(constructPreferencesQuery(options.agent, options.pdsUrl));
452
+
}
453
+
454
+
455
+
456
+
export function constructArbitraryQuery(uri?: string, slingshoturl?: string) {
457
+
return queryOptions({
458
+
queryKey: ["arbitrary", uri],
459
+
queryFn: async () => {
460
+
if (!uri) return undefined as undefined
461
+
const res = await fetch(
462
+
`https://${slingshoturl}/xrpc/com.bad-example.repo.getUriRecord?at_uri=${encodeURIComponent(uri)}`
463
+
);
464
+
let data: any;
465
+
try {
466
+
data = await res.json();
467
+
} catch {
468
+
return undefined;
469
+
}
470
+
if (res.status === 400) return undefined;
471
+
if (data?.error === "InvalidRequest" && data.message?.includes("Could not find repo")) {
472
+
return undefined; // cache โnot foundโ
473
+
}
474
+
try {
475
+
if (!res.ok) throw new Error("Failed to fetch post");
476
+
return (data) as {
477
+
uri: string;
478
+
cid: string;
479
+
value: any;
480
+
};
481
+
} catch (_e) {
482
+
return undefined;
483
+
}
484
+
},
485
+
retry: (failureCount, error) => {
486
+
// dont retry 400 errors
487
+
if ((error as any)?.message?.includes("400")) return false;
488
+
return failureCount < 2;
489
+
},
490
+
staleTime: /*0,//*/ 5 * 60 * 1000, // 5 minutes
491
+
gcTime: /*0//*/5 * 60 * 1000,
492
+
});
493
+
}
494
+
export function useQueryArbitrary(uri: string): UseQueryResult<
495
+
{
496
+
uri: string;
497
+
cid: string;
498
+
value: any;
499
+
},
500
+
Error
501
+
>;
502
+
export function useQueryArbitrary(): UseQueryResult<
503
+
undefined,
504
+
Error
505
+
>;
506
+
export function useQueryArbitrary(uri?: string): UseQueryResult<
507
+
{
508
+
uri: string;
509
+
cid: string;
510
+
value: any;
511
+
} | undefined,
512
+
Error
513
+
>;
514
+
export function useQueryArbitrary(uri?: string) {
515
+
const [slingshoturl] = useAtom(slingshotURLAtom)
516
+
return useQuery(constructArbitraryQuery(uri, slingshoturl));
517
+
}
518
+
519
+
export function constructFallbackNothingQuery(){
520
+
return queryOptions({
521
+
queryKey: ["nothing"],
522
+
queryFn: async () => {
523
+
return undefined
524
+
},
525
+
});
526
+
}
527
+
528
+
type ListRecordsResponse = {
529
+
cursor?: string;
530
+
records: {
531
+
uri: string;
532
+
cid: string;
533
+
value: ATPAPI.AppBskyFeedPost.Record;
534
+
}[];
535
+
};
536
+
537
+
export function constructAuthorFeedQuery(did: string, pdsUrl: string) {
538
+
return queryOptions({
539
+
queryKey: ['authorFeed', did],
540
+
queryFn: async ({ pageParam }: QueryFunctionContext) => {
541
+
const limit = 25;
542
+
543
+
const cursor = pageParam as string | undefined;
544
+
const cursorParam = cursor ? `&cursor=${cursor}` : '';
545
+
546
+
const url = `${pdsUrl}/xrpc/com.atproto.repo.listRecords?repo=${did}&collection=app.bsky.feed.post&limit=${limit}${cursorParam}`;
547
+
548
+
const res = await fetch(url);
549
+
if (!res.ok) throw new Error("Failed to fetch author's posts");
550
+
551
+
return res.json() as Promise<ListRecordsResponse>;
552
+
},
553
+
});
554
+
}
555
+
556
+
export function useInfiniteQueryAuthorFeed(did: string | undefined, pdsUrl: string | undefined) {
557
+
const { queryKey, queryFn } = constructAuthorFeedQuery(did!, pdsUrl!);
558
+
559
+
return useInfiniteQuery({
560
+
queryKey,
561
+
queryFn,
562
+
initialPageParam: undefined as never, // ???? what is this shit
563
+
getNextPageParam: (lastPage) => lastPage.cursor as null | undefined,
564
+
enabled: !!did && !!pdsUrl,
565
+
});
566
+
}
567
+
568
+
type FeedSkeletonPage = ATPAPI.AppBskyFeedGetFeedSkeleton.OutputSchema;
569
+
570
+
export function constructInfiniteFeedSkeletonQuery(options: {
571
+
feedUri: string;
572
+
agent?: ATPAPI.Agent;
573
+
isAuthed: boolean;
574
+
pdsUrl?: string;
575
+
feedServiceDid?: string;
576
+
}) {
577
+
const { feedUri, agent, isAuthed, pdsUrl, feedServiceDid } = options;
578
+
579
+
return queryOptions({
580
+
queryKey: ["feedSkeleton", feedUri, { isAuthed, did: agent?.did }],
581
+
582
+
queryFn: async ({ pageParam }: QueryFunctionContext): Promise<FeedSkeletonPage> => {
583
+
const cursorParam = pageParam ? `&cursor=${pageParam}` : "";
584
+
585
+
if (isAuthed) {
586
+
if (!agent || !pdsUrl || !feedServiceDid) {
587
+
throw new Error("Missing required info for authenticated feed fetch.");
588
+
}
589
+
const url = `${pdsUrl}/xrpc/app.bsky.feed.getFeedSkeleton?feed=${encodeURIComponent(feedUri)}${cursorParam}`;
590
+
const res = await agent.fetchHandler(url, {
591
+
method: "GET",
592
+
headers: {
593
+
"atproto-proxy": `${feedServiceDid}#bsky_fg`,
594
+
"Content-Type": "application/json",
595
+
},
596
+
});
597
+
if (!res.ok) throw new Error(`Authenticated feed fetch failed: ${res.statusText}`);
598
+
return (await res.json()) as FeedSkeletonPage;
599
+
} else {
600
+
const url = `https://discover.bsky.app/xrpc/app.bsky.feed.getFeedSkeleton?feed=${encodeURIComponent(feedUri)}${cursorParam}`;
601
+
const res = await fetch(url);
602
+
if (!res.ok) throw new Error(`Public feed fetch failed: ${res.statusText}`);
603
+
return (await res.json()) as FeedSkeletonPage;
604
+
}
605
+
},
606
+
});
607
+
}
608
+
609
+
export function useInfiniteQueryFeedSkeleton(options: {
610
+
feedUri: string;
611
+
agent?: ATPAPI.Agent;
612
+
isAuthed: boolean;
613
+
pdsUrl?: string;
614
+
feedServiceDid?: string;
615
+
}) {
616
+
const { queryKey, queryFn } = constructInfiniteFeedSkeletonQuery(options);
617
+
618
+
return {...useInfiniteQuery({
619
+
queryKey,
620
+
queryFn,
621
+
initialPageParam: undefined as never,
622
+
getNextPageParam: (lastPage) => lastPage.cursor as null | undefined,
623
+
staleTime: Infinity,
624
+
refetchOnWindowFocus: false,
625
+
enabled: !!options.feedUri && (options.isAuthed ? !!options.agent && !!options.pdsUrl && !!options.feedServiceDid : true),
626
+
}), queryKey: queryKey};
627
+
}
628
+
629
+
630
+
export function yknowIReallyHateThisButWhateverGuardedConstructConstellationInfiniteQueryLinks(query?: {
631
+
constellation: string,
632
+
method: '/links'
633
+
target?: string
634
+
collection: string
635
+
path: string
636
+
}) {
637
+
console.log(
638
+
'yknowIReallyHateThisButWhateverGuardedConstructConstellationInfiniteQueryLinks',
639
+
query,
640
+
)
641
+
642
+
return infiniteQueryOptions({
643
+
enabled: !!query?.target,
644
+
queryKey: [
645
+
'reddwarf_constellation',
646
+
query?.method,
647
+
query?.target,
648
+
query?.collection,
649
+
query?.path,
650
+
] as const,
651
+
652
+
queryFn: async ({pageParam}: {pageParam?: string}) => {
653
+
if (!query || !query?.target) return undefined
654
+
655
+
const method = query.method
656
+
const target = query.target
657
+
const collection = query.collection
658
+
const path = query.path
659
+
const cursor = pageParam
660
+
661
+
const res = await fetch(
662
+
`https://${query.constellation}${method}?target=${encodeURIComponent(target)}${
663
+
collection ? `&collection=${encodeURIComponent(collection)}` : ''
664
+
}${path ? `&path=${encodeURIComponent(path)}` : ''}${
665
+
cursor ? `&cursor=${encodeURIComponent(cursor)}` : ''
666
+
}`,
667
+
)
668
+
669
+
if (!res.ok) throw new Error('Failed to fetch')
670
+
671
+
return (await res.json()) as linksRecordsResponse
672
+
},
673
+
674
+
getNextPageParam: lastPage => {
675
+
return (lastPage as any)?.cursor ?? undefined
676
+
},
677
+
initialPageParam: undefined,
678
+
staleTime: 5 * 60 * 1000,
679
+
gcTime: 5 * 60 * 1000,
680
+
})
681
+
}
+1
-1
tsconfig.json
+1
-1
tsconfig.json
+49
-5
vite.config.ts
+49
-5
vite.config.ts
···
1
-
import { defineConfig } from "vite";
1
+
import { resolve } from "node:path";
2
+
3
+
import tailwindcss from "@tailwindcss/vite";
4
+
import { TanStackRouterVite } from "@tanstack/router-plugin/vite";
2
5
import viteReact from "@vitejs/plugin-react";
3
-
import tailwindcss from "@tailwindcss/vite";
6
+
import AutoImport from 'unplugin-auto-import/vite'
7
+
import IconsResolver from 'unplugin-icons/resolver'
8
+
import Icons from 'unplugin-icons/vite'
9
+
import { defineConfig } from "vite";
10
+
11
+
import { generateMetadataPlugin } from "./oauthdev.mts";
12
+
13
+
const PROD_URL = "https://reddwarf.app"
14
+
const DEV_URL = "https://local3768forumtest.whey.party"
4
15
5
-
import { TanStackRouterVite } from "@tanstack/router-plugin/vite";
6
-
import { resolve } from "node:path";
16
+
function shp(url: string): string {
17
+
return url.replace(/^https?:\/\//, '');
18
+
}
7
19
8
20
// https://vitejs.dev/config/
9
21
export default defineConfig({
10
22
plugins: [
23
+
generateMetadataPlugin({
24
+
prod: PROD_URL,
25
+
dev: DEV_URL,
26
+
}),
11
27
TanStackRouterVite({ autoCodeSplitting: true }),
12
-
viteReact(),
28
+
viteReact({
29
+
babel: {
30
+
plugins: ['babel-plugin-react-compiler'],
31
+
},
32
+
}),
13
33
tailwindcss(),
34
+
AutoImport({
35
+
include: [
36
+
/\.[tj]sx?$/, // .ts, .tsx, .js, .jsx
37
+
],
38
+
resolvers: [
39
+
IconsResolver({
40
+
prefix: 'Icon',
41
+
extension: 'jsx',
42
+
enabledCollections: ['mdi','material-symbols'],
43
+
}),
44
+
],
45
+
dts: 'src/auto-imports.d.ts',
46
+
}),
47
+
Icons({
48
+
//autoInstall: true,
49
+
compiler: 'jsx',
50
+
jsx: 'react'
51
+
}),
14
52
],
15
53
// test: {
16
54
// globals: true,
···
21
59
"@": resolve(__dirname, "./src"),
22
60
"~": resolve(__dirname, "./src"),
23
61
},
62
+
},
63
+
server: {
64
+
allowedHosts: [shp(PROD_URL),shp(DEV_URL)],
65
+
},
66
+
css: {
67
+
devSourcemap: true,
24
68
},
25
69
});