+11
.cta.json
+11
.cta.json
+9
.gitignore
+9
.gitignore
+11
.vscode/settings.json
+11
.vscode/settings.json
+73
README.md
+73
README.md
···
1
+
# ForumTest - ATProto forum built with ESAV
2
+
its an atproto forum built with [ESAV](https://tangled.sh/@whey.party/esav), an elasticsearch-based configurable generic appview.
3
+
4
+
this project explores how far you can push ESAV as a backend with a example product (this forum atproto forum test thing). everything goes through ESAV, except for identity resolution, i have a deno deploy app that i use and share across multiple projects (is used in red dwarf too)
5
+
6
+
i havent enabled a CDN yet so currently all images load using getBlob
7
+
8
+
Live at: [https://forumtest.whey.party](https://forumtest.whey.party)
9
+
Discuss at: [https://forumtest.whey.party/f/@forumtest.whey.party](https://forumtest.whey.party/f/@forumtest.whey.party)
10
+
11
+
## ESAV config
12
+
custom record types:
13
+
```json
14
+
"record_types": [
15
+
"com.example.ft.topic.post",
16
+
"com.example.ft.topic.reaction",
17
+
"com.example.ft.topic.moderation",
18
+
"com.example.ft.forum.definition",
19
+
"com.example.ft.forum.layout",
20
+
"com.example.ft.forum.request",
21
+
"com.example.ft.forum.accept",
22
+
"com.example.ft.forum.category"
23
+
],
24
+
```
25
+
26
+
custom indexes:
27
+
```json
28
+
"index_fields": {
29
+
"com.example.ft.topic.reaction": {
30
+
"subject": {
31
+
"id": "reactionSubject",
32
+
"type": "keyword"
33
+
},
34
+
"reactionEmoji": {
35
+
"id": "reactionEmoji",
36
+
"type": "keyword"
37
+
}
38
+
},
39
+
"com.example.ft.topic.post": {
40
+
"text": {
41
+
"id": "text",
42
+
"type": "text"
43
+
},
44
+
"title": {
45
+
"id": "title",
46
+
"type": "text"
47
+
},
48
+
"reply.root.uri": {
49
+
"id": "root",
50
+
"type": "keyword"
51
+
},
52
+
"reply.parent.uri": {
53
+
"id": "parent",
54
+
"type": "keyword"
55
+
},
56
+
"forum": {
57
+
"id": "forum",
58
+
"type": "keyword"
59
+
}
60
+
},
61
+
"com.example.ft.forum.definition": {
62
+
"description": {
63
+
"id": "description",
64
+
"type": "text"
65
+
},
66
+
"displayName": {
67
+
"id": "displayName",
68
+
"type": "text"
69
+
}
70
+
}
71
+
}
72
+
73
+
```
+20
index.html
+20
index.html
···
1
+
<!DOCTYPE html>
2
+
<html lang="en">
3
+
<head>
4
+
<meta charset="UTF-8" />
5
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+
<link rel="icon" href="/favicon.ico" />
7
+
<meta name="theme-color" content="#000000" />
8
+
<meta
9
+
name="description"
10
+
content="atproto forum test"
11
+
/>
12
+
<link rel="apple-touch-icon" href="/logo192.png" />
13
+
<link rel="manifest" href="/manifest.json" />
14
+
<title>ForumTest</title>
15
+
</head>
16
+
<body class="bg-gray-900">
17
+
<div id="app" class="overflow-auto h-dvh max-h-dvh"></div>
18
+
<script type="module" src="/src/main.tsx"></script>
19
+
</body>
20
+
</html>
+5209
package-lock.json
+5209
package-lock.json
···
1
+
{
2
+
"name": "forumtest",
3
+
"lockfileVersion": 3,
4
+
"requires": true,
5
+
"packages": {
6
+
"": {
7
+
"name": "forumtest",
8
+
"dependencies": {
9
+
"@atproto/api": "^0.16.0",
10
+
"@radix-ui/react-dialog": "^1.1.14",
11
+
"@radix-ui/react-icons": "^1.3.2",
12
+
"@radix-ui/react-popover": "^1.1.14",
13
+
"@radix-ui/react-select": "^2.2.5",
14
+
"@tailwindcss/vite": "^4.1.11",
15
+
"@tanstack/react-query": "^5.84.1",
16
+
"@tanstack/react-router": "^1.130.2",
17
+
"@tanstack/react-router-devtools": "^1.130.2",
18
+
"@tanstack/router-plugin": "^1.121.2",
19
+
"idb-keyval": "^6.2.2",
20
+
"react": "^19.0.0",
21
+
"react-dom": "^19.0.0",
22
+
"tailwindcss": "^4.1.11"
23
+
},
24
+
"devDependencies": {
25
+
"@testing-library/dom": "^10.4.0",
26
+
"@testing-library/react": "^16.2.0",
27
+
"@types/react": "^19.0.8",
28
+
"@types/react-dom": "^19.0.3",
29
+
"@vitejs/plugin-react": "^4.3.4",
30
+
"jsdom": "^26.0.0",
31
+
"typescript": "^5.7.2",
32
+
"vite": "^6.3.5",
33
+
"vitest": "^3.0.5",
34
+
"web-vitals": "^4.2.4"
35
+
}
36
+
},
37
+
"node_modules/@ampproject/remapping": {
38
+
"version": "2.3.0",
39
+
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
40
+
"integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
41
+
"license": "Apache-2.0",
42
+
"dependencies": {
43
+
"@jridgewell/gen-mapping": "^0.3.5",
44
+
"@jridgewell/trace-mapping": "^0.3.24"
45
+
},
46
+
"engines": {
47
+
"node": ">=6.0.0"
48
+
}
49
+
},
50
+
"node_modules/@asamuzakjp/css-color": {
51
+
"version": "3.2.0",
52
+
"resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.2.0.tgz",
53
+
"integrity": "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==",
54
+
"dev": true,
55
+
"license": "MIT",
56
+
"dependencies": {
57
+
"@csstools/css-calc": "^2.1.3",
58
+
"@csstools/css-color-parser": "^3.0.9",
59
+
"@csstools/css-parser-algorithms": "^3.0.4",
60
+
"@csstools/css-tokenizer": "^3.0.3",
61
+
"lru-cache": "^10.4.3"
62
+
}
63
+
},
64
+
"node_modules/@asamuzakjp/css-color/node_modules/lru-cache": {
65
+
"version": "10.4.3",
66
+
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
67
+
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
68
+
"dev": true,
69
+
"license": "ISC"
70
+
},
71
+
"node_modules/@atproto/api": {
72
+
"version": "0.16.0",
73
+
"resolved": "https://registry.npmjs.org/@atproto/api/-/api-0.16.0.tgz",
74
+
"integrity": "sha512-PQHeae6mz/L1YirUslfci7bknfg3RrSZjXpYwzLICxIOvqGKIkOi0+qukC2Py238RhXRo8YZ9dCuole9HQBXDw==",
75
+
"license": "MIT",
76
+
"dependencies": {
77
+
"@atproto/common-web": "^0.4.2",
78
+
"@atproto/lexicon": "^0.4.12",
79
+
"@atproto/syntax": "^0.4.0",
80
+
"@atproto/xrpc": "^0.7.1",
81
+
"await-lock": "^2.2.2",
82
+
"multiformats": "^9.9.0",
83
+
"tlds": "^1.234.0",
84
+
"zod": "^3.23.8"
85
+
}
86
+
},
87
+
"node_modules/@atproto/common-web": {
88
+
"version": "0.4.2",
89
+
"resolved": "https://registry.npmjs.org/@atproto/common-web/-/common-web-0.4.2.tgz",
90
+
"integrity": "sha512-vrXwGNoFGogodjQvJDxAeP3QbGtawgZute2ed1XdRO0wMixLk3qewtikZm06H259QDJVu6voKC5mubml+WgQUw==",
91
+
"license": "MIT",
92
+
"dependencies": {
93
+
"graphemer": "^1.4.0",
94
+
"multiformats": "^9.9.0",
95
+
"uint8arrays": "3.0.0",
96
+
"zod": "^3.23.8"
97
+
}
98
+
},
99
+
"node_modules/@atproto/lexicon": {
100
+
"version": "0.4.12",
101
+
"resolved": "https://registry.npmjs.org/@atproto/lexicon/-/lexicon-0.4.12.tgz",
102
+
"integrity": "sha512-fcEvEQ1GpQYF5igZ4IZjPWEoWVpsEF22L9RexxLS3ptfySXLflEyH384e7HITzO/73McDeaJx3lqHIuqn9ulnw==",
103
+
"license": "MIT",
104
+
"dependencies": {
105
+
"@atproto/common-web": "^0.4.2",
106
+
"@atproto/syntax": "^0.4.0",
107
+
"iso-datestring-validator": "^2.2.2",
108
+
"multiformats": "^9.9.0",
109
+
"zod": "^3.23.8"
110
+
}
111
+
},
112
+
"node_modules/@atproto/syntax": {
113
+
"version": "0.4.0",
114
+
"resolved": "https://registry.npmjs.org/@atproto/syntax/-/syntax-0.4.0.tgz",
115
+
"integrity": "sha512-b9y5ceHS8YKOfP3mdKmwAx5yVj9294UN7FG2XzP6V5aKUdFazEYRnR9m5n5ZQFKa3GNvz7de9guZCJ/sUTcOAA==",
116
+
"license": "MIT"
117
+
},
118
+
"node_modules/@atproto/xrpc": {
119
+
"version": "0.7.1",
120
+
"resolved": "https://registry.npmjs.org/@atproto/xrpc/-/xrpc-0.7.1.tgz",
121
+
"integrity": "sha512-ANHEzlskYlMEdH18m+Itp3a8d0pEJao2qoDybDoMupTnoeNkya4VKIaOgAi6ERQnqatBBZyn9asW+7rJmSt/8g==",
122
+
"license": "MIT",
123
+
"dependencies": {
124
+
"@atproto/lexicon": "^0.4.12",
125
+
"zod": "^3.23.8"
126
+
}
127
+
},
128
+
"node_modules/@babel/code-frame": {
129
+
"version": "7.27.1",
130
+
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
131
+
"integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==",
132
+
"license": "MIT",
133
+
"dependencies": {
134
+
"@babel/helper-validator-identifier": "^7.27.1",
135
+
"js-tokens": "^4.0.0",
136
+
"picocolors": "^1.1.1"
137
+
},
138
+
"engines": {
139
+
"node": ">=6.9.0"
140
+
}
141
+
},
142
+
"node_modules/@babel/compat-data": {
143
+
"version": "7.28.0",
144
+
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz",
145
+
"integrity": "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==",
146
+
"license": "MIT",
147
+
"engines": {
148
+
"node": ">=6.9.0"
149
+
}
150
+
},
151
+
"node_modules/@babel/core": {
152
+
"version": "7.28.0",
153
+
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz",
154
+
"integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==",
155
+
"license": "MIT",
156
+
"dependencies": {
157
+
"@ampproject/remapping": "^2.2.0",
158
+
"@babel/code-frame": "^7.27.1",
159
+
"@babel/generator": "^7.28.0",
160
+
"@babel/helper-compilation-targets": "^7.27.2",
161
+
"@babel/helper-module-transforms": "^7.27.3",
162
+
"@babel/helpers": "^7.27.6",
163
+
"@babel/parser": "^7.28.0",
164
+
"@babel/template": "^7.27.2",
165
+
"@babel/traverse": "^7.28.0",
166
+
"@babel/types": "^7.28.0",
167
+
"convert-source-map": "^2.0.0",
168
+
"debug": "^4.1.0",
169
+
"gensync": "^1.0.0-beta.2",
170
+
"json5": "^2.2.3",
171
+
"semver": "^6.3.1"
172
+
},
173
+
"engines": {
174
+
"node": ">=6.9.0"
175
+
},
176
+
"funding": {
177
+
"type": "opencollective",
178
+
"url": "https://opencollective.com/babel"
179
+
}
180
+
},
181
+
"node_modules/@babel/generator": {
182
+
"version": "7.28.0",
183
+
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.0.tgz",
184
+
"integrity": "sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==",
185
+
"license": "MIT",
186
+
"dependencies": {
187
+
"@babel/parser": "^7.28.0",
188
+
"@babel/types": "^7.28.0",
189
+
"@jridgewell/gen-mapping": "^0.3.12",
190
+
"@jridgewell/trace-mapping": "^0.3.28",
191
+
"jsesc": "^3.0.2"
192
+
},
193
+
"engines": {
194
+
"node": ">=6.9.0"
195
+
}
196
+
},
197
+
"node_modules/@babel/helper-annotate-as-pure": {
198
+
"version": "7.27.3",
199
+
"resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz",
200
+
"integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==",
201
+
"license": "MIT",
202
+
"dependencies": {
203
+
"@babel/types": "^7.27.3"
204
+
},
205
+
"engines": {
206
+
"node": ">=6.9.0"
207
+
}
208
+
},
209
+
"node_modules/@babel/helper-compilation-targets": {
210
+
"version": "7.27.2",
211
+
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz",
212
+
"integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==",
213
+
"license": "MIT",
214
+
"dependencies": {
215
+
"@babel/compat-data": "^7.27.2",
216
+
"@babel/helper-validator-option": "^7.27.1",
217
+
"browserslist": "^4.24.0",
218
+
"lru-cache": "^5.1.1",
219
+
"semver": "^6.3.1"
220
+
},
221
+
"engines": {
222
+
"node": ">=6.9.0"
223
+
}
224
+
},
225
+
"node_modules/@babel/helper-create-class-features-plugin": {
226
+
"version": "7.27.1",
227
+
"resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.27.1.tgz",
228
+
"integrity": "sha512-QwGAmuvM17btKU5VqXfb+Giw4JcN0hjuufz3DYnpeVDvZLAObloM77bhMXiqry3Iio+Ai4phVRDwl6WU10+r5A==",
229
+
"license": "MIT",
230
+
"dependencies": {
231
+
"@babel/helper-annotate-as-pure": "^7.27.1",
232
+
"@babel/helper-member-expression-to-functions": "^7.27.1",
233
+
"@babel/helper-optimise-call-expression": "^7.27.1",
234
+
"@babel/helper-replace-supers": "^7.27.1",
235
+
"@babel/helper-skip-transparent-expression-wrappers": "^7.27.1",
236
+
"@babel/traverse": "^7.27.1",
237
+
"semver": "^6.3.1"
238
+
},
239
+
"engines": {
240
+
"node": ">=6.9.0"
241
+
},
242
+
"peerDependencies": {
243
+
"@babel/core": "^7.0.0"
244
+
}
245
+
},
246
+
"node_modules/@babel/helper-globals": {
247
+
"version": "7.28.0",
248
+
"resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
249
+
"integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
250
+
"license": "MIT",
251
+
"engines": {
252
+
"node": ">=6.9.0"
253
+
}
254
+
},
255
+
"node_modules/@babel/helper-member-expression-to-functions": {
256
+
"version": "7.27.1",
257
+
"resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz",
258
+
"integrity": "sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==",
259
+
"license": "MIT",
260
+
"dependencies": {
261
+
"@babel/traverse": "^7.27.1",
262
+
"@babel/types": "^7.27.1"
263
+
},
264
+
"engines": {
265
+
"node": ">=6.9.0"
266
+
}
267
+
},
268
+
"node_modules/@babel/helper-module-imports": {
269
+
"version": "7.27.1",
270
+
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz",
271
+
"integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==",
272
+
"license": "MIT",
273
+
"dependencies": {
274
+
"@babel/traverse": "^7.27.1",
275
+
"@babel/types": "^7.27.1"
276
+
},
277
+
"engines": {
278
+
"node": ">=6.9.0"
279
+
}
280
+
},
281
+
"node_modules/@babel/helper-module-transforms": {
282
+
"version": "7.27.3",
283
+
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz",
284
+
"integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==",
285
+
"license": "MIT",
286
+
"dependencies": {
287
+
"@babel/helper-module-imports": "^7.27.1",
288
+
"@babel/helper-validator-identifier": "^7.27.1",
289
+
"@babel/traverse": "^7.27.3"
290
+
},
291
+
"engines": {
292
+
"node": ">=6.9.0"
293
+
},
294
+
"peerDependencies": {
295
+
"@babel/core": "^7.0.0"
296
+
}
297
+
},
298
+
"node_modules/@babel/helper-optimise-call-expression": {
299
+
"version": "7.27.1",
300
+
"resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz",
301
+
"integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==",
302
+
"license": "MIT",
303
+
"dependencies": {
304
+
"@babel/types": "^7.27.1"
305
+
},
306
+
"engines": {
307
+
"node": ">=6.9.0"
308
+
}
309
+
},
310
+
"node_modules/@babel/helper-plugin-utils": {
311
+
"version": "7.27.1",
312
+
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz",
313
+
"integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==",
314
+
"license": "MIT",
315
+
"engines": {
316
+
"node": ">=6.9.0"
317
+
}
318
+
},
319
+
"node_modules/@babel/helper-replace-supers": {
320
+
"version": "7.27.1",
321
+
"resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz",
322
+
"integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==",
323
+
"license": "MIT",
324
+
"dependencies": {
325
+
"@babel/helper-member-expression-to-functions": "^7.27.1",
326
+
"@babel/helper-optimise-call-expression": "^7.27.1",
327
+
"@babel/traverse": "^7.27.1"
328
+
},
329
+
"engines": {
330
+
"node": ">=6.9.0"
331
+
},
332
+
"peerDependencies": {
333
+
"@babel/core": "^7.0.0"
334
+
}
335
+
},
336
+
"node_modules/@babel/helper-skip-transparent-expression-wrappers": {
337
+
"version": "7.27.1",
338
+
"resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz",
339
+
"integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==",
340
+
"license": "MIT",
341
+
"dependencies": {
342
+
"@babel/traverse": "^7.27.1",
343
+
"@babel/types": "^7.27.1"
344
+
},
345
+
"engines": {
346
+
"node": ">=6.9.0"
347
+
}
348
+
},
349
+
"node_modules/@babel/helper-string-parser": {
350
+
"version": "7.27.1",
351
+
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
352
+
"integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
353
+
"license": "MIT",
354
+
"engines": {
355
+
"node": ">=6.9.0"
356
+
}
357
+
},
358
+
"node_modules/@babel/helper-validator-identifier": {
359
+
"version": "7.27.1",
360
+
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz",
361
+
"integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==",
362
+
"license": "MIT",
363
+
"engines": {
364
+
"node": ">=6.9.0"
365
+
}
366
+
},
367
+
"node_modules/@babel/helper-validator-option": {
368
+
"version": "7.27.1",
369
+
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz",
370
+
"integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==",
371
+
"license": "MIT",
372
+
"engines": {
373
+
"node": ">=6.9.0"
374
+
}
375
+
},
376
+
"node_modules/@babel/helpers": {
377
+
"version": "7.28.2",
378
+
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.2.tgz",
379
+
"integrity": "sha512-/V9771t+EgXz62aCcyofnQhGM8DQACbRhvzKFsXKC9QM+5MadF8ZmIm0crDMaz3+o0h0zXfJnd4EhbYbxsrcFw==",
380
+
"license": "MIT",
381
+
"dependencies": {
382
+
"@babel/template": "^7.27.2",
383
+
"@babel/types": "^7.28.2"
384
+
},
385
+
"engines": {
386
+
"node": ">=6.9.0"
387
+
}
388
+
},
389
+
"node_modules/@babel/parser": {
390
+
"version": "7.28.0",
391
+
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz",
392
+
"integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==",
393
+
"license": "MIT",
394
+
"dependencies": {
395
+
"@babel/types": "^7.28.0"
396
+
},
397
+
"bin": {
398
+
"parser": "bin/babel-parser.js"
399
+
},
400
+
"engines": {
401
+
"node": ">=6.0.0"
402
+
}
403
+
},
404
+
"node_modules/@babel/plugin-syntax-jsx": {
405
+
"version": "7.27.1",
406
+
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz",
407
+
"integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==",
408
+
"license": "MIT",
409
+
"dependencies": {
410
+
"@babel/helper-plugin-utils": "^7.27.1"
411
+
},
412
+
"engines": {
413
+
"node": ">=6.9.0"
414
+
},
415
+
"peerDependencies": {
416
+
"@babel/core": "^7.0.0-0"
417
+
}
418
+
},
419
+
"node_modules/@babel/plugin-syntax-typescript": {
420
+
"version": "7.27.1",
421
+
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz",
422
+
"integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==",
423
+
"license": "MIT",
424
+
"dependencies": {
425
+
"@babel/helper-plugin-utils": "^7.27.1"
426
+
},
427
+
"engines": {
428
+
"node": ">=6.9.0"
429
+
},
430
+
"peerDependencies": {
431
+
"@babel/core": "^7.0.0-0"
432
+
}
433
+
},
434
+
"node_modules/@babel/plugin-transform-modules-commonjs": {
435
+
"version": "7.27.1",
436
+
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz",
437
+
"integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==",
438
+
"license": "MIT",
439
+
"dependencies": {
440
+
"@babel/helper-module-transforms": "^7.27.1",
441
+
"@babel/helper-plugin-utils": "^7.27.1"
442
+
},
443
+
"engines": {
444
+
"node": ">=6.9.0"
445
+
},
446
+
"peerDependencies": {
447
+
"@babel/core": "^7.0.0-0"
448
+
}
449
+
},
450
+
"node_modules/@babel/plugin-transform-react-jsx-self": {
451
+
"version": "7.27.1",
452
+
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz",
453
+
"integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==",
454
+
"dev": true,
455
+
"license": "MIT",
456
+
"dependencies": {
457
+
"@babel/helper-plugin-utils": "^7.27.1"
458
+
},
459
+
"engines": {
460
+
"node": ">=6.9.0"
461
+
},
462
+
"peerDependencies": {
463
+
"@babel/core": "^7.0.0-0"
464
+
}
465
+
},
466
+
"node_modules/@babel/plugin-transform-react-jsx-source": {
467
+
"version": "7.27.1",
468
+
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz",
469
+
"integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==",
470
+
"dev": true,
471
+
"license": "MIT",
472
+
"dependencies": {
473
+
"@babel/helper-plugin-utils": "^7.27.1"
474
+
},
475
+
"engines": {
476
+
"node": ">=6.9.0"
477
+
},
478
+
"peerDependencies": {
479
+
"@babel/core": "^7.0.0-0"
480
+
}
481
+
},
482
+
"node_modules/@babel/plugin-transform-typescript": {
483
+
"version": "7.28.0",
484
+
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.0.tgz",
485
+
"integrity": "sha512-4AEiDEBPIZvLQaWlc9liCavE0xRM0dNca41WtBeM3jgFptfUOSG9z0uteLhq6+3rq+WB6jIvUwKDTpXEHPJ2Vg==",
486
+
"license": "MIT",
487
+
"dependencies": {
488
+
"@babel/helper-annotate-as-pure": "^7.27.3",
489
+
"@babel/helper-create-class-features-plugin": "^7.27.1",
490
+
"@babel/helper-plugin-utils": "^7.27.1",
491
+
"@babel/helper-skip-transparent-expression-wrappers": "^7.27.1",
492
+
"@babel/plugin-syntax-typescript": "^7.27.1"
493
+
},
494
+
"engines": {
495
+
"node": ">=6.9.0"
496
+
},
497
+
"peerDependencies": {
498
+
"@babel/core": "^7.0.0-0"
499
+
}
500
+
},
501
+
"node_modules/@babel/preset-typescript": {
502
+
"version": "7.27.1",
503
+
"resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.27.1.tgz",
504
+
"integrity": "sha512-l7WfQfX0WK4M0v2RudjuQK4u99BS6yLHYEmdtVPP7lKV013zr9DygFuWNlnbvQ9LR+LS0Egz/XAvGx5U9MX0fQ==",
505
+
"license": "MIT",
506
+
"dependencies": {
507
+
"@babel/helper-plugin-utils": "^7.27.1",
508
+
"@babel/helper-validator-option": "^7.27.1",
509
+
"@babel/plugin-syntax-jsx": "^7.27.1",
510
+
"@babel/plugin-transform-modules-commonjs": "^7.27.1",
511
+
"@babel/plugin-transform-typescript": "^7.27.1"
512
+
},
513
+
"engines": {
514
+
"node": ">=6.9.0"
515
+
},
516
+
"peerDependencies": {
517
+
"@babel/core": "^7.0.0-0"
518
+
}
519
+
},
520
+
"node_modules/@babel/runtime": {
521
+
"version": "7.28.2",
522
+
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.2.tgz",
523
+
"integrity": "sha512-KHp2IflsnGywDjBWDkR9iEqiWSpc8GIi0lgTT3mOElT0PP1tG26P4tmFI2YvAdzgq9RGyoHZQEIEdZy6Ec5xCA==",
524
+
"dev": true,
525
+
"license": "MIT",
526
+
"engines": {
527
+
"node": ">=6.9.0"
528
+
}
529
+
},
530
+
"node_modules/@babel/template": {
531
+
"version": "7.27.2",
532
+
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz",
533
+
"integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==",
534
+
"license": "MIT",
535
+
"dependencies": {
536
+
"@babel/code-frame": "^7.27.1",
537
+
"@babel/parser": "^7.27.2",
538
+
"@babel/types": "^7.27.1"
539
+
},
540
+
"engines": {
541
+
"node": ">=6.9.0"
542
+
}
543
+
},
544
+
"node_modules/@babel/traverse": {
545
+
"version": "7.28.0",
546
+
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.0.tgz",
547
+
"integrity": "sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==",
548
+
"license": "MIT",
549
+
"dependencies": {
550
+
"@babel/code-frame": "^7.27.1",
551
+
"@babel/generator": "^7.28.0",
552
+
"@babel/helper-globals": "^7.28.0",
553
+
"@babel/parser": "^7.28.0",
554
+
"@babel/template": "^7.27.2",
555
+
"@babel/types": "^7.28.0",
556
+
"debug": "^4.3.1"
557
+
},
558
+
"engines": {
559
+
"node": ">=6.9.0"
560
+
}
561
+
},
562
+
"node_modules/@babel/types": {
563
+
"version": "7.28.2",
564
+
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz",
565
+
"integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==",
566
+
"license": "MIT",
567
+
"dependencies": {
568
+
"@babel/helper-string-parser": "^7.27.1",
569
+
"@babel/helper-validator-identifier": "^7.27.1"
570
+
},
571
+
"engines": {
572
+
"node": ">=6.9.0"
573
+
}
574
+
},
575
+
"node_modules/@csstools/color-helpers": {
576
+
"version": "5.0.2",
577
+
"resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.0.2.tgz",
578
+
"integrity": "sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA==",
579
+
"dev": true,
580
+
"funding": [
581
+
{
582
+
"type": "github",
583
+
"url": "https://github.com/sponsors/csstools"
584
+
},
585
+
{
586
+
"type": "opencollective",
587
+
"url": "https://opencollective.com/csstools"
588
+
}
589
+
],
590
+
"license": "MIT-0",
591
+
"engines": {
592
+
"node": ">=18"
593
+
}
594
+
},
595
+
"node_modules/@csstools/css-calc": {
596
+
"version": "2.1.4",
597
+
"resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz",
598
+
"integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==",
599
+
"dev": true,
600
+
"funding": [
601
+
{
602
+
"type": "github",
603
+
"url": "https://github.com/sponsors/csstools"
604
+
},
605
+
{
606
+
"type": "opencollective",
607
+
"url": "https://opencollective.com/csstools"
608
+
}
609
+
],
610
+
"license": "MIT",
611
+
"engines": {
612
+
"node": ">=18"
613
+
},
614
+
"peerDependencies": {
615
+
"@csstools/css-parser-algorithms": "^3.0.5",
616
+
"@csstools/css-tokenizer": "^3.0.4"
617
+
}
618
+
},
619
+
"node_modules/@csstools/css-color-parser": {
620
+
"version": "3.0.10",
621
+
"resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.0.10.tgz",
622
+
"integrity": "sha512-TiJ5Ajr6WRd1r8HSiwJvZBiJOqtH86aHpUjq5aEKWHiII2Qfjqd/HCWKPOW8EP4vcspXbHnXrwIDlu5savQipg==",
623
+
"dev": true,
624
+
"funding": [
625
+
{
626
+
"type": "github",
627
+
"url": "https://github.com/sponsors/csstools"
628
+
},
629
+
{
630
+
"type": "opencollective",
631
+
"url": "https://opencollective.com/csstools"
632
+
}
633
+
],
634
+
"license": "MIT",
635
+
"dependencies": {
636
+
"@csstools/color-helpers": "^5.0.2",
637
+
"@csstools/css-calc": "^2.1.4"
638
+
},
639
+
"engines": {
640
+
"node": ">=18"
641
+
},
642
+
"peerDependencies": {
643
+
"@csstools/css-parser-algorithms": "^3.0.5",
644
+
"@csstools/css-tokenizer": "^3.0.4"
645
+
}
646
+
},
647
+
"node_modules/@csstools/css-parser-algorithms": {
648
+
"version": "3.0.5",
649
+
"resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz",
650
+
"integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==",
651
+
"dev": true,
652
+
"funding": [
653
+
{
654
+
"type": "github",
655
+
"url": "https://github.com/sponsors/csstools"
656
+
},
657
+
{
658
+
"type": "opencollective",
659
+
"url": "https://opencollective.com/csstools"
660
+
}
661
+
],
662
+
"license": "MIT",
663
+
"engines": {
664
+
"node": ">=18"
665
+
},
666
+
"peerDependencies": {
667
+
"@csstools/css-tokenizer": "^3.0.4"
668
+
}
669
+
},
670
+
"node_modules/@csstools/css-tokenizer": {
671
+
"version": "3.0.4",
672
+
"resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz",
673
+
"integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==",
674
+
"dev": true,
675
+
"funding": [
676
+
{
677
+
"type": "github",
678
+
"url": "https://github.com/sponsors/csstools"
679
+
},
680
+
{
681
+
"type": "opencollective",
682
+
"url": "https://opencollective.com/csstools"
683
+
}
684
+
],
685
+
"license": "MIT",
686
+
"engines": {
687
+
"node": ">=18"
688
+
}
689
+
},
690
+
"node_modules/@esbuild/aix-ppc64": {
691
+
"version": "0.25.8",
692
+
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.8.tgz",
693
+
"integrity": "sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA==",
694
+
"cpu": [
695
+
"ppc64"
696
+
],
697
+
"license": "MIT",
698
+
"optional": true,
699
+
"os": [
700
+
"aix"
701
+
],
702
+
"engines": {
703
+
"node": ">=18"
704
+
}
705
+
},
706
+
"node_modules/@esbuild/android-arm": {
707
+
"version": "0.25.8",
708
+
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.8.tgz",
709
+
"integrity": "sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw==",
710
+
"cpu": [
711
+
"arm"
712
+
],
713
+
"license": "MIT",
714
+
"optional": true,
715
+
"os": [
716
+
"android"
717
+
],
718
+
"engines": {
719
+
"node": ">=18"
720
+
}
721
+
},
722
+
"node_modules/@esbuild/android-arm64": {
723
+
"version": "0.25.8",
724
+
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.8.tgz",
725
+
"integrity": "sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w==",
726
+
"cpu": [
727
+
"arm64"
728
+
],
729
+
"license": "MIT",
730
+
"optional": true,
731
+
"os": [
732
+
"android"
733
+
],
734
+
"engines": {
735
+
"node": ">=18"
736
+
}
737
+
},
738
+
"node_modules/@esbuild/android-x64": {
739
+
"version": "0.25.8",
740
+
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.8.tgz",
741
+
"integrity": "sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA==",
742
+
"cpu": [
743
+
"x64"
744
+
],
745
+
"license": "MIT",
746
+
"optional": true,
747
+
"os": [
748
+
"android"
749
+
],
750
+
"engines": {
751
+
"node": ">=18"
752
+
}
753
+
},
754
+
"node_modules/@esbuild/darwin-arm64": {
755
+
"version": "0.25.8",
756
+
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.8.tgz",
757
+
"integrity": "sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw==",
758
+
"cpu": [
759
+
"arm64"
760
+
],
761
+
"license": "MIT",
762
+
"optional": true,
763
+
"os": [
764
+
"darwin"
765
+
],
766
+
"engines": {
767
+
"node": ">=18"
768
+
}
769
+
},
770
+
"node_modules/@esbuild/darwin-x64": {
771
+
"version": "0.25.8",
772
+
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.8.tgz",
773
+
"integrity": "sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg==",
774
+
"cpu": [
775
+
"x64"
776
+
],
777
+
"license": "MIT",
778
+
"optional": true,
779
+
"os": [
780
+
"darwin"
781
+
],
782
+
"engines": {
783
+
"node": ">=18"
784
+
}
785
+
},
786
+
"node_modules/@esbuild/freebsd-arm64": {
787
+
"version": "0.25.8",
788
+
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.8.tgz",
789
+
"integrity": "sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA==",
790
+
"cpu": [
791
+
"arm64"
792
+
],
793
+
"license": "MIT",
794
+
"optional": true,
795
+
"os": [
796
+
"freebsd"
797
+
],
798
+
"engines": {
799
+
"node": ">=18"
800
+
}
801
+
},
802
+
"node_modules/@esbuild/freebsd-x64": {
803
+
"version": "0.25.8",
804
+
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.8.tgz",
805
+
"integrity": "sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw==",
806
+
"cpu": [
807
+
"x64"
808
+
],
809
+
"license": "MIT",
810
+
"optional": true,
811
+
"os": [
812
+
"freebsd"
813
+
],
814
+
"engines": {
815
+
"node": ">=18"
816
+
}
817
+
},
818
+
"node_modules/@esbuild/linux-arm": {
819
+
"version": "0.25.8",
820
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.8.tgz",
821
+
"integrity": "sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg==",
822
+
"cpu": [
823
+
"arm"
824
+
],
825
+
"license": "MIT",
826
+
"optional": true,
827
+
"os": [
828
+
"linux"
829
+
],
830
+
"engines": {
831
+
"node": ">=18"
832
+
}
833
+
},
834
+
"node_modules/@esbuild/linux-arm64": {
835
+
"version": "0.25.8",
836
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.8.tgz",
837
+
"integrity": "sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w==",
838
+
"cpu": [
839
+
"arm64"
840
+
],
841
+
"license": "MIT",
842
+
"optional": true,
843
+
"os": [
844
+
"linux"
845
+
],
846
+
"engines": {
847
+
"node": ">=18"
848
+
}
849
+
},
850
+
"node_modules/@esbuild/linux-ia32": {
851
+
"version": "0.25.8",
852
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.8.tgz",
853
+
"integrity": "sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg==",
854
+
"cpu": [
855
+
"ia32"
856
+
],
857
+
"license": "MIT",
858
+
"optional": true,
859
+
"os": [
860
+
"linux"
861
+
],
862
+
"engines": {
863
+
"node": ">=18"
864
+
}
865
+
},
866
+
"node_modules/@esbuild/linux-loong64": {
867
+
"version": "0.25.8",
868
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.8.tgz",
869
+
"integrity": "sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ==",
870
+
"cpu": [
871
+
"loong64"
872
+
],
873
+
"license": "MIT",
874
+
"optional": true,
875
+
"os": [
876
+
"linux"
877
+
],
878
+
"engines": {
879
+
"node": ">=18"
880
+
}
881
+
},
882
+
"node_modules/@esbuild/linux-mips64el": {
883
+
"version": "0.25.8",
884
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.8.tgz",
885
+
"integrity": "sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw==",
886
+
"cpu": [
887
+
"mips64el"
888
+
],
889
+
"license": "MIT",
890
+
"optional": true,
891
+
"os": [
892
+
"linux"
893
+
],
894
+
"engines": {
895
+
"node": ">=18"
896
+
}
897
+
},
898
+
"node_modules/@esbuild/linux-ppc64": {
899
+
"version": "0.25.8",
900
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.8.tgz",
901
+
"integrity": "sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ==",
902
+
"cpu": [
903
+
"ppc64"
904
+
],
905
+
"license": "MIT",
906
+
"optional": true,
907
+
"os": [
908
+
"linux"
909
+
],
910
+
"engines": {
911
+
"node": ">=18"
912
+
}
913
+
},
914
+
"node_modules/@esbuild/linux-riscv64": {
915
+
"version": "0.25.8",
916
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.8.tgz",
917
+
"integrity": "sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg==",
918
+
"cpu": [
919
+
"riscv64"
920
+
],
921
+
"license": "MIT",
922
+
"optional": true,
923
+
"os": [
924
+
"linux"
925
+
],
926
+
"engines": {
927
+
"node": ">=18"
928
+
}
929
+
},
930
+
"node_modules/@esbuild/linux-s390x": {
931
+
"version": "0.25.8",
932
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.8.tgz",
933
+
"integrity": "sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg==",
934
+
"cpu": [
935
+
"s390x"
936
+
],
937
+
"license": "MIT",
938
+
"optional": true,
939
+
"os": [
940
+
"linux"
941
+
],
942
+
"engines": {
943
+
"node": ">=18"
944
+
}
945
+
},
946
+
"node_modules/@esbuild/linux-x64": {
947
+
"version": "0.25.8",
948
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.8.tgz",
949
+
"integrity": "sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ==",
950
+
"cpu": [
951
+
"x64"
952
+
],
953
+
"license": "MIT",
954
+
"optional": true,
955
+
"os": [
956
+
"linux"
957
+
],
958
+
"engines": {
959
+
"node": ">=18"
960
+
}
961
+
},
962
+
"node_modules/@esbuild/netbsd-arm64": {
963
+
"version": "0.25.8",
964
+
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.8.tgz",
965
+
"integrity": "sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw==",
966
+
"cpu": [
967
+
"arm64"
968
+
],
969
+
"license": "MIT",
970
+
"optional": true,
971
+
"os": [
972
+
"netbsd"
973
+
],
974
+
"engines": {
975
+
"node": ">=18"
976
+
}
977
+
},
978
+
"node_modules/@esbuild/netbsd-x64": {
979
+
"version": "0.25.8",
980
+
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.8.tgz",
981
+
"integrity": "sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg==",
982
+
"cpu": [
983
+
"x64"
984
+
],
985
+
"license": "MIT",
986
+
"optional": true,
987
+
"os": [
988
+
"netbsd"
989
+
],
990
+
"engines": {
991
+
"node": ">=18"
992
+
}
993
+
},
994
+
"node_modules/@esbuild/openbsd-arm64": {
995
+
"version": "0.25.8",
996
+
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.8.tgz",
997
+
"integrity": "sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ==",
998
+
"cpu": [
999
+
"arm64"
1000
+
],
1001
+
"license": "MIT",
1002
+
"optional": true,
1003
+
"os": [
1004
+
"openbsd"
1005
+
],
1006
+
"engines": {
1007
+
"node": ">=18"
1008
+
}
1009
+
},
1010
+
"node_modules/@esbuild/openbsd-x64": {
1011
+
"version": "0.25.8",
1012
+
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.8.tgz",
1013
+
"integrity": "sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ==",
1014
+
"cpu": [
1015
+
"x64"
1016
+
],
1017
+
"license": "MIT",
1018
+
"optional": true,
1019
+
"os": [
1020
+
"openbsd"
1021
+
],
1022
+
"engines": {
1023
+
"node": ">=18"
1024
+
}
1025
+
},
1026
+
"node_modules/@esbuild/openharmony-arm64": {
1027
+
"version": "0.25.8",
1028
+
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.8.tgz",
1029
+
"integrity": "sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg==",
1030
+
"cpu": [
1031
+
"arm64"
1032
+
],
1033
+
"license": "MIT",
1034
+
"optional": true,
1035
+
"os": [
1036
+
"openharmony"
1037
+
],
1038
+
"engines": {
1039
+
"node": ">=18"
1040
+
}
1041
+
},
1042
+
"node_modules/@esbuild/sunos-x64": {
1043
+
"version": "0.25.8",
1044
+
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.8.tgz",
1045
+
"integrity": "sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w==",
1046
+
"cpu": [
1047
+
"x64"
1048
+
],
1049
+
"license": "MIT",
1050
+
"optional": true,
1051
+
"os": [
1052
+
"sunos"
1053
+
],
1054
+
"engines": {
1055
+
"node": ">=18"
1056
+
}
1057
+
},
1058
+
"node_modules/@esbuild/win32-arm64": {
1059
+
"version": "0.25.8",
1060
+
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.8.tgz",
1061
+
"integrity": "sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ==",
1062
+
"cpu": [
1063
+
"arm64"
1064
+
],
1065
+
"license": "MIT",
1066
+
"optional": true,
1067
+
"os": [
1068
+
"win32"
1069
+
],
1070
+
"engines": {
1071
+
"node": ">=18"
1072
+
}
1073
+
},
1074
+
"node_modules/@esbuild/win32-ia32": {
1075
+
"version": "0.25.8",
1076
+
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.8.tgz",
1077
+
"integrity": "sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg==",
1078
+
"cpu": [
1079
+
"ia32"
1080
+
],
1081
+
"license": "MIT",
1082
+
"optional": true,
1083
+
"os": [
1084
+
"win32"
1085
+
],
1086
+
"engines": {
1087
+
"node": ">=18"
1088
+
}
1089
+
},
1090
+
"node_modules/@esbuild/win32-x64": {
1091
+
"version": "0.25.8",
1092
+
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.8.tgz",
1093
+
"integrity": "sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw==",
1094
+
"cpu": [
1095
+
"x64"
1096
+
],
1097
+
"license": "MIT",
1098
+
"optional": true,
1099
+
"os": [
1100
+
"win32"
1101
+
],
1102
+
"engines": {
1103
+
"node": ">=18"
1104
+
}
1105
+
},
1106
+
"node_modules/@floating-ui/core": {
1107
+
"version": "1.7.3",
1108
+
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz",
1109
+
"integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==",
1110
+
"license": "MIT",
1111
+
"dependencies": {
1112
+
"@floating-ui/utils": "^0.2.10"
1113
+
}
1114
+
},
1115
+
"node_modules/@floating-ui/dom": {
1116
+
"version": "1.7.3",
1117
+
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.3.tgz",
1118
+
"integrity": "sha512-uZA413QEpNuhtb3/iIKoYMSK07keHPYeXF02Zhd6e213j+d1NamLix/mCLxBUDW/Gx52sPH2m+chlUsyaBs/Ag==",
1119
+
"license": "MIT",
1120
+
"dependencies": {
1121
+
"@floating-ui/core": "^1.7.3",
1122
+
"@floating-ui/utils": "^0.2.10"
1123
+
}
1124
+
},
1125
+
"node_modules/@floating-ui/react-dom": {
1126
+
"version": "2.1.5",
1127
+
"resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.5.tgz",
1128
+
"integrity": "sha512-HDO/1/1oH9fjj4eLgegrlH3dklZpHtUYYFiVwMUwfGvk9jWDRWqkklA2/NFScknrcNSspbV868WjXORvreDX+Q==",
1129
+
"license": "MIT",
1130
+
"dependencies": {
1131
+
"@floating-ui/dom": "^1.7.3"
1132
+
},
1133
+
"peerDependencies": {
1134
+
"react": ">=16.8.0",
1135
+
"react-dom": ">=16.8.0"
1136
+
}
1137
+
},
1138
+
"node_modules/@floating-ui/utils": {
1139
+
"version": "0.2.10",
1140
+
"resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz",
1141
+
"integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==",
1142
+
"license": "MIT"
1143
+
},
1144
+
"node_modules/@isaacs/fs-minipass": {
1145
+
"version": "4.0.1",
1146
+
"resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
1147
+
"integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==",
1148
+
"license": "ISC",
1149
+
"dependencies": {
1150
+
"minipass": "^7.0.4"
1151
+
},
1152
+
"engines": {
1153
+
"node": ">=18.0.0"
1154
+
}
1155
+
},
1156
+
"node_modules/@jridgewell/gen-mapping": {
1157
+
"version": "0.3.12",
1158
+
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz",
1159
+
"integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==",
1160
+
"license": "MIT",
1161
+
"dependencies": {
1162
+
"@jridgewell/sourcemap-codec": "^1.5.0",
1163
+
"@jridgewell/trace-mapping": "^0.3.24"
1164
+
}
1165
+
},
1166
+
"node_modules/@jridgewell/resolve-uri": {
1167
+
"version": "3.1.2",
1168
+
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
1169
+
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
1170
+
"license": "MIT",
1171
+
"engines": {
1172
+
"node": ">=6.0.0"
1173
+
}
1174
+
},
1175
+
"node_modules/@jridgewell/sourcemap-codec": {
1176
+
"version": "1.5.4",
1177
+
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz",
1178
+
"integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==",
1179
+
"license": "MIT"
1180
+
},
1181
+
"node_modules/@jridgewell/trace-mapping": {
1182
+
"version": "0.3.29",
1183
+
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz",
1184
+
"integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==",
1185
+
"license": "MIT",
1186
+
"dependencies": {
1187
+
"@jridgewell/resolve-uri": "^3.1.0",
1188
+
"@jridgewell/sourcemap-codec": "^1.4.14"
1189
+
}
1190
+
},
1191
+
"node_modules/@radix-ui/number": {
1192
+
"version": "1.1.1",
1193
+
"resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz",
1194
+
"integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==",
1195
+
"license": "MIT"
1196
+
},
1197
+
"node_modules/@radix-ui/primitive": {
1198
+
"version": "1.1.2",
1199
+
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.2.tgz",
1200
+
"integrity": "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==",
1201
+
"license": "MIT"
1202
+
},
1203
+
"node_modules/@radix-ui/react-arrow": {
1204
+
"version": "1.1.7",
1205
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz",
1206
+
"integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==",
1207
+
"license": "MIT",
1208
+
"dependencies": {
1209
+
"@radix-ui/react-primitive": "2.1.3"
1210
+
},
1211
+
"peerDependencies": {
1212
+
"@types/react": "*",
1213
+
"@types/react-dom": "*",
1214
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
1215
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1216
+
},
1217
+
"peerDependenciesMeta": {
1218
+
"@types/react": {
1219
+
"optional": true
1220
+
},
1221
+
"@types/react-dom": {
1222
+
"optional": true
1223
+
}
1224
+
}
1225
+
},
1226
+
"node_modules/@radix-ui/react-collection": {
1227
+
"version": "1.1.7",
1228
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz",
1229
+
"integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==",
1230
+
"license": "MIT",
1231
+
"dependencies": {
1232
+
"@radix-ui/react-compose-refs": "1.1.2",
1233
+
"@radix-ui/react-context": "1.1.2",
1234
+
"@radix-ui/react-primitive": "2.1.3",
1235
+
"@radix-ui/react-slot": "1.2.3"
1236
+
},
1237
+
"peerDependencies": {
1238
+
"@types/react": "*",
1239
+
"@types/react-dom": "*",
1240
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
1241
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1242
+
},
1243
+
"peerDependenciesMeta": {
1244
+
"@types/react": {
1245
+
"optional": true
1246
+
},
1247
+
"@types/react-dom": {
1248
+
"optional": true
1249
+
}
1250
+
}
1251
+
},
1252
+
"node_modules/@radix-ui/react-compose-refs": {
1253
+
"version": "1.1.2",
1254
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
1255
+
"integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==",
1256
+
"license": "MIT",
1257
+
"peerDependencies": {
1258
+
"@types/react": "*",
1259
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1260
+
},
1261
+
"peerDependenciesMeta": {
1262
+
"@types/react": {
1263
+
"optional": true
1264
+
}
1265
+
}
1266
+
},
1267
+
"node_modules/@radix-ui/react-context": {
1268
+
"version": "1.1.2",
1269
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz",
1270
+
"integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==",
1271
+
"license": "MIT",
1272
+
"peerDependencies": {
1273
+
"@types/react": "*",
1274
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1275
+
},
1276
+
"peerDependenciesMeta": {
1277
+
"@types/react": {
1278
+
"optional": true
1279
+
}
1280
+
}
1281
+
},
1282
+
"node_modules/@radix-ui/react-dialog": {
1283
+
"version": "1.1.14",
1284
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.14.tgz",
1285
+
"integrity": "sha512-+CpweKjqpzTmwRwcYECQcNYbI8V9VSQt0SNFKeEBLgfucbsLssU6Ppq7wUdNXEGb573bMjFhVjKVll8rmV6zMw==",
1286
+
"license": "MIT",
1287
+
"dependencies": {
1288
+
"@radix-ui/primitive": "1.1.2",
1289
+
"@radix-ui/react-compose-refs": "1.1.2",
1290
+
"@radix-ui/react-context": "1.1.2",
1291
+
"@radix-ui/react-dismissable-layer": "1.1.10",
1292
+
"@radix-ui/react-focus-guards": "1.1.2",
1293
+
"@radix-ui/react-focus-scope": "1.1.7",
1294
+
"@radix-ui/react-id": "1.1.1",
1295
+
"@radix-ui/react-portal": "1.1.9",
1296
+
"@radix-ui/react-presence": "1.1.4",
1297
+
"@radix-ui/react-primitive": "2.1.3",
1298
+
"@radix-ui/react-slot": "1.2.3",
1299
+
"@radix-ui/react-use-controllable-state": "1.2.2",
1300
+
"aria-hidden": "^1.2.4",
1301
+
"react-remove-scroll": "^2.6.3"
1302
+
},
1303
+
"peerDependencies": {
1304
+
"@types/react": "*",
1305
+
"@types/react-dom": "*",
1306
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
1307
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1308
+
},
1309
+
"peerDependenciesMeta": {
1310
+
"@types/react": {
1311
+
"optional": true
1312
+
},
1313
+
"@types/react-dom": {
1314
+
"optional": true
1315
+
}
1316
+
}
1317
+
},
1318
+
"node_modules/@radix-ui/react-direction": {
1319
+
"version": "1.1.1",
1320
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz",
1321
+
"integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==",
1322
+
"license": "MIT",
1323
+
"peerDependencies": {
1324
+
"@types/react": "*",
1325
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1326
+
},
1327
+
"peerDependenciesMeta": {
1328
+
"@types/react": {
1329
+
"optional": true
1330
+
}
1331
+
}
1332
+
},
1333
+
"node_modules/@radix-ui/react-dismissable-layer": {
1334
+
"version": "1.1.10",
1335
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.10.tgz",
1336
+
"integrity": "sha512-IM1zzRV4W3HtVgftdQiiOmA0AdJlCtMLe00FXaHwgt3rAnNsIyDqshvkIW3hj/iu5hu8ERP7KIYki6NkqDxAwQ==",
1337
+
"license": "MIT",
1338
+
"dependencies": {
1339
+
"@radix-ui/primitive": "1.1.2",
1340
+
"@radix-ui/react-compose-refs": "1.1.2",
1341
+
"@radix-ui/react-primitive": "2.1.3",
1342
+
"@radix-ui/react-use-callback-ref": "1.1.1",
1343
+
"@radix-ui/react-use-escape-keydown": "1.1.1"
1344
+
},
1345
+
"peerDependencies": {
1346
+
"@types/react": "*",
1347
+
"@types/react-dom": "*",
1348
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
1349
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1350
+
},
1351
+
"peerDependenciesMeta": {
1352
+
"@types/react": {
1353
+
"optional": true
1354
+
},
1355
+
"@types/react-dom": {
1356
+
"optional": true
1357
+
}
1358
+
}
1359
+
},
1360
+
"node_modules/@radix-ui/react-focus-guards": {
1361
+
"version": "1.1.2",
1362
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.2.tgz",
1363
+
"integrity": "sha512-fyjAACV62oPV925xFCrH8DR5xWhg9KYtJT4s3u54jxp+L/hbpTY2kIeEFFbFe+a/HCE94zGQMZLIpVTPVZDhaA==",
1364
+
"license": "MIT",
1365
+
"peerDependencies": {
1366
+
"@types/react": "*",
1367
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1368
+
},
1369
+
"peerDependenciesMeta": {
1370
+
"@types/react": {
1371
+
"optional": true
1372
+
}
1373
+
}
1374
+
},
1375
+
"node_modules/@radix-ui/react-focus-scope": {
1376
+
"version": "1.1.7",
1377
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz",
1378
+
"integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==",
1379
+
"license": "MIT",
1380
+
"dependencies": {
1381
+
"@radix-ui/react-compose-refs": "1.1.2",
1382
+
"@radix-ui/react-primitive": "2.1.3",
1383
+
"@radix-ui/react-use-callback-ref": "1.1.1"
1384
+
},
1385
+
"peerDependencies": {
1386
+
"@types/react": "*",
1387
+
"@types/react-dom": "*",
1388
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
1389
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1390
+
},
1391
+
"peerDependenciesMeta": {
1392
+
"@types/react": {
1393
+
"optional": true
1394
+
},
1395
+
"@types/react-dom": {
1396
+
"optional": true
1397
+
}
1398
+
}
1399
+
},
1400
+
"node_modules/@radix-ui/react-icons": {
1401
+
"version": "1.3.2",
1402
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-icons/-/react-icons-1.3.2.tgz",
1403
+
"integrity": "sha512-fyQIhGDhzfc9pK2kH6Pl9c4BDJGfMkPqkyIgYDthyNYoNg3wVhoJMMh19WS4Up/1KMPFVpNsT2q3WmXn2N1m6g==",
1404
+
"license": "MIT",
1405
+
"peerDependencies": {
1406
+
"react": "^16.x || ^17.x || ^18.x || ^19.0.0 || ^19.0.0-rc"
1407
+
}
1408
+
},
1409
+
"node_modules/@radix-ui/react-id": {
1410
+
"version": "1.1.1",
1411
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz",
1412
+
"integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==",
1413
+
"license": "MIT",
1414
+
"dependencies": {
1415
+
"@radix-ui/react-use-layout-effect": "1.1.1"
1416
+
},
1417
+
"peerDependencies": {
1418
+
"@types/react": "*",
1419
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1420
+
},
1421
+
"peerDependenciesMeta": {
1422
+
"@types/react": {
1423
+
"optional": true
1424
+
}
1425
+
}
1426
+
},
1427
+
"node_modules/@radix-ui/react-popover": {
1428
+
"version": "1.1.14",
1429
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.14.tgz",
1430
+
"integrity": "sha512-ODz16+1iIbGUfFEfKx2HTPKizg2MN39uIOV8MXeHnmdd3i/N9Wt7vU46wbHsqA0xoaQyXVcs0KIlBdOA2Y95bw==",
1431
+
"license": "MIT",
1432
+
"dependencies": {
1433
+
"@radix-ui/primitive": "1.1.2",
1434
+
"@radix-ui/react-compose-refs": "1.1.2",
1435
+
"@radix-ui/react-context": "1.1.2",
1436
+
"@radix-ui/react-dismissable-layer": "1.1.10",
1437
+
"@radix-ui/react-focus-guards": "1.1.2",
1438
+
"@radix-ui/react-focus-scope": "1.1.7",
1439
+
"@radix-ui/react-id": "1.1.1",
1440
+
"@radix-ui/react-popper": "1.2.7",
1441
+
"@radix-ui/react-portal": "1.1.9",
1442
+
"@radix-ui/react-presence": "1.1.4",
1443
+
"@radix-ui/react-primitive": "2.1.3",
1444
+
"@radix-ui/react-slot": "1.2.3",
1445
+
"@radix-ui/react-use-controllable-state": "1.2.2",
1446
+
"aria-hidden": "^1.2.4",
1447
+
"react-remove-scroll": "^2.6.3"
1448
+
},
1449
+
"peerDependencies": {
1450
+
"@types/react": "*",
1451
+
"@types/react-dom": "*",
1452
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
1453
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1454
+
},
1455
+
"peerDependenciesMeta": {
1456
+
"@types/react": {
1457
+
"optional": true
1458
+
},
1459
+
"@types/react-dom": {
1460
+
"optional": true
1461
+
}
1462
+
}
1463
+
},
1464
+
"node_modules/@radix-ui/react-popper": {
1465
+
"version": "1.2.7",
1466
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.7.tgz",
1467
+
"integrity": "sha512-IUFAccz1JyKcf/RjB552PlWwxjeCJB8/4KxT7EhBHOJM+mN7LdW+B3kacJXILm32xawcMMjb2i0cIZpo+f9kiQ==",
1468
+
"license": "MIT",
1469
+
"dependencies": {
1470
+
"@floating-ui/react-dom": "^2.0.0",
1471
+
"@radix-ui/react-arrow": "1.1.7",
1472
+
"@radix-ui/react-compose-refs": "1.1.2",
1473
+
"@radix-ui/react-context": "1.1.2",
1474
+
"@radix-ui/react-primitive": "2.1.3",
1475
+
"@radix-ui/react-use-callback-ref": "1.1.1",
1476
+
"@radix-ui/react-use-layout-effect": "1.1.1",
1477
+
"@radix-ui/react-use-rect": "1.1.1",
1478
+
"@radix-ui/react-use-size": "1.1.1",
1479
+
"@radix-ui/rect": "1.1.1"
1480
+
},
1481
+
"peerDependencies": {
1482
+
"@types/react": "*",
1483
+
"@types/react-dom": "*",
1484
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
1485
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1486
+
},
1487
+
"peerDependenciesMeta": {
1488
+
"@types/react": {
1489
+
"optional": true
1490
+
},
1491
+
"@types/react-dom": {
1492
+
"optional": true
1493
+
}
1494
+
}
1495
+
},
1496
+
"node_modules/@radix-ui/react-portal": {
1497
+
"version": "1.1.9",
1498
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz",
1499
+
"integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==",
1500
+
"license": "MIT",
1501
+
"dependencies": {
1502
+
"@radix-ui/react-primitive": "2.1.3",
1503
+
"@radix-ui/react-use-layout-effect": "1.1.1"
1504
+
},
1505
+
"peerDependencies": {
1506
+
"@types/react": "*",
1507
+
"@types/react-dom": "*",
1508
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
1509
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1510
+
},
1511
+
"peerDependenciesMeta": {
1512
+
"@types/react": {
1513
+
"optional": true
1514
+
},
1515
+
"@types/react-dom": {
1516
+
"optional": true
1517
+
}
1518
+
}
1519
+
},
1520
+
"node_modules/@radix-ui/react-presence": {
1521
+
"version": "1.1.4",
1522
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.4.tgz",
1523
+
"integrity": "sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA==",
1524
+
"license": "MIT",
1525
+
"dependencies": {
1526
+
"@radix-ui/react-compose-refs": "1.1.2",
1527
+
"@radix-ui/react-use-layout-effect": "1.1.1"
1528
+
},
1529
+
"peerDependencies": {
1530
+
"@types/react": "*",
1531
+
"@types/react-dom": "*",
1532
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
1533
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1534
+
},
1535
+
"peerDependenciesMeta": {
1536
+
"@types/react": {
1537
+
"optional": true
1538
+
},
1539
+
"@types/react-dom": {
1540
+
"optional": true
1541
+
}
1542
+
}
1543
+
},
1544
+
"node_modules/@radix-ui/react-primitive": {
1545
+
"version": "2.1.3",
1546
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz",
1547
+
"integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==",
1548
+
"license": "MIT",
1549
+
"dependencies": {
1550
+
"@radix-ui/react-slot": "1.2.3"
1551
+
},
1552
+
"peerDependencies": {
1553
+
"@types/react": "*",
1554
+
"@types/react-dom": "*",
1555
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
1556
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1557
+
},
1558
+
"peerDependenciesMeta": {
1559
+
"@types/react": {
1560
+
"optional": true
1561
+
},
1562
+
"@types/react-dom": {
1563
+
"optional": true
1564
+
}
1565
+
}
1566
+
},
1567
+
"node_modules/@radix-ui/react-select": {
1568
+
"version": "2.2.5",
1569
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.5.tgz",
1570
+
"integrity": "sha512-HnMTdXEVuuyzx63ME0ut4+sEMYW6oouHWNGUZc7ddvUWIcfCva/AMoqEW/3wnEllriMWBa0RHspCYnfCWJQYmA==",
1571
+
"license": "MIT",
1572
+
"dependencies": {
1573
+
"@radix-ui/number": "1.1.1",
1574
+
"@radix-ui/primitive": "1.1.2",
1575
+
"@radix-ui/react-collection": "1.1.7",
1576
+
"@radix-ui/react-compose-refs": "1.1.2",
1577
+
"@radix-ui/react-context": "1.1.2",
1578
+
"@radix-ui/react-direction": "1.1.1",
1579
+
"@radix-ui/react-dismissable-layer": "1.1.10",
1580
+
"@radix-ui/react-focus-guards": "1.1.2",
1581
+
"@radix-ui/react-focus-scope": "1.1.7",
1582
+
"@radix-ui/react-id": "1.1.1",
1583
+
"@radix-ui/react-popper": "1.2.7",
1584
+
"@radix-ui/react-portal": "1.1.9",
1585
+
"@radix-ui/react-primitive": "2.1.3",
1586
+
"@radix-ui/react-slot": "1.2.3",
1587
+
"@radix-ui/react-use-callback-ref": "1.1.1",
1588
+
"@radix-ui/react-use-controllable-state": "1.2.2",
1589
+
"@radix-ui/react-use-layout-effect": "1.1.1",
1590
+
"@radix-ui/react-use-previous": "1.1.1",
1591
+
"@radix-ui/react-visually-hidden": "1.2.3",
1592
+
"aria-hidden": "^1.2.4",
1593
+
"react-remove-scroll": "^2.6.3"
1594
+
},
1595
+
"peerDependencies": {
1596
+
"@types/react": "*",
1597
+
"@types/react-dom": "*",
1598
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
1599
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1600
+
},
1601
+
"peerDependenciesMeta": {
1602
+
"@types/react": {
1603
+
"optional": true
1604
+
},
1605
+
"@types/react-dom": {
1606
+
"optional": true
1607
+
}
1608
+
}
1609
+
},
1610
+
"node_modules/@radix-ui/react-slot": {
1611
+
"version": "1.2.3",
1612
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
1613
+
"integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==",
1614
+
"license": "MIT",
1615
+
"dependencies": {
1616
+
"@radix-ui/react-compose-refs": "1.1.2"
1617
+
},
1618
+
"peerDependencies": {
1619
+
"@types/react": "*",
1620
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1621
+
},
1622
+
"peerDependenciesMeta": {
1623
+
"@types/react": {
1624
+
"optional": true
1625
+
}
1626
+
}
1627
+
},
1628
+
"node_modules/@radix-ui/react-use-callback-ref": {
1629
+
"version": "1.1.1",
1630
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz",
1631
+
"integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==",
1632
+
"license": "MIT",
1633
+
"peerDependencies": {
1634
+
"@types/react": "*",
1635
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1636
+
},
1637
+
"peerDependenciesMeta": {
1638
+
"@types/react": {
1639
+
"optional": true
1640
+
}
1641
+
}
1642
+
},
1643
+
"node_modules/@radix-ui/react-use-controllable-state": {
1644
+
"version": "1.2.2",
1645
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz",
1646
+
"integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==",
1647
+
"license": "MIT",
1648
+
"dependencies": {
1649
+
"@radix-ui/react-use-effect-event": "0.0.2",
1650
+
"@radix-ui/react-use-layout-effect": "1.1.1"
1651
+
},
1652
+
"peerDependencies": {
1653
+
"@types/react": "*",
1654
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1655
+
},
1656
+
"peerDependenciesMeta": {
1657
+
"@types/react": {
1658
+
"optional": true
1659
+
}
1660
+
}
1661
+
},
1662
+
"node_modules/@radix-ui/react-use-effect-event": {
1663
+
"version": "0.0.2",
1664
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz",
1665
+
"integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==",
1666
+
"license": "MIT",
1667
+
"dependencies": {
1668
+
"@radix-ui/react-use-layout-effect": "1.1.1"
1669
+
},
1670
+
"peerDependencies": {
1671
+
"@types/react": "*",
1672
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1673
+
},
1674
+
"peerDependenciesMeta": {
1675
+
"@types/react": {
1676
+
"optional": true
1677
+
}
1678
+
}
1679
+
},
1680
+
"node_modules/@radix-ui/react-use-escape-keydown": {
1681
+
"version": "1.1.1",
1682
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz",
1683
+
"integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==",
1684
+
"license": "MIT",
1685
+
"dependencies": {
1686
+
"@radix-ui/react-use-callback-ref": "1.1.1"
1687
+
},
1688
+
"peerDependencies": {
1689
+
"@types/react": "*",
1690
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1691
+
},
1692
+
"peerDependenciesMeta": {
1693
+
"@types/react": {
1694
+
"optional": true
1695
+
}
1696
+
}
1697
+
},
1698
+
"node_modules/@radix-ui/react-use-layout-effect": {
1699
+
"version": "1.1.1",
1700
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz",
1701
+
"integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==",
1702
+
"license": "MIT",
1703
+
"peerDependencies": {
1704
+
"@types/react": "*",
1705
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1706
+
},
1707
+
"peerDependenciesMeta": {
1708
+
"@types/react": {
1709
+
"optional": true
1710
+
}
1711
+
}
1712
+
},
1713
+
"node_modules/@radix-ui/react-use-previous": {
1714
+
"version": "1.1.1",
1715
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz",
1716
+
"integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==",
1717
+
"license": "MIT",
1718
+
"peerDependencies": {
1719
+
"@types/react": "*",
1720
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1721
+
},
1722
+
"peerDependenciesMeta": {
1723
+
"@types/react": {
1724
+
"optional": true
1725
+
}
1726
+
}
1727
+
},
1728
+
"node_modules/@radix-ui/react-use-rect": {
1729
+
"version": "1.1.1",
1730
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz",
1731
+
"integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==",
1732
+
"license": "MIT",
1733
+
"dependencies": {
1734
+
"@radix-ui/rect": "1.1.1"
1735
+
},
1736
+
"peerDependencies": {
1737
+
"@types/react": "*",
1738
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1739
+
},
1740
+
"peerDependenciesMeta": {
1741
+
"@types/react": {
1742
+
"optional": true
1743
+
}
1744
+
}
1745
+
},
1746
+
"node_modules/@radix-ui/react-use-size": {
1747
+
"version": "1.1.1",
1748
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz",
1749
+
"integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==",
1750
+
"license": "MIT",
1751
+
"dependencies": {
1752
+
"@radix-ui/react-use-layout-effect": "1.1.1"
1753
+
},
1754
+
"peerDependencies": {
1755
+
"@types/react": "*",
1756
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1757
+
},
1758
+
"peerDependenciesMeta": {
1759
+
"@types/react": {
1760
+
"optional": true
1761
+
}
1762
+
}
1763
+
},
1764
+
"node_modules/@radix-ui/react-visually-hidden": {
1765
+
"version": "1.2.3",
1766
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz",
1767
+
"integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==",
1768
+
"license": "MIT",
1769
+
"dependencies": {
1770
+
"@radix-ui/react-primitive": "2.1.3"
1771
+
},
1772
+
"peerDependencies": {
1773
+
"@types/react": "*",
1774
+
"@types/react-dom": "*",
1775
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
1776
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1777
+
},
1778
+
"peerDependenciesMeta": {
1779
+
"@types/react": {
1780
+
"optional": true
1781
+
},
1782
+
"@types/react-dom": {
1783
+
"optional": true
1784
+
}
1785
+
}
1786
+
},
1787
+
"node_modules/@radix-ui/rect": {
1788
+
"version": "1.1.1",
1789
+
"resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz",
1790
+
"integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==",
1791
+
"license": "MIT"
1792
+
},
1793
+
"node_modules/@rolldown/pluginutils": {
1794
+
"version": "1.0.0-beta.27",
1795
+
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz",
1796
+
"integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==",
1797
+
"dev": true,
1798
+
"license": "MIT"
1799
+
},
1800
+
"node_modules/@rollup/rollup-android-arm-eabi": {
1801
+
"version": "4.46.2",
1802
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.46.2.tgz",
1803
+
"integrity": "sha512-Zj3Hl6sN34xJtMv7Anwb5Gu01yujyE/cLBDB2gnHTAHaWS1Z38L7kuSG+oAh0giZMqG060f/YBStXtMH6FvPMA==",
1804
+
"cpu": [
1805
+
"arm"
1806
+
],
1807
+
"license": "MIT",
1808
+
"optional": true,
1809
+
"os": [
1810
+
"android"
1811
+
]
1812
+
},
1813
+
"node_modules/@rollup/rollup-android-arm64": {
1814
+
"version": "4.46.2",
1815
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.46.2.tgz",
1816
+
"integrity": "sha512-nTeCWY83kN64oQ5MGz3CgtPx8NSOhC5lWtsjTs+8JAJNLcP3QbLCtDDgUKQc/Ro/frpMq4SHUaHN6AMltcEoLQ==",
1817
+
"cpu": [
1818
+
"arm64"
1819
+
],
1820
+
"license": "MIT",
1821
+
"optional": true,
1822
+
"os": [
1823
+
"android"
1824
+
]
1825
+
},
1826
+
"node_modules/@rollup/rollup-darwin-arm64": {
1827
+
"version": "4.46.2",
1828
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.46.2.tgz",
1829
+
"integrity": "sha512-HV7bW2Fb/F5KPdM/9bApunQh68YVDU8sO8BvcW9OngQVN3HHHkw99wFupuUJfGR9pYLLAjcAOA6iO+evsbBaPQ==",
1830
+
"cpu": [
1831
+
"arm64"
1832
+
],
1833
+
"license": "MIT",
1834
+
"optional": true,
1835
+
"os": [
1836
+
"darwin"
1837
+
]
1838
+
},
1839
+
"node_modules/@rollup/rollup-darwin-x64": {
1840
+
"version": "4.46.2",
1841
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.46.2.tgz",
1842
+
"integrity": "sha512-SSj8TlYV5nJixSsm/y3QXfhspSiLYP11zpfwp6G/YDXctf3Xkdnk4woJIF5VQe0of2OjzTt8EsxnJDCdHd2xMA==",
1843
+
"cpu": [
1844
+
"x64"
1845
+
],
1846
+
"license": "MIT",
1847
+
"optional": true,
1848
+
"os": [
1849
+
"darwin"
1850
+
]
1851
+
},
1852
+
"node_modules/@rollup/rollup-freebsd-arm64": {
1853
+
"version": "4.46.2",
1854
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.46.2.tgz",
1855
+
"integrity": "sha512-ZyrsG4TIT9xnOlLsSSi9w/X29tCbK1yegE49RYm3tu3wF1L/B6LVMqnEWyDB26d9Ecx9zrmXCiPmIabVuLmNSg==",
1856
+
"cpu": [
1857
+
"arm64"
1858
+
],
1859
+
"license": "MIT",
1860
+
"optional": true,
1861
+
"os": [
1862
+
"freebsd"
1863
+
]
1864
+
},
1865
+
"node_modules/@rollup/rollup-freebsd-x64": {
1866
+
"version": "4.46.2",
1867
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.46.2.tgz",
1868
+
"integrity": "sha512-pCgHFoOECwVCJ5GFq8+gR8SBKnMO+xe5UEqbemxBpCKYQddRQMgomv1104RnLSg7nNvgKy05sLsY51+OVRyiVw==",
1869
+
"cpu": [
1870
+
"x64"
1871
+
],
1872
+
"license": "MIT",
1873
+
"optional": true,
1874
+
"os": [
1875
+
"freebsd"
1876
+
]
1877
+
},
1878
+
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
1879
+
"version": "4.46.2",
1880
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.46.2.tgz",
1881
+
"integrity": "sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA==",
1882
+
"cpu": [
1883
+
"arm"
1884
+
],
1885
+
"license": "MIT",
1886
+
"optional": true,
1887
+
"os": [
1888
+
"linux"
1889
+
]
1890
+
},
1891
+
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
1892
+
"version": "4.46.2",
1893
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.46.2.tgz",
1894
+
"integrity": "sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ==",
1895
+
"cpu": [
1896
+
"arm"
1897
+
],
1898
+
"license": "MIT",
1899
+
"optional": true,
1900
+
"os": [
1901
+
"linux"
1902
+
]
1903
+
},
1904
+
"node_modules/@rollup/rollup-linux-arm64-gnu": {
1905
+
"version": "4.46.2",
1906
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.46.2.tgz",
1907
+
"integrity": "sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng==",
1908
+
"cpu": [
1909
+
"arm64"
1910
+
],
1911
+
"license": "MIT",
1912
+
"optional": true,
1913
+
"os": [
1914
+
"linux"
1915
+
]
1916
+
},
1917
+
"node_modules/@rollup/rollup-linux-arm64-musl": {
1918
+
"version": "4.46.2",
1919
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.46.2.tgz",
1920
+
"integrity": "sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg==",
1921
+
"cpu": [
1922
+
"arm64"
1923
+
],
1924
+
"license": "MIT",
1925
+
"optional": true,
1926
+
"os": [
1927
+
"linux"
1928
+
]
1929
+
},
1930
+
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
1931
+
"version": "4.46.2",
1932
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.46.2.tgz",
1933
+
"integrity": "sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA==",
1934
+
"cpu": [
1935
+
"loong64"
1936
+
],
1937
+
"license": "MIT",
1938
+
"optional": true,
1939
+
"os": [
1940
+
"linux"
1941
+
]
1942
+
},
1943
+
"node_modules/@rollup/rollup-linux-ppc64-gnu": {
1944
+
"version": "4.46.2",
1945
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.46.2.tgz",
1946
+
"integrity": "sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw==",
1947
+
"cpu": [
1948
+
"ppc64"
1949
+
],
1950
+
"license": "MIT",
1951
+
"optional": true,
1952
+
"os": [
1953
+
"linux"
1954
+
]
1955
+
},
1956
+
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
1957
+
"version": "4.46.2",
1958
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.46.2.tgz",
1959
+
"integrity": "sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ==",
1960
+
"cpu": [
1961
+
"riscv64"
1962
+
],
1963
+
"license": "MIT",
1964
+
"optional": true,
1965
+
"os": [
1966
+
"linux"
1967
+
]
1968
+
},
1969
+
"node_modules/@rollup/rollup-linux-riscv64-musl": {
1970
+
"version": "4.46.2",
1971
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.46.2.tgz",
1972
+
"integrity": "sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw==",
1973
+
"cpu": [
1974
+
"riscv64"
1975
+
],
1976
+
"license": "MIT",
1977
+
"optional": true,
1978
+
"os": [
1979
+
"linux"
1980
+
]
1981
+
},
1982
+
"node_modules/@rollup/rollup-linux-s390x-gnu": {
1983
+
"version": "4.46.2",
1984
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.46.2.tgz",
1985
+
"integrity": "sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA==",
1986
+
"cpu": [
1987
+
"s390x"
1988
+
],
1989
+
"license": "MIT",
1990
+
"optional": true,
1991
+
"os": [
1992
+
"linux"
1993
+
]
1994
+
},
1995
+
"node_modules/@rollup/rollup-linux-x64-gnu": {
1996
+
"version": "4.46.2",
1997
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.46.2.tgz",
1998
+
"integrity": "sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==",
1999
+
"cpu": [
2000
+
"x64"
2001
+
],
2002
+
"license": "MIT",
2003
+
"optional": true,
2004
+
"os": [
2005
+
"linux"
2006
+
]
2007
+
},
2008
+
"node_modules/@rollup/rollup-linux-x64-musl": {
2009
+
"version": "4.46.2",
2010
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.46.2.tgz",
2011
+
"integrity": "sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==",
2012
+
"cpu": [
2013
+
"x64"
2014
+
],
2015
+
"license": "MIT",
2016
+
"optional": true,
2017
+
"os": [
2018
+
"linux"
2019
+
]
2020
+
},
2021
+
"node_modules/@rollup/rollup-win32-arm64-msvc": {
2022
+
"version": "4.46.2",
2023
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.46.2.tgz",
2024
+
"integrity": "sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g==",
2025
+
"cpu": [
2026
+
"arm64"
2027
+
],
2028
+
"license": "MIT",
2029
+
"optional": true,
2030
+
"os": [
2031
+
"win32"
2032
+
]
2033
+
},
2034
+
"node_modules/@rollup/rollup-win32-ia32-msvc": {
2035
+
"version": "4.46.2",
2036
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.46.2.tgz",
2037
+
"integrity": "sha512-gBgaUDESVzMgWZhcyjfs9QFK16D8K6QZpwAaVNJxYDLHWayOta4ZMjGm/vsAEy3hvlS2GosVFlBlP9/Wb85DqQ==",
2038
+
"cpu": [
2039
+
"ia32"
2040
+
],
2041
+
"license": "MIT",
2042
+
"optional": true,
2043
+
"os": [
2044
+
"win32"
2045
+
]
2046
+
},
2047
+
"node_modules/@rollup/rollup-win32-x64-msvc": {
2048
+
"version": "4.46.2",
2049
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.46.2.tgz",
2050
+
"integrity": "sha512-CvUo2ixeIQGtF6WvuB87XWqPQkoFAFqW+HUo/WzHwuHDvIwZCtjdWXoYCcr06iKGydiqTclC4jU/TNObC/xKZg==",
2051
+
"cpu": [
2052
+
"x64"
2053
+
],
2054
+
"license": "MIT",
2055
+
"optional": true,
2056
+
"os": [
2057
+
"win32"
2058
+
]
2059
+
},
2060
+
"node_modules/@tailwindcss/node": {
2061
+
"version": "4.1.11",
2062
+
"resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.11.tgz",
2063
+
"integrity": "sha512-yzhzuGRmv5QyU9qLNg4GTlYI6STedBWRE7NjxP45CsFYYq9taI0zJXZBMqIC/c8fViNLhmrbpSFS57EoxUmD6Q==",
2064
+
"license": "MIT",
2065
+
"dependencies": {
2066
+
"@ampproject/remapping": "^2.3.0",
2067
+
"enhanced-resolve": "^5.18.1",
2068
+
"jiti": "^2.4.2",
2069
+
"lightningcss": "1.30.1",
2070
+
"magic-string": "^0.30.17",
2071
+
"source-map-js": "^1.2.1",
2072
+
"tailwindcss": "4.1.11"
2073
+
}
2074
+
},
2075
+
"node_modules/@tailwindcss/oxide": {
2076
+
"version": "4.1.11",
2077
+
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.11.tgz",
2078
+
"integrity": "sha512-Q69XzrtAhuyfHo+5/HMgr1lAiPP/G40OMFAnws7xcFEYqcypZmdW8eGXaOUIeOl1dzPJBPENXgbjsOyhg2nkrg==",
2079
+
"hasInstallScript": true,
2080
+
"license": "MIT",
2081
+
"dependencies": {
2082
+
"detect-libc": "^2.0.4",
2083
+
"tar": "^7.4.3"
2084
+
},
2085
+
"engines": {
2086
+
"node": ">= 10"
2087
+
},
2088
+
"optionalDependencies": {
2089
+
"@tailwindcss/oxide-android-arm64": "4.1.11",
2090
+
"@tailwindcss/oxide-darwin-arm64": "4.1.11",
2091
+
"@tailwindcss/oxide-darwin-x64": "4.1.11",
2092
+
"@tailwindcss/oxide-freebsd-x64": "4.1.11",
2093
+
"@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.11",
2094
+
"@tailwindcss/oxide-linux-arm64-gnu": "4.1.11",
2095
+
"@tailwindcss/oxide-linux-arm64-musl": "4.1.11",
2096
+
"@tailwindcss/oxide-linux-x64-gnu": "4.1.11",
2097
+
"@tailwindcss/oxide-linux-x64-musl": "4.1.11",
2098
+
"@tailwindcss/oxide-wasm32-wasi": "4.1.11",
2099
+
"@tailwindcss/oxide-win32-arm64-msvc": "4.1.11",
2100
+
"@tailwindcss/oxide-win32-x64-msvc": "4.1.11"
2101
+
}
2102
+
},
2103
+
"node_modules/@tailwindcss/oxide-android-arm64": {
2104
+
"version": "4.1.11",
2105
+
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.11.tgz",
2106
+
"integrity": "sha512-3IfFuATVRUMZZprEIx9OGDjG3Ou3jG4xQzNTvjDoKmU9JdmoCohQJ83MYd0GPnQIu89YoJqvMM0G3uqLRFtetg==",
2107
+
"cpu": [
2108
+
"arm64"
2109
+
],
2110
+
"license": "MIT",
2111
+
"optional": true,
2112
+
"os": [
2113
+
"android"
2114
+
],
2115
+
"engines": {
2116
+
"node": ">= 10"
2117
+
}
2118
+
},
2119
+
"node_modules/@tailwindcss/oxide-darwin-arm64": {
2120
+
"version": "4.1.11",
2121
+
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.11.tgz",
2122
+
"integrity": "sha512-ESgStEOEsyg8J5YcMb1xl8WFOXfeBmrhAwGsFxxB2CxY9evy63+AtpbDLAyRkJnxLy2WsD1qF13E97uQyP1lfQ==",
2123
+
"cpu": [
2124
+
"arm64"
2125
+
],
2126
+
"license": "MIT",
2127
+
"optional": true,
2128
+
"os": [
2129
+
"darwin"
2130
+
],
2131
+
"engines": {
2132
+
"node": ">= 10"
2133
+
}
2134
+
},
2135
+
"node_modules/@tailwindcss/oxide-darwin-x64": {
2136
+
"version": "4.1.11",
2137
+
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.11.tgz",
2138
+
"integrity": "sha512-EgnK8kRchgmgzG6jE10UQNaH9Mwi2n+yw1jWmof9Vyg2lpKNX2ioe7CJdf9M5f8V9uaQxInenZkOxnTVL3fhAw==",
2139
+
"cpu": [
2140
+
"x64"
2141
+
],
2142
+
"license": "MIT",
2143
+
"optional": true,
2144
+
"os": [
2145
+
"darwin"
2146
+
],
2147
+
"engines": {
2148
+
"node": ">= 10"
2149
+
}
2150
+
},
2151
+
"node_modules/@tailwindcss/oxide-freebsd-x64": {
2152
+
"version": "4.1.11",
2153
+
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.11.tgz",
2154
+
"integrity": "sha512-xdqKtbpHs7pQhIKmqVpxStnY1skuNh4CtbcyOHeX1YBE0hArj2romsFGb6yUmzkq/6M24nkxDqU8GYrKrz+UcA==",
2155
+
"cpu": [
2156
+
"x64"
2157
+
],
2158
+
"license": "MIT",
2159
+
"optional": true,
2160
+
"os": [
2161
+
"freebsd"
2162
+
],
2163
+
"engines": {
2164
+
"node": ">= 10"
2165
+
}
2166
+
},
2167
+
"node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
2168
+
"version": "4.1.11",
2169
+
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.11.tgz",
2170
+
"integrity": "sha512-ryHQK2eyDYYMwB5wZL46uoxz2zzDZsFBwfjssgB7pzytAeCCa6glsiJGjhTEddq/4OsIjsLNMAiMlHNYnkEEeg==",
2171
+
"cpu": [
2172
+
"arm"
2173
+
],
2174
+
"license": "MIT",
2175
+
"optional": true,
2176
+
"os": [
2177
+
"linux"
2178
+
],
2179
+
"engines": {
2180
+
"node": ">= 10"
2181
+
}
2182
+
},
2183
+
"node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
2184
+
"version": "4.1.11",
2185
+
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.11.tgz",
2186
+
"integrity": "sha512-mYwqheq4BXF83j/w75ewkPJmPZIqqP1nhoghS9D57CLjsh3Nfq0m4ftTotRYtGnZd3eCztgbSPJ9QhfC91gDZQ==",
2187
+
"cpu": [
2188
+
"arm64"
2189
+
],
2190
+
"license": "MIT",
2191
+
"optional": true,
2192
+
"os": [
2193
+
"linux"
2194
+
],
2195
+
"engines": {
2196
+
"node": ">= 10"
2197
+
}
2198
+
},
2199
+
"node_modules/@tailwindcss/oxide-linux-arm64-musl": {
2200
+
"version": "4.1.11",
2201
+
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.11.tgz",
2202
+
"integrity": "sha512-m/NVRFNGlEHJrNVk3O6I9ggVuNjXHIPoD6bqay/pubtYC9QIdAMpS+cswZQPBLvVvEF6GtSNONbDkZrjWZXYNQ==",
2203
+
"cpu": [
2204
+
"arm64"
2205
+
],
2206
+
"license": "MIT",
2207
+
"optional": true,
2208
+
"os": [
2209
+
"linux"
2210
+
],
2211
+
"engines": {
2212
+
"node": ">= 10"
2213
+
}
2214
+
},
2215
+
"node_modules/@tailwindcss/oxide-linux-x64-gnu": {
2216
+
"version": "4.1.11",
2217
+
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.11.tgz",
2218
+
"integrity": "sha512-YW6sblI7xukSD2TdbbaeQVDysIm/UPJtObHJHKxDEcW2exAtY47j52f8jZXkqE1krdnkhCMGqP3dbniu1Te2Fg==",
2219
+
"cpu": [
2220
+
"x64"
2221
+
],
2222
+
"license": "MIT",
2223
+
"optional": true,
2224
+
"os": [
2225
+
"linux"
2226
+
],
2227
+
"engines": {
2228
+
"node": ">= 10"
2229
+
}
2230
+
},
2231
+
"node_modules/@tailwindcss/oxide-linux-x64-musl": {
2232
+
"version": "4.1.11",
2233
+
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.11.tgz",
2234
+
"integrity": "sha512-e3C/RRhGunWYNC3aSF7exsQkdXzQ/M+aYuZHKnw4U7KQwTJotnWsGOIVih0s2qQzmEzOFIJ3+xt7iq67K/p56Q==",
2235
+
"cpu": [
2236
+
"x64"
2237
+
],
2238
+
"license": "MIT",
2239
+
"optional": true,
2240
+
"os": [
2241
+
"linux"
2242
+
],
2243
+
"engines": {
2244
+
"node": ">= 10"
2245
+
}
2246
+
},
2247
+
"node_modules/@tailwindcss/oxide-wasm32-wasi": {
2248
+
"version": "4.1.11",
2249
+
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.11.tgz",
2250
+
"integrity": "sha512-Xo1+/GU0JEN/C/dvcammKHzeM6NqKovG+6921MR6oadee5XPBaKOumrJCXvopJ/Qb5TH7LX/UAywbqrP4lax0g==",
2251
+
"bundleDependencies": [
2252
+
"@napi-rs/wasm-runtime",
2253
+
"@emnapi/core",
2254
+
"@emnapi/runtime",
2255
+
"@tybys/wasm-util",
2256
+
"@emnapi/wasi-threads",
2257
+
"tslib"
2258
+
],
2259
+
"cpu": [
2260
+
"wasm32"
2261
+
],
2262
+
"license": "MIT",
2263
+
"optional": true,
2264
+
"dependencies": {
2265
+
"@emnapi/core": "^1.4.3",
2266
+
"@emnapi/runtime": "^1.4.3",
2267
+
"@emnapi/wasi-threads": "^1.0.2",
2268
+
"@napi-rs/wasm-runtime": "^0.2.11",
2269
+
"@tybys/wasm-util": "^0.9.0",
2270
+
"tslib": "^2.8.0"
2271
+
},
2272
+
"engines": {
2273
+
"node": ">=14.0.0"
2274
+
}
2275
+
},
2276
+
"node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
2277
+
"version": "4.1.11",
2278
+
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.11.tgz",
2279
+
"integrity": "sha512-UgKYx5PwEKrac3GPNPf6HVMNhUIGuUh4wlDFR2jYYdkX6pL/rn73zTq/4pzUm8fOjAn5L8zDeHp9iXmUGOXZ+w==",
2280
+
"cpu": [
2281
+
"arm64"
2282
+
],
2283
+
"license": "MIT",
2284
+
"optional": true,
2285
+
"os": [
2286
+
"win32"
2287
+
],
2288
+
"engines": {
2289
+
"node": ">= 10"
2290
+
}
2291
+
},
2292
+
"node_modules/@tailwindcss/oxide-win32-x64-msvc": {
2293
+
"version": "4.1.11",
2294
+
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.11.tgz",
2295
+
"integrity": "sha512-YfHoggn1j0LK7wR82TOucWc5LDCguHnoS879idHekmmiR7g9HUtMw9MI0NHatS28u/Xlkfi9w5RJWgz2Dl+5Qg==",
2296
+
"cpu": [
2297
+
"x64"
2298
+
],
2299
+
"license": "MIT",
2300
+
"optional": true,
2301
+
"os": [
2302
+
"win32"
2303
+
],
2304
+
"engines": {
2305
+
"node": ">= 10"
2306
+
}
2307
+
},
2308
+
"node_modules/@tailwindcss/vite": {
2309
+
"version": "4.1.11",
2310
+
"resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.11.tgz",
2311
+
"integrity": "sha512-RHYhrR3hku0MJFRV+fN2gNbDNEh3dwKvY8XJvTxCSXeMOsCRSr+uKvDWQcbizrHgjML6ZmTE5OwMrl5wKcujCw==",
2312
+
"license": "MIT",
2313
+
"dependencies": {
2314
+
"@tailwindcss/node": "4.1.11",
2315
+
"@tailwindcss/oxide": "4.1.11",
2316
+
"tailwindcss": "4.1.11"
2317
+
},
2318
+
"peerDependencies": {
2319
+
"vite": "^5.2.0 || ^6 || ^7"
2320
+
}
2321
+
},
2322
+
"node_modules/@tanstack/history": {
2323
+
"version": "1.130.12",
2324
+
"resolved": "https://registry.npmjs.org/@tanstack/history/-/history-1.130.12.tgz",
2325
+
"integrity": "sha512-2VO1nNFDWojgZ7Uqv/OJfH6LphZQ1kE6l8sI3YBgSPtj3qN6I/rsoTHW9rGjwiDO8sQoDRXod2hpH6HMs5NDsw==",
2326
+
"license": "MIT",
2327
+
"engines": {
2328
+
"node": ">=12"
2329
+
},
2330
+
"funding": {
2331
+
"type": "github",
2332
+
"url": "https://github.com/sponsors/tannerlinsley"
2333
+
}
2334
+
},
2335
+
"node_modules/@tanstack/query-core": {
2336
+
"version": "5.83.1",
2337
+
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.83.1.tgz",
2338
+
"integrity": "sha512-OG69LQgT7jSp+5pPuCfzltq/+7l2xoweggjme9vlbCPa/d7D7zaqv5vN/S82SzSYZ4EDLTxNO1PWrv49RAS64Q==",
2339
+
"license": "MIT",
2340
+
"funding": {
2341
+
"type": "github",
2342
+
"url": "https://github.com/sponsors/tannerlinsley"
2343
+
}
2344
+
},
2345
+
"node_modules/@tanstack/react-query": {
2346
+
"version": "5.84.1",
2347
+
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.84.1.tgz",
2348
+
"integrity": "sha512-zo7EUygcWJMQfFNWDSG7CBhy8irje/XY0RDVKKV4IQJAysb+ZJkkJPcnQi+KboyGUgT+SQebRFoTqLuTtfoDLw==",
2349
+
"license": "MIT",
2350
+
"dependencies": {
2351
+
"@tanstack/query-core": "5.83.1"
2352
+
},
2353
+
"funding": {
2354
+
"type": "github",
2355
+
"url": "https://github.com/sponsors/tannerlinsley"
2356
+
},
2357
+
"peerDependencies": {
2358
+
"react": "^18 || ^19"
2359
+
}
2360
+
},
2361
+
"node_modules/@tanstack/react-router": {
2362
+
"version": "1.130.12",
2363
+
"resolved": "https://registry.npmjs.org/@tanstack/react-router/-/react-router-1.130.12.tgz",
2364
+
"integrity": "sha512-7BYgOpGc1vK8MH1LIFLLBudGpH46GQy+hewnP7dNQJ4KHmkwPHv958L1IMA9jU/rs5g1ZH5n1f33BAMOBXUMYQ==",
2365
+
"license": "MIT",
2366
+
"dependencies": {
2367
+
"@tanstack/history": "1.130.12",
2368
+
"@tanstack/react-store": "^0.7.0",
2369
+
"@tanstack/router-core": "1.130.12",
2370
+
"isbot": "^5.1.22",
2371
+
"tiny-invariant": "^1.3.3",
2372
+
"tiny-warning": "^1.0.3"
2373
+
},
2374
+
"engines": {
2375
+
"node": ">=12"
2376
+
},
2377
+
"funding": {
2378
+
"type": "github",
2379
+
"url": "https://github.com/sponsors/tannerlinsley"
2380
+
},
2381
+
"peerDependencies": {
2382
+
"react": ">=18.0.0 || >=19.0.0",
2383
+
"react-dom": ">=18.0.0 || >=19.0.0"
2384
+
}
2385
+
},
2386
+
"node_modules/@tanstack/react-router-devtools": {
2387
+
"version": "1.130.13",
2388
+
"resolved": "https://registry.npmjs.org/@tanstack/react-router-devtools/-/react-router-devtools-1.130.13.tgz",
2389
+
"integrity": "sha512-cY+jYxEP4/WNDgFFlI5/1u2U9zY9zHmJDoNxCF3NiaSgtAIVHdCKRGvfG6oRl6EposNGtn+JJhQkMkfAyoN9lQ==",
2390
+
"license": "MIT",
2391
+
"dependencies": {
2392
+
"@tanstack/router-devtools-core": "1.130.13"
2393
+
},
2394
+
"engines": {
2395
+
"node": ">=12"
2396
+
},
2397
+
"funding": {
2398
+
"type": "github",
2399
+
"url": "https://github.com/sponsors/tannerlinsley"
2400
+
},
2401
+
"peerDependencies": {
2402
+
"@tanstack/react-router": "^1.130.12",
2403
+
"react": ">=18.0.0 || >=19.0.0",
2404
+
"react-dom": ">=18.0.0 || >=19.0.0"
2405
+
}
2406
+
},
2407
+
"node_modules/@tanstack/react-store": {
2408
+
"version": "0.7.3",
2409
+
"resolved": "https://registry.npmjs.org/@tanstack/react-store/-/react-store-0.7.3.tgz",
2410
+
"integrity": "sha512-3Dnqtbw9P2P0gw8uUM8WP2fFfg8XMDSZCTsywRPZe/XqqYW8PGkXKZTvP0AHkE4mpqP9Y43GpOg9vwO44azu6Q==",
2411
+
"license": "MIT",
2412
+
"dependencies": {
2413
+
"@tanstack/store": "0.7.2",
2414
+
"use-sync-external-store": "^1.5.0"
2415
+
},
2416
+
"funding": {
2417
+
"type": "github",
2418
+
"url": "https://github.com/sponsors/tannerlinsley"
2419
+
},
2420
+
"peerDependencies": {
2421
+
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
2422
+
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
2423
+
}
2424
+
},
2425
+
"node_modules/@tanstack/router-core": {
2426
+
"version": "1.130.12",
2427
+
"resolved": "https://registry.npmjs.org/@tanstack/router-core/-/router-core-1.130.12.tgz",
2428
+
"integrity": "sha512-emq3cRU9Na1hnIToojzkfJcOZm/MG2bv9M+Kr/elUxEf83enGEwQXC1EKezTuwNgeJrOv8vPJdEhWM7IQodnHQ==",
2429
+
"license": "MIT",
2430
+
"dependencies": {
2431
+
"@tanstack/history": "1.130.12",
2432
+
"@tanstack/store": "^0.7.0",
2433
+
"cookie-es": "^1.2.2",
2434
+
"seroval": "^1.3.2",
2435
+
"seroval-plugins": "^1.3.2",
2436
+
"tiny-invariant": "^1.3.3",
2437
+
"tiny-warning": "^1.0.3"
2438
+
},
2439
+
"engines": {
2440
+
"node": ">=12"
2441
+
},
2442
+
"funding": {
2443
+
"type": "github",
2444
+
"url": "https://github.com/sponsors/tannerlinsley"
2445
+
}
2446
+
},
2447
+
"node_modules/@tanstack/router-devtools-core": {
2448
+
"version": "1.130.13",
2449
+
"resolved": "https://registry.npmjs.org/@tanstack/router-devtools-core/-/router-devtools-core-1.130.13.tgz",
2450
+
"integrity": "sha512-Fn8lwnc5zvyllaDQNY6qTSTtKZsEY4mlZlJVTmC2/vvY1susXUA0NQPmpBquJYQAHJGzqPX83h/yKb7hzBSH3g==",
2451
+
"license": "MIT",
2452
+
"dependencies": {
2453
+
"clsx": "^2.1.1",
2454
+
"goober": "^2.1.16",
2455
+
"solid-js": "^1.9.5"
2456
+
},
2457
+
"engines": {
2458
+
"node": ">=12"
2459
+
},
2460
+
"funding": {
2461
+
"type": "github",
2462
+
"url": "https://github.com/sponsors/tannerlinsley"
2463
+
},
2464
+
"peerDependencies": {
2465
+
"@tanstack/router-core": "^1.130.12",
2466
+
"csstype": "^3.0.10",
2467
+
"solid-js": ">=1.9.5",
2468
+
"tiny-invariant": "^1.3.3"
2469
+
},
2470
+
"peerDependenciesMeta": {
2471
+
"csstype": {
2472
+
"optional": true
2473
+
}
2474
+
}
2475
+
},
2476
+
"node_modules/@tanstack/router-generator": {
2477
+
"version": "1.130.15",
2478
+
"resolved": "https://registry.npmjs.org/@tanstack/router-generator/-/router-generator-1.130.15.tgz",
2479
+
"integrity": "sha512-2TICfuSN8oYydTHd+nATkKV4B37XRrAWrwK9+g5dPVUP9lhLy7FQy3IVcb1HRXFXvW0zr5zPNxXErTrOmrceyA==",
2480
+
"license": "MIT",
2481
+
"dependencies": {
2482
+
"@tanstack/router-core": "1.130.12",
2483
+
"@tanstack/router-utils": "1.130.12",
2484
+
"@tanstack/virtual-file-routes": "1.129.7",
2485
+
"prettier": "^3.5.0",
2486
+
"recast": "^0.23.11",
2487
+
"source-map": "^0.7.4",
2488
+
"tsx": "^4.19.2",
2489
+
"zod": "^3.24.2"
2490
+
},
2491
+
"engines": {
2492
+
"node": ">=12"
2493
+
},
2494
+
"funding": {
2495
+
"type": "github",
2496
+
"url": "https://github.com/sponsors/tannerlinsley"
2497
+
}
2498
+
},
2499
+
"node_modules/@tanstack/router-plugin": {
2500
+
"version": "1.130.15",
2501
+
"resolved": "https://registry.npmjs.org/@tanstack/router-plugin/-/router-plugin-1.130.15.tgz",
2502
+
"integrity": "sha512-ovYGN0a5CxIPkVdbJPLAqwlE0eUYhHm0PkPCH0TxR24XpEGaCxAOw92DriLRZj9R4xTg5oeJqM+3wiZJfujx/A==",
2503
+
"license": "MIT",
2504
+
"dependencies": {
2505
+
"@babel/core": "^7.27.7",
2506
+
"@babel/plugin-syntax-jsx": "^7.27.1",
2507
+
"@babel/plugin-syntax-typescript": "^7.27.1",
2508
+
"@babel/template": "^7.27.2",
2509
+
"@babel/traverse": "^7.27.7",
2510
+
"@babel/types": "^7.27.7",
2511
+
"@tanstack/router-core": "1.130.12",
2512
+
"@tanstack/router-generator": "1.130.15",
2513
+
"@tanstack/router-utils": "1.130.12",
2514
+
"@tanstack/virtual-file-routes": "1.129.7",
2515
+
"babel-dead-code-elimination": "^1.0.10",
2516
+
"chokidar": "^3.6.0",
2517
+
"unplugin": "^2.1.2",
2518
+
"zod": "^3.24.2"
2519
+
},
2520
+
"engines": {
2521
+
"node": ">=12"
2522
+
},
2523
+
"funding": {
2524
+
"type": "github",
2525
+
"url": "https://github.com/sponsors/tannerlinsley"
2526
+
},
2527
+
"peerDependencies": {
2528
+
"@rsbuild/core": ">=1.0.2",
2529
+
"@tanstack/react-router": "^1.130.12",
2530
+
"vite": ">=5.0.0 || >=6.0.0",
2531
+
"vite-plugin-solid": "^2.11.2",
2532
+
"webpack": ">=5.92.0"
2533
+
},
2534
+
"peerDependenciesMeta": {
2535
+
"@rsbuild/core": {
2536
+
"optional": true
2537
+
},
2538
+
"@tanstack/react-router": {
2539
+
"optional": true
2540
+
},
2541
+
"vite": {
2542
+
"optional": true
2543
+
},
2544
+
"vite-plugin-solid": {
2545
+
"optional": true
2546
+
},
2547
+
"webpack": {
2548
+
"optional": true
2549
+
}
2550
+
}
2551
+
},
2552
+
"node_modules/@tanstack/router-utils": {
2553
+
"version": "1.130.12",
2554
+
"resolved": "https://registry.npmjs.org/@tanstack/router-utils/-/router-utils-1.130.12.tgz",
2555
+
"integrity": "sha512-vyk7qduNrVrJWgUXHqRyZrFLOL9YJ/4ycN5PbJ2cLRBln01NkG/abKTHi32V31yMehxkxAO0EoicicvalnV0FA==",
2556
+
"license": "MIT",
2557
+
"dependencies": {
2558
+
"@babel/core": "^7.27.4",
2559
+
"@babel/generator": "^7.27.5",
2560
+
"@babel/parser": "^7.27.5",
2561
+
"@babel/preset-typescript": "^7.27.1",
2562
+
"ansis": "^4.1.0",
2563
+
"diff": "^8.0.2"
2564
+
},
2565
+
"engines": {
2566
+
"node": ">=12"
2567
+
},
2568
+
"funding": {
2569
+
"type": "github",
2570
+
"url": "https://github.com/sponsors/tannerlinsley"
2571
+
}
2572
+
},
2573
+
"node_modules/@tanstack/store": {
2574
+
"version": "0.7.2",
2575
+
"resolved": "https://registry.npmjs.org/@tanstack/store/-/store-0.7.2.tgz",
2576
+
"integrity": "sha512-RP80Z30BYiPX2Pyo0Nyw4s1SJFH2jyM6f9i3HfX4pA+gm5jsnYryscdq2aIQLnL4TaGuQMO+zXmN9nh1Qck+Pg==",
2577
+
"license": "MIT",
2578
+
"funding": {
2579
+
"type": "github",
2580
+
"url": "https://github.com/sponsors/tannerlinsley"
2581
+
}
2582
+
},
2583
+
"node_modules/@tanstack/virtual-file-routes": {
2584
+
"version": "1.129.7",
2585
+
"resolved": "https://registry.npmjs.org/@tanstack/virtual-file-routes/-/virtual-file-routes-1.129.7.tgz",
2586
+
"integrity": "sha512-a+MxoAXG+Sq94Jp67OtveKOp2vQq75AWdVI8DRt6w19B0NEqpfm784FTLbVp/qdR1wmxCOmKAvElGSIiBOx5OQ==",
2587
+
"license": "MIT",
2588
+
"engines": {
2589
+
"node": ">=12"
2590
+
},
2591
+
"funding": {
2592
+
"type": "github",
2593
+
"url": "https://github.com/sponsors/tannerlinsley"
2594
+
}
2595
+
},
2596
+
"node_modules/@testing-library/dom": {
2597
+
"version": "10.4.1",
2598
+
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz",
2599
+
"integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==",
2600
+
"dev": true,
2601
+
"license": "MIT",
2602
+
"dependencies": {
2603
+
"@babel/code-frame": "^7.10.4",
2604
+
"@babel/runtime": "^7.12.5",
2605
+
"@types/aria-query": "^5.0.1",
2606
+
"aria-query": "5.3.0",
2607
+
"dom-accessibility-api": "^0.5.9",
2608
+
"lz-string": "^1.5.0",
2609
+
"picocolors": "1.1.1",
2610
+
"pretty-format": "^27.0.2"
2611
+
},
2612
+
"engines": {
2613
+
"node": ">=18"
2614
+
}
2615
+
},
2616
+
"node_modules/@testing-library/react": {
2617
+
"version": "16.3.0",
2618
+
"resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.0.tgz",
2619
+
"integrity": "sha512-kFSyxiEDwv1WLl2fgsq6pPBbw5aWKrsY2/noi1Id0TK0UParSF62oFQFGHXIyaG4pp2tEub/Zlel+fjjZILDsw==",
2620
+
"dev": true,
2621
+
"license": "MIT",
2622
+
"dependencies": {
2623
+
"@babel/runtime": "^7.12.5"
2624
+
},
2625
+
"engines": {
2626
+
"node": ">=18"
2627
+
},
2628
+
"peerDependencies": {
2629
+
"@testing-library/dom": "^10.0.0",
2630
+
"@types/react": "^18.0.0 || ^19.0.0",
2631
+
"@types/react-dom": "^18.0.0 || ^19.0.0",
2632
+
"react": "^18.0.0 || ^19.0.0",
2633
+
"react-dom": "^18.0.0 || ^19.0.0"
2634
+
},
2635
+
"peerDependenciesMeta": {
2636
+
"@types/react": {
2637
+
"optional": true
2638
+
},
2639
+
"@types/react-dom": {
2640
+
"optional": true
2641
+
}
2642
+
}
2643
+
},
2644
+
"node_modules/@types/aria-query": {
2645
+
"version": "5.0.4",
2646
+
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
2647
+
"integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
2648
+
"dev": true,
2649
+
"license": "MIT"
2650
+
},
2651
+
"node_modules/@types/babel__core": {
2652
+
"version": "7.20.5",
2653
+
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
2654
+
"integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
2655
+
"dev": true,
2656
+
"license": "MIT",
2657
+
"dependencies": {
2658
+
"@babel/parser": "^7.20.7",
2659
+
"@babel/types": "^7.20.7",
2660
+
"@types/babel__generator": "*",
2661
+
"@types/babel__template": "*",
2662
+
"@types/babel__traverse": "*"
2663
+
}
2664
+
},
2665
+
"node_modules/@types/babel__generator": {
2666
+
"version": "7.27.0",
2667
+
"resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz",
2668
+
"integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==",
2669
+
"dev": true,
2670
+
"license": "MIT",
2671
+
"dependencies": {
2672
+
"@babel/types": "^7.0.0"
2673
+
}
2674
+
},
2675
+
"node_modules/@types/babel__template": {
2676
+
"version": "7.4.4",
2677
+
"resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
2678
+
"integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
2679
+
"dev": true,
2680
+
"license": "MIT",
2681
+
"dependencies": {
2682
+
"@babel/parser": "^7.1.0",
2683
+
"@babel/types": "^7.0.0"
2684
+
}
2685
+
},
2686
+
"node_modules/@types/babel__traverse": {
2687
+
"version": "7.28.0",
2688
+
"resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz",
2689
+
"integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==",
2690
+
"dev": true,
2691
+
"license": "MIT",
2692
+
"dependencies": {
2693
+
"@babel/types": "^7.28.2"
2694
+
}
2695
+
},
2696
+
"node_modules/@types/chai": {
2697
+
"version": "5.2.2",
2698
+
"resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.2.tgz",
2699
+
"integrity": "sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==",
2700
+
"dev": true,
2701
+
"license": "MIT",
2702
+
"dependencies": {
2703
+
"@types/deep-eql": "*"
2704
+
}
2705
+
},
2706
+
"node_modules/@types/deep-eql": {
2707
+
"version": "4.0.2",
2708
+
"resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz",
2709
+
"integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==",
2710
+
"dev": true,
2711
+
"license": "MIT"
2712
+
},
2713
+
"node_modules/@types/estree": {
2714
+
"version": "1.0.8",
2715
+
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
2716
+
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
2717
+
"license": "MIT"
2718
+
},
2719
+
"node_modules/@types/react": {
2720
+
"version": "19.1.9",
2721
+
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.9.tgz",
2722
+
"integrity": "sha512-WmdoynAX8Stew/36uTSVMcLJJ1KRh6L3IZRx1PZ7qJtBqT3dYTgyDTx8H1qoRghErydW7xw9mSJ3wS//tCRpFA==",
2723
+
"devOptional": true,
2724
+
"license": "MIT",
2725
+
"dependencies": {
2726
+
"csstype": "^3.0.2"
2727
+
}
2728
+
},
2729
+
"node_modules/@types/react-dom": {
2730
+
"version": "19.1.7",
2731
+
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.7.tgz",
2732
+
"integrity": "sha512-i5ZzwYpqjmrKenzkoLM2Ibzt6mAsM7pxB6BCIouEVVmgiqaMj1TjaK7hnA36hbW5aZv20kx7Lw6hWzPWg0Rurw==",
2733
+
"devOptional": true,
2734
+
"license": "MIT",
2735
+
"peerDependencies": {
2736
+
"@types/react": "^19.0.0"
2737
+
}
2738
+
},
2739
+
"node_modules/@vitejs/plugin-react": {
2740
+
"version": "4.7.0",
2741
+
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz",
2742
+
"integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==",
2743
+
"dev": true,
2744
+
"license": "MIT",
2745
+
"dependencies": {
2746
+
"@babel/core": "^7.28.0",
2747
+
"@babel/plugin-transform-react-jsx-self": "^7.27.1",
2748
+
"@babel/plugin-transform-react-jsx-source": "^7.27.1",
2749
+
"@rolldown/pluginutils": "1.0.0-beta.27",
2750
+
"@types/babel__core": "^7.20.5",
2751
+
"react-refresh": "^0.17.0"
2752
+
},
2753
+
"engines": {
2754
+
"node": "^14.18.0 || >=16.0.0"
2755
+
},
2756
+
"peerDependencies": {
2757
+
"vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
2758
+
}
2759
+
},
2760
+
"node_modules/@vitest/expect": {
2761
+
"version": "3.2.4",
2762
+
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz",
2763
+
"integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==",
2764
+
"dev": true,
2765
+
"license": "MIT",
2766
+
"dependencies": {
2767
+
"@types/chai": "^5.2.2",
2768
+
"@vitest/spy": "3.2.4",
2769
+
"@vitest/utils": "3.2.4",
2770
+
"chai": "^5.2.0",
2771
+
"tinyrainbow": "^2.0.0"
2772
+
},
2773
+
"funding": {
2774
+
"url": "https://opencollective.com/vitest"
2775
+
}
2776
+
},
2777
+
"node_modules/@vitest/mocker": {
2778
+
"version": "3.2.4",
2779
+
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.4.tgz",
2780
+
"integrity": "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==",
2781
+
"dev": true,
2782
+
"license": "MIT",
2783
+
"dependencies": {
2784
+
"@vitest/spy": "3.2.4",
2785
+
"estree-walker": "^3.0.3",
2786
+
"magic-string": "^0.30.17"
2787
+
},
2788
+
"funding": {
2789
+
"url": "https://opencollective.com/vitest"
2790
+
},
2791
+
"peerDependencies": {
2792
+
"msw": "^2.4.9",
2793
+
"vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0"
2794
+
},
2795
+
"peerDependenciesMeta": {
2796
+
"msw": {
2797
+
"optional": true
2798
+
},
2799
+
"vite": {
2800
+
"optional": true
2801
+
}
2802
+
}
2803
+
},
2804
+
"node_modules/@vitest/pretty-format": {
2805
+
"version": "3.2.4",
2806
+
"resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz",
2807
+
"integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==",
2808
+
"dev": true,
2809
+
"license": "MIT",
2810
+
"dependencies": {
2811
+
"tinyrainbow": "^2.0.0"
2812
+
},
2813
+
"funding": {
2814
+
"url": "https://opencollective.com/vitest"
2815
+
}
2816
+
},
2817
+
"node_modules/@vitest/runner": {
2818
+
"version": "3.2.4",
2819
+
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.4.tgz",
2820
+
"integrity": "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==",
2821
+
"dev": true,
2822
+
"license": "MIT",
2823
+
"dependencies": {
2824
+
"@vitest/utils": "3.2.4",
2825
+
"pathe": "^2.0.3",
2826
+
"strip-literal": "^3.0.0"
2827
+
},
2828
+
"funding": {
2829
+
"url": "https://opencollective.com/vitest"
2830
+
}
2831
+
},
2832
+
"node_modules/@vitest/snapshot": {
2833
+
"version": "3.2.4",
2834
+
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.4.tgz",
2835
+
"integrity": "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==",
2836
+
"dev": true,
2837
+
"license": "MIT",
2838
+
"dependencies": {
2839
+
"@vitest/pretty-format": "3.2.4",
2840
+
"magic-string": "^0.30.17",
2841
+
"pathe": "^2.0.3"
2842
+
},
2843
+
"funding": {
2844
+
"url": "https://opencollective.com/vitest"
2845
+
}
2846
+
},
2847
+
"node_modules/@vitest/spy": {
2848
+
"version": "3.2.4",
2849
+
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz",
2850
+
"integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==",
2851
+
"dev": true,
2852
+
"license": "MIT",
2853
+
"dependencies": {
2854
+
"tinyspy": "^4.0.3"
2855
+
},
2856
+
"funding": {
2857
+
"url": "https://opencollective.com/vitest"
2858
+
}
2859
+
},
2860
+
"node_modules/@vitest/utils": {
2861
+
"version": "3.2.4",
2862
+
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz",
2863
+
"integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==",
2864
+
"dev": true,
2865
+
"license": "MIT",
2866
+
"dependencies": {
2867
+
"@vitest/pretty-format": "3.2.4",
2868
+
"loupe": "^3.1.4",
2869
+
"tinyrainbow": "^2.0.0"
2870
+
},
2871
+
"funding": {
2872
+
"url": "https://opencollective.com/vitest"
2873
+
}
2874
+
},
2875
+
"node_modules/acorn": {
2876
+
"version": "8.15.0",
2877
+
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
2878
+
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
2879
+
"license": "MIT",
2880
+
"bin": {
2881
+
"acorn": "bin/acorn"
2882
+
},
2883
+
"engines": {
2884
+
"node": ">=0.4.0"
2885
+
}
2886
+
},
2887
+
"node_modules/agent-base": {
2888
+
"version": "7.1.4",
2889
+
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
2890
+
"integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==",
2891
+
"dev": true,
2892
+
"license": "MIT",
2893
+
"engines": {
2894
+
"node": ">= 14"
2895
+
}
2896
+
},
2897
+
"node_modules/ansi-regex": {
2898
+
"version": "5.0.1",
2899
+
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
2900
+
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
2901
+
"dev": true,
2902
+
"license": "MIT",
2903
+
"engines": {
2904
+
"node": ">=8"
2905
+
}
2906
+
},
2907
+
"node_modules/ansi-styles": {
2908
+
"version": "5.2.0",
2909
+
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
2910
+
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
2911
+
"dev": true,
2912
+
"license": "MIT",
2913
+
"engines": {
2914
+
"node": ">=10"
2915
+
},
2916
+
"funding": {
2917
+
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
2918
+
}
2919
+
},
2920
+
"node_modules/ansis": {
2921
+
"version": "4.1.0",
2922
+
"resolved": "https://registry.npmjs.org/ansis/-/ansis-4.1.0.tgz",
2923
+
"integrity": "sha512-BGcItUBWSMRgOCe+SVZJ+S7yTRG0eGt9cXAHev72yuGcY23hnLA7Bky5L/xLyPINoSN95geovfBkqoTlNZYa7w==",
2924
+
"license": "ISC",
2925
+
"engines": {
2926
+
"node": ">=14"
2927
+
}
2928
+
},
2929
+
"node_modules/anymatch": {
2930
+
"version": "3.1.3",
2931
+
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
2932
+
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
2933
+
"license": "ISC",
2934
+
"dependencies": {
2935
+
"normalize-path": "^3.0.0",
2936
+
"picomatch": "^2.0.4"
2937
+
},
2938
+
"engines": {
2939
+
"node": ">= 8"
2940
+
}
2941
+
},
2942
+
"node_modules/aria-hidden": {
2943
+
"version": "1.2.6",
2944
+
"resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz",
2945
+
"integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==",
2946
+
"license": "MIT",
2947
+
"dependencies": {
2948
+
"tslib": "^2.0.0"
2949
+
},
2950
+
"engines": {
2951
+
"node": ">=10"
2952
+
}
2953
+
},
2954
+
"node_modules/aria-query": {
2955
+
"version": "5.3.0",
2956
+
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
2957
+
"integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
2958
+
"dev": true,
2959
+
"license": "Apache-2.0",
2960
+
"dependencies": {
2961
+
"dequal": "^2.0.3"
2962
+
}
2963
+
},
2964
+
"node_modules/assertion-error": {
2965
+
"version": "2.0.1",
2966
+
"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz",
2967
+
"integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==",
2968
+
"dev": true,
2969
+
"license": "MIT",
2970
+
"engines": {
2971
+
"node": ">=12"
2972
+
}
2973
+
},
2974
+
"node_modules/ast-types": {
2975
+
"version": "0.16.1",
2976
+
"resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz",
2977
+
"integrity": "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==",
2978
+
"license": "MIT",
2979
+
"dependencies": {
2980
+
"tslib": "^2.0.1"
2981
+
},
2982
+
"engines": {
2983
+
"node": ">=4"
2984
+
}
2985
+
},
2986
+
"node_modules/await-lock": {
2987
+
"version": "2.2.2",
2988
+
"resolved": "https://registry.npmjs.org/await-lock/-/await-lock-2.2.2.tgz",
2989
+
"integrity": "sha512-aDczADvlvTGajTDjcjpJMqRkOF6Qdz3YbPZm/PyW6tKPkx2hlYBzxMhEywM/tU72HrVZjgl5VCdRuMlA7pZ8Gw==",
2990
+
"license": "MIT"
2991
+
},
2992
+
"node_modules/babel-dead-code-elimination": {
2993
+
"version": "1.0.10",
2994
+
"resolved": "https://registry.npmjs.org/babel-dead-code-elimination/-/babel-dead-code-elimination-1.0.10.tgz",
2995
+
"integrity": "sha512-DV5bdJZTzZ0zn0DC24v3jD7Mnidh6xhKa4GfKCbq3sfW8kaWhDdZjP3i81geA8T33tdYqWKw4D3fVv0CwEgKVA==",
2996
+
"license": "MIT",
2997
+
"dependencies": {
2998
+
"@babel/core": "^7.23.7",
2999
+
"@babel/parser": "^7.23.6",
3000
+
"@babel/traverse": "^7.23.7",
3001
+
"@babel/types": "^7.23.6"
3002
+
}
3003
+
},
3004
+
"node_modules/binary-extensions": {
3005
+
"version": "2.3.0",
3006
+
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
3007
+
"integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
3008
+
"license": "MIT",
3009
+
"engines": {
3010
+
"node": ">=8"
3011
+
},
3012
+
"funding": {
3013
+
"url": "https://github.com/sponsors/sindresorhus"
3014
+
}
3015
+
},
3016
+
"node_modules/braces": {
3017
+
"version": "3.0.3",
3018
+
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
3019
+
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
3020
+
"license": "MIT",
3021
+
"dependencies": {
3022
+
"fill-range": "^7.1.1"
3023
+
},
3024
+
"engines": {
3025
+
"node": ">=8"
3026
+
}
3027
+
},
3028
+
"node_modules/browserslist": {
3029
+
"version": "4.25.1",
3030
+
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz",
3031
+
"integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==",
3032
+
"funding": [
3033
+
{
3034
+
"type": "opencollective",
3035
+
"url": "https://opencollective.com/browserslist"
3036
+
},
3037
+
{
3038
+
"type": "tidelift",
3039
+
"url": "https://tidelift.com/funding/github/npm/browserslist"
3040
+
},
3041
+
{
3042
+
"type": "github",
3043
+
"url": "https://github.com/sponsors/ai"
3044
+
}
3045
+
],
3046
+
"license": "MIT",
3047
+
"dependencies": {
3048
+
"caniuse-lite": "^1.0.30001726",
3049
+
"electron-to-chromium": "^1.5.173",
3050
+
"node-releases": "^2.0.19",
3051
+
"update-browserslist-db": "^1.1.3"
3052
+
},
3053
+
"bin": {
3054
+
"browserslist": "cli.js"
3055
+
},
3056
+
"engines": {
3057
+
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
3058
+
}
3059
+
},
3060
+
"node_modules/cac": {
3061
+
"version": "6.7.14",
3062
+
"resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
3063
+
"integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==",
3064
+
"dev": true,
3065
+
"license": "MIT",
3066
+
"engines": {
3067
+
"node": ">=8"
3068
+
}
3069
+
},
3070
+
"node_modules/caniuse-lite": {
3071
+
"version": "1.0.30001731",
3072
+
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001731.tgz",
3073
+
"integrity": "sha512-lDdp2/wrOmTRWuoB5DpfNkC0rJDU8DqRa6nYL6HK6sytw70QMopt/NIc/9SM7ylItlBWfACXk0tEn37UWM/+mg==",
3074
+
"funding": [
3075
+
{
3076
+
"type": "opencollective",
3077
+
"url": "https://opencollective.com/browserslist"
3078
+
},
3079
+
{
3080
+
"type": "tidelift",
3081
+
"url": "https://tidelift.com/funding/github/npm/caniuse-lite"
3082
+
},
3083
+
{
3084
+
"type": "github",
3085
+
"url": "https://github.com/sponsors/ai"
3086
+
}
3087
+
],
3088
+
"license": "CC-BY-4.0"
3089
+
},
3090
+
"node_modules/chai": {
3091
+
"version": "5.2.1",
3092
+
"resolved": "https://registry.npmjs.org/chai/-/chai-5.2.1.tgz",
3093
+
"integrity": "sha512-5nFxhUrX0PqtyogoYOA8IPswy5sZFTOsBFl/9bNsmDLgsxYTzSZQJDPppDnZPTQbzSEm0hqGjWPzRemQCYbD6A==",
3094
+
"dev": true,
3095
+
"license": "MIT",
3096
+
"dependencies": {
3097
+
"assertion-error": "^2.0.1",
3098
+
"check-error": "^2.1.1",
3099
+
"deep-eql": "^5.0.1",
3100
+
"loupe": "^3.1.0",
3101
+
"pathval": "^2.0.0"
3102
+
},
3103
+
"engines": {
3104
+
"node": ">=18"
3105
+
}
3106
+
},
3107
+
"node_modules/check-error": {
3108
+
"version": "2.1.1",
3109
+
"resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz",
3110
+
"integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==",
3111
+
"dev": true,
3112
+
"license": "MIT",
3113
+
"engines": {
3114
+
"node": ">= 16"
3115
+
}
3116
+
},
3117
+
"node_modules/chokidar": {
3118
+
"version": "3.6.0",
3119
+
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
3120
+
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
3121
+
"license": "MIT",
3122
+
"dependencies": {
3123
+
"anymatch": "~3.1.2",
3124
+
"braces": "~3.0.2",
3125
+
"glob-parent": "~5.1.2",
3126
+
"is-binary-path": "~2.1.0",
3127
+
"is-glob": "~4.0.1",
3128
+
"normalize-path": "~3.0.0",
3129
+
"readdirp": "~3.6.0"
3130
+
},
3131
+
"engines": {
3132
+
"node": ">= 8.10.0"
3133
+
},
3134
+
"funding": {
3135
+
"url": "https://paulmillr.com/funding/"
3136
+
},
3137
+
"optionalDependencies": {
3138
+
"fsevents": "~2.3.2"
3139
+
}
3140
+
},
3141
+
"node_modules/chownr": {
3142
+
"version": "3.0.0",
3143
+
"resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz",
3144
+
"integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==",
3145
+
"license": "BlueOak-1.0.0",
3146
+
"engines": {
3147
+
"node": ">=18"
3148
+
}
3149
+
},
3150
+
"node_modules/clsx": {
3151
+
"version": "2.1.1",
3152
+
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
3153
+
"integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
3154
+
"license": "MIT",
3155
+
"engines": {
3156
+
"node": ">=6"
3157
+
}
3158
+
},
3159
+
"node_modules/convert-source-map": {
3160
+
"version": "2.0.0",
3161
+
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
3162
+
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
3163
+
"license": "MIT"
3164
+
},
3165
+
"node_modules/cookie-es": {
3166
+
"version": "1.2.2",
3167
+
"resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-1.2.2.tgz",
3168
+
"integrity": "sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==",
3169
+
"license": "MIT"
3170
+
},
3171
+
"node_modules/cssstyle": {
3172
+
"version": "4.6.0",
3173
+
"resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.6.0.tgz",
3174
+
"integrity": "sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==",
3175
+
"dev": true,
3176
+
"license": "MIT",
3177
+
"dependencies": {
3178
+
"@asamuzakjp/css-color": "^3.2.0",
3179
+
"rrweb-cssom": "^0.8.0"
3180
+
},
3181
+
"engines": {
3182
+
"node": ">=18"
3183
+
}
3184
+
},
3185
+
"node_modules/csstype": {
3186
+
"version": "3.1.3",
3187
+
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
3188
+
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
3189
+
"license": "MIT"
3190
+
},
3191
+
"node_modules/data-urls": {
3192
+
"version": "5.0.0",
3193
+
"resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz",
3194
+
"integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==",
3195
+
"dev": true,
3196
+
"license": "MIT",
3197
+
"dependencies": {
3198
+
"whatwg-mimetype": "^4.0.0",
3199
+
"whatwg-url": "^14.0.0"
3200
+
},
3201
+
"engines": {
3202
+
"node": ">=18"
3203
+
}
3204
+
},
3205
+
"node_modules/debug": {
3206
+
"version": "4.4.1",
3207
+
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
3208
+
"integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
3209
+
"license": "MIT",
3210
+
"dependencies": {
3211
+
"ms": "^2.1.3"
3212
+
},
3213
+
"engines": {
3214
+
"node": ">=6.0"
3215
+
},
3216
+
"peerDependenciesMeta": {
3217
+
"supports-color": {
3218
+
"optional": true
3219
+
}
3220
+
}
3221
+
},
3222
+
"node_modules/decimal.js": {
3223
+
"version": "10.6.0",
3224
+
"resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz",
3225
+
"integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==",
3226
+
"dev": true,
3227
+
"license": "MIT"
3228
+
},
3229
+
"node_modules/deep-eql": {
3230
+
"version": "5.0.2",
3231
+
"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz",
3232
+
"integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==",
3233
+
"dev": true,
3234
+
"license": "MIT",
3235
+
"engines": {
3236
+
"node": ">=6"
3237
+
}
3238
+
},
3239
+
"node_modules/dequal": {
3240
+
"version": "2.0.3",
3241
+
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
3242
+
"integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
3243
+
"dev": true,
3244
+
"license": "MIT",
3245
+
"engines": {
3246
+
"node": ">=6"
3247
+
}
3248
+
},
3249
+
"node_modules/detect-libc": {
3250
+
"version": "2.0.4",
3251
+
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz",
3252
+
"integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==",
3253
+
"license": "Apache-2.0",
3254
+
"engines": {
3255
+
"node": ">=8"
3256
+
}
3257
+
},
3258
+
"node_modules/detect-node-es": {
3259
+
"version": "1.1.0",
3260
+
"resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
3261
+
"integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==",
3262
+
"license": "MIT"
3263
+
},
3264
+
"node_modules/diff": {
3265
+
"version": "8.0.2",
3266
+
"resolved": "https://registry.npmjs.org/diff/-/diff-8.0.2.tgz",
3267
+
"integrity": "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==",
3268
+
"license": "BSD-3-Clause",
3269
+
"engines": {
3270
+
"node": ">=0.3.1"
3271
+
}
3272
+
},
3273
+
"node_modules/dom-accessibility-api": {
3274
+
"version": "0.5.16",
3275
+
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
3276
+
"integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
3277
+
"dev": true,
3278
+
"license": "MIT"
3279
+
},
3280
+
"node_modules/electron-to-chromium": {
3281
+
"version": "1.5.194",
3282
+
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.194.tgz",
3283
+
"integrity": "sha512-SdnWJwSUot04UR51I2oPD8kuP2VI37/CADR1OHsFOUzZIvfWJBO6q11k5P/uKNyTT3cdOsnyjkrZ+DDShqYqJA==",
3284
+
"license": "ISC"
3285
+
},
3286
+
"node_modules/enhanced-resolve": {
3287
+
"version": "5.18.2",
3288
+
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.2.tgz",
3289
+
"integrity": "sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ==",
3290
+
"license": "MIT",
3291
+
"dependencies": {
3292
+
"graceful-fs": "^4.2.4",
3293
+
"tapable": "^2.2.0"
3294
+
},
3295
+
"engines": {
3296
+
"node": ">=10.13.0"
3297
+
}
3298
+
},
3299
+
"node_modules/entities": {
3300
+
"version": "6.0.1",
3301
+
"resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz",
3302
+
"integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==",
3303
+
"dev": true,
3304
+
"license": "BSD-2-Clause",
3305
+
"engines": {
3306
+
"node": ">=0.12"
3307
+
},
3308
+
"funding": {
3309
+
"url": "https://github.com/fb55/entities?sponsor=1"
3310
+
}
3311
+
},
3312
+
"node_modules/es-module-lexer": {
3313
+
"version": "1.7.0",
3314
+
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz",
3315
+
"integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==",
3316
+
"dev": true,
3317
+
"license": "MIT"
3318
+
},
3319
+
"node_modules/esbuild": {
3320
+
"version": "0.25.8",
3321
+
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.8.tgz",
3322
+
"integrity": "sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q==",
3323
+
"hasInstallScript": true,
3324
+
"license": "MIT",
3325
+
"bin": {
3326
+
"esbuild": "bin/esbuild"
3327
+
},
3328
+
"engines": {
3329
+
"node": ">=18"
3330
+
},
3331
+
"optionalDependencies": {
3332
+
"@esbuild/aix-ppc64": "0.25.8",
3333
+
"@esbuild/android-arm": "0.25.8",
3334
+
"@esbuild/android-arm64": "0.25.8",
3335
+
"@esbuild/android-x64": "0.25.8",
3336
+
"@esbuild/darwin-arm64": "0.25.8",
3337
+
"@esbuild/darwin-x64": "0.25.8",
3338
+
"@esbuild/freebsd-arm64": "0.25.8",
3339
+
"@esbuild/freebsd-x64": "0.25.8",
3340
+
"@esbuild/linux-arm": "0.25.8",
3341
+
"@esbuild/linux-arm64": "0.25.8",
3342
+
"@esbuild/linux-ia32": "0.25.8",
3343
+
"@esbuild/linux-loong64": "0.25.8",
3344
+
"@esbuild/linux-mips64el": "0.25.8",
3345
+
"@esbuild/linux-ppc64": "0.25.8",
3346
+
"@esbuild/linux-riscv64": "0.25.8",
3347
+
"@esbuild/linux-s390x": "0.25.8",
3348
+
"@esbuild/linux-x64": "0.25.8",
3349
+
"@esbuild/netbsd-arm64": "0.25.8",
3350
+
"@esbuild/netbsd-x64": "0.25.8",
3351
+
"@esbuild/openbsd-arm64": "0.25.8",
3352
+
"@esbuild/openbsd-x64": "0.25.8",
3353
+
"@esbuild/openharmony-arm64": "0.25.8",
3354
+
"@esbuild/sunos-x64": "0.25.8",
3355
+
"@esbuild/win32-arm64": "0.25.8",
3356
+
"@esbuild/win32-ia32": "0.25.8",
3357
+
"@esbuild/win32-x64": "0.25.8"
3358
+
}
3359
+
},
3360
+
"node_modules/escalade": {
3361
+
"version": "3.2.0",
3362
+
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
3363
+
"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
3364
+
"license": "MIT",
3365
+
"engines": {
3366
+
"node": ">=6"
3367
+
}
3368
+
},
3369
+
"node_modules/esprima": {
3370
+
"version": "4.0.1",
3371
+
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
3372
+
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
3373
+
"license": "BSD-2-Clause",
3374
+
"bin": {
3375
+
"esparse": "bin/esparse.js",
3376
+
"esvalidate": "bin/esvalidate.js"
3377
+
},
3378
+
"engines": {
3379
+
"node": ">=4"
3380
+
}
3381
+
},
3382
+
"node_modules/estree-walker": {
3383
+
"version": "3.0.3",
3384
+
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
3385
+
"integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
3386
+
"dev": true,
3387
+
"license": "MIT",
3388
+
"dependencies": {
3389
+
"@types/estree": "^1.0.0"
3390
+
}
3391
+
},
3392
+
"node_modules/expect-type": {
3393
+
"version": "1.2.2",
3394
+
"resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz",
3395
+
"integrity": "sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==",
3396
+
"dev": true,
3397
+
"license": "Apache-2.0",
3398
+
"engines": {
3399
+
"node": ">=12.0.0"
3400
+
}
3401
+
},
3402
+
"node_modules/fill-range": {
3403
+
"version": "7.1.1",
3404
+
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
3405
+
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
3406
+
"license": "MIT",
3407
+
"dependencies": {
3408
+
"to-regex-range": "^5.0.1"
3409
+
},
3410
+
"engines": {
3411
+
"node": ">=8"
3412
+
}
3413
+
},
3414
+
"node_modules/fsevents": {
3415
+
"version": "2.3.3",
3416
+
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
3417
+
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
3418
+
"hasInstallScript": true,
3419
+
"license": "MIT",
3420
+
"optional": true,
3421
+
"os": [
3422
+
"darwin"
3423
+
],
3424
+
"engines": {
3425
+
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
3426
+
}
3427
+
},
3428
+
"node_modules/gensync": {
3429
+
"version": "1.0.0-beta.2",
3430
+
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
3431
+
"integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
3432
+
"license": "MIT",
3433
+
"engines": {
3434
+
"node": ">=6.9.0"
3435
+
}
3436
+
},
3437
+
"node_modules/get-nonce": {
3438
+
"version": "1.0.1",
3439
+
"resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz",
3440
+
"integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==",
3441
+
"license": "MIT",
3442
+
"engines": {
3443
+
"node": ">=6"
3444
+
}
3445
+
},
3446
+
"node_modules/get-tsconfig": {
3447
+
"version": "4.10.1",
3448
+
"resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz",
3449
+
"integrity": "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==",
3450
+
"license": "MIT",
3451
+
"dependencies": {
3452
+
"resolve-pkg-maps": "^1.0.0"
3453
+
},
3454
+
"funding": {
3455
+
"url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
3456
+
}
3457
+
},
3458
+
"node_modules/glob-parent": {
3459
+
"version": "5.1.2",
3460
+
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
3461
+
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
3462
+
"license": "ISC",
3463
+
"dependencies": {
3464
+
"is-glob": "^4.0.1"
3465
+
},
3466
+
"engines": {
3467
+
"node": ">= 6"
3468
+
}
3469
+
},
3470
+
"node_modules/goober": {
3471
+
"version": "2.1.16",
3472
+
"resolved": "https://registry.npmjs.org/goober/-/goober-2.1.16.tgz",
3473
+
"integrity": "sha512-erjk19y1U33+XAMe1VTvIONHYoSqE4iS7BYUZfHaqeohLmnC0FdxEh7rQU+6MZ4OajItzjZFSRtVANrQwNq6/g==",
3474
+
"license": "MIT",
3475
+
"peerDependencies": {
3476
+
"csstype": "^3.0.10"
3477
+
}
3478
+
},
3479
+
"node_modules/graceful-fs": {
3480
+
"version": "4.2.11",
3481
+
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
3482
+
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
3483
+
"license": "ISC"
3484
+
},
3485
+
"node_modules/graphemer": {
3486
+
"version": "1.4.0",
3487
+
"resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
3488
+
"integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
3489
+
"license": "MIT"
3490
+
},
3491
+
"node_modules/html-encoding-sniffer": {
3492
+
"version": "4.0.0",
3493
+
"resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz",
3494
+
"integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==",
3495
+
"dev": true,
3496
+
"license": "MIT",
3497
+
"dependencies": {
3498
+
"whatwg-encoding": "^3.1.1"
3499
+
},
3500
+
"engines": {
3501
+
"node": ">=18"
3502
+
}
3503
+
},
3504
+
"node_modules/http-proxy-agent": {
3505
+
"version": "7.0.2",
3506
+
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
3507
+
"integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
3508
+
"dev": true,
3509
+
"license": "MIT",
3510
+
"dependencies": {
3511
+
"agent-base": "^7.1.0",
3512
+
"debug": "^4.3.4"
3513
+
},
3514
+
"engines": {
3515
+
"node": ">= 14"
3516
+
}
3517
+
},
3518
+
"node_modules/https-proxy-agent": {
3519
+
"version": "7.0.6",
3520
+
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
3521
+
"integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
3522
+
"dev": true,
3523
+
"license": "MIT",
3524
+
"dependencies": {
3525
+
"agent-base": "^7.1.2",
3526
+
"debug": "4"
3527
+
},
3528
+
"engines": {
3529
+
"node": ">= 14"
3530
+
}
3531
+
},
3532
+
"node_modules/iconv-lite": {
3533
+
"version": "0.6.3",
3534
+
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
3535
+
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
3536
+
"dev": true,
3537
+
"license": "MIT",
3538
+
"dependencies": {
3539
+
"safer-buffer": ">= 2.1.2 < 3.0.0"
3540
+
},
3541
+
"engines": {
3542
+
"node": ">=0.10.0"
3543
+
}
3544
+
},
3545
+
"node_modules/idb-keyval": {
3546
+
"version": "6.2.2",
3547
+
"resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.2.tgz",
3548
+
"integrity": "sha512-yjD9nARJ/jb1g+CvD0tlhUHOrJ9Sy0P8T9MF3YaLlHnSRpwPfpTX0XIvpmw3gAJUmEu3FiICLBDPXVwyEvrleg==",
3549
+
"license": "Apache-2.0"
3550
+
},
3551
+
"node_modules/is-binary-path": {
3552
+
"version": "2.1.0",
3553
+
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
3554
+
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
3555
+
"license": "MIT",
3556
+
"dependencies": {
3557
+
"binary-extensions": "^2.0.0"
3558
+
},
3559
+
"engines": {
3560
+
"node": ">=8"
3561
+
}
3562
+
},
3563
+
"node_modules/is-extglob": {
3564
+
"version": "2.1.1",
3565
+
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
3566
+
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
3567
+
"license": "MIT",
3568
+
"engines": {
3569
+
"node": ">=0.10.0"
3570
+
}
3571
+
},
3572
+
"node_modules/is-glob": {
3573
+
"version": "4.0.3",
3574
+
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
3575
+
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
3576
+
"license": "MIT",
3577
+
"dependencies": {
3578
+
"is-extglob": "^2.1.1"
3579
+
},
3580
+
"engines": {
3581
+
"node": ">=0.10.0"
3582
+
}
3583
+
},
3584
+
"node_modules/is-number": {
3585
+
"version": "7.0.0",
3586
+
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
3587
+
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
3588
+
"license": "MIT",
3589
+
"engines": {
3590
+
"node": ">=0.12.0"
3591
+
}
3592
+
},
3593
+
"node_modules/is-potential-custom-element-name": {
3594
+
"version": "1.0.1",
3595
+
"resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
3596
+
"integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==",
3597
+
"dev": true,
3598
+
"license": "MIT"
3599
+
},
3600
+
"node_modules/isbot": {
3601
+
"version": "5.1.29",
3602
+
"resolved": "https://registry.npmjs.org/isbot/-/isbot-5.1.29.tgz",
3603
+
"integrity": "sha512-DelDWWoa3mBoyWTq3wjp+GIWx/yZdN7zLUE7NFhKjAiJ+uJVRkbLlwykdduCE4sPUUy8mlTYTmdhBUYu91F+sw==",
3604
+
"license": "Unlicense",
3605
+
"engines": {
3606
+
"node": ">=18"
3607
+
}
3608
+
},
3609
+
"node_modules/iso-datestring-validator": {
3610
+
"version": "2.2.2",
3611
+
"resolved": "https://registry.npmjs.org/iso-datestring-validator/-/iso-datestring-validator-2.2.2.tgz",
3612
+
"integrity": "sha512-yLEMkBbLZTlVQqOnQ4FiMujR6T4DEcCb1xizmvXS+OxuhwcbtynoosRzdMA69zZCShCNAbi+gJ71FxZBBXx1SA==",
3613
+
"license": "MIT"
3614
+
},
3615
+
"node_modules/jiti": {
3616
+
"version": "2.5.1",
3617
+
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz",
3618
+
"integrity": "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==",
3619
+
"license": "MIT",
3620
+
"bin": {
3621
+
"jiti": "lib/jiti-cli.mjs"
3622
+
}
3623
+
},
3624
+
"node_modules/js-tokens": {
3625
+
"version": "4.0.0",
3626
+
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
3627
+
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
3628
+
"license": "MIT"
3629
+
},
3630
+
"node_modules/jsdom": {
3631
+
"version": "26.1.0",
3632
+
"resolved": "https://registry.npmjs.org/jsdom/-/jsdom-26.1.0.tgz",
3633
+
"integrity": "sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==",
3634
+
"dev": true,
3635
+
"license": "MIT",
3636
+
"dependencies": {
3637
+
"cssstyle": "^4.2.1",
3638
+
"data-urls": "^5.0.0",
3639
+
"decimal.js": "^10.5.0",
3640
+
"html-encoding-sniffer": "^4.0.0",
3641
+
"http-proxy-agent": "^7.0.2",
3642
+
"https-proxy-agent": "^7.0.6",
3643
+
"is-potential-custom-element-name": "^1.0.1",
3644
+
"nwsapi": "^2.2.16",
3645
+
"parse5": "^7.2.1",
3646
+
"rrweb-cssom": "^0.8.0",
3647
+
"saxes": "^6.0.0",
3648
+
"symbol-tree": "^3.2.4",
3649
+
"tough-cookie": "^5.1.1",
3650
+
"w3c-xmlserializer": "^5.0.0",
3651
+
"webidl-conversions": "^7.0.0",
3652
+
"whatwg-encoding": "^3.1.1",
3653
+
"whatwg-mimetype": "^4.0.0",
3654
+
"whatwg-url": "^14.1.1",
3655
+
"ws": "^8.18.0",
3656
+
"xml-name-validator": "^5.0.0"
3657
+
},
3658
+
"engines": {
3659
+
"node": ">=18"
3660
+
},
3661
+
"peerDependencies": {
3662
+
"canvas": "^3.0.0"
3663
+
},
3664
+
"peerDependenciesMeta": {
3665
+
"canvas": {
3666
+
"optional": true
3667
+
}
3668
+
}
3669
+
},
3670
+
"node_modules/jsesc": {
3671
+
"version": "3.1.0",
3672
+
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
3673
+
"integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
3674
+
"license": "MIT",
3675
+
"bin": {
3676
+
"jsesc": "bin/jsesc"
3677
+
},
3678
+
"engines": {
3679
+
"node": ">=6"
3680
+
}
3681
+
},
3682
+
"node_modules/json5": {
3683
+
"version": "2.2.3",
3684
+
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
3685
+
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
3686
+
"license": "MIT",
3687
+
"bin": {
3688
+
"json5": "lib/cli.js"
3689
+
},
3690
+
"engines": {
3691
+
"node": ">=6"
3692
+
}
3693
+
},
3694
+
"node_modules/lightningcss": {
3695
+
"version": "1.30.1",
3696
+
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz",
3697
+
"integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==",
3698
+
"license": "MPL-2.0",
3699
+
"dependencies": {
3700
+
"detect-libc": "^2.0.3"
3701
+
},
3702
+
"engines": {
3703
+
"node": ">= 12.0.0"
3704
+
},
3705
+
"funding": {
3706
+
"type": "opencollective",
3707
+
"url": "https://opencollective.com/parcel"
3708
+
},
3709
+
"optionalDependencies": {
3710
+
"lightningcss-darwin-arm64": "1.30.1",
3711
+
"lightningcss-darwin-x64": "1.30.1",
3712
+
"lightningcss-freebsd-x64": "1.30.1",
3713
+
"lightningcss-linux-arm-gnueabihf": "1.30.1",
3714
+
"lightningcss-linux-arm64-gnu": "1.30.1",
3715
+
"lightningcss-linux-arm64-musl": "1.30.1",
3716
+
"lightningcss-linux-x64-gnu": "1.30.1",
3717
+
"lightningcss-linux-x64-musl": "1.30.1",
3718
+
"lightningcss-win32-arm64-msvc": "1.30.1",
3719
+
"lightningcss-win32-x64-msvc": "1.30.1"
3720
+
}
3721
+
},
3722
+
"node_modules/lightningcss-darwin-arm64": {
3723
+
"version": "1.30.1",
3724
+
"resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz",
3725
+
"integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==",
3726
+
"cpu": [
3727
+
"arm64"
3728
+
],
3729
+
"license": "MPL-2.0",
3730
+
"optional": true,
3731
+
"os": [
3732
+
"darwin"
3733
+
],
3734
+
"engines": {
3735
+
"node": ">= 12.0.0"
3736
+
},
3737
+
"funding": {
3738
+
"type": "opencollective",
3739
+
"url": "https://opencollective.com/parcel"
3740
+
}
3741
+
},
3742
+
"node_modules/lightningcss-darwin-x64": {
3743
+
"version": "1.30.1",
3744
+
"resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz",
3745
+
"integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==",
3746
+
"cpu": [
3747
+
"x64"
3748
+
],
3749
+
"license": "MPL-2.0",
3750
+
"optional": true,
3751
+
"os": [
3752
+
"darwin"
3753
+
],
3754
+
"engines": {
3755
+
"node": ">= 12.0.0"
3756
+
},
3757
+
"funding": {
3758
+
"type": "opencollective",
3759
+
"url": "https://opencollective.com/parcel"
3760
+
}
3761
+
},
3762
+
"node_modules/lightningcss-freebsd-x64": {
3763
+
"version": "1.30.1",
3764
+
"resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz",
3765
+
"integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==",
3766
+
"cpu": [
3767
+
"x64"
3768
+
],
3769
+
"license": "MPL-2.0",
3770
+
"optional": true,
3771
+
"os": [
3772
+
"freebsd"
3773
+
],
3774
+
"engines": {
3775
+
"node": ">= 12.0.0"
3776
+
},
3777
+
"funding": {
3778
+
"type": "opencollective",
3779
+
"url": "https://opencollective.com/parcel"
3780
+
}
3781
+
},
3782
+
"node_modules/lightningcss-linux-arm-gnueabihf": {
3783
+
"version": "1.30.1",
3784
+
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz",
3785
+
"integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==",
3786
+
"cpu": [
3787
+
"arm"
3788
+
],
3789
+
"license": "MPL-2.0",
3790
+
"optional": true,
3791
+
"os": [
3792
+
"linux"
3793
+
],
3794
+
"engines": {
3795
+
"node": ">= 12.0.0"
3796
+
},
3797
+
"funding": {
3798
+
"type": "opencollective",
3799
+
"url": "https://opencollective.com/parcel"
3800
+
}
3801
+
},
3802
+
"node_modules/lightningcss-linux-arm64-gnu": {
3803
+
"version": "1.30.1",
3804
+
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz",
3805
+
"integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==",
3806
+
"cpu": [
3807
+
"arm64"
3808
+
],
3809
+
"license": "MPL-2.0",
3810
+
"optional": true,
3811
+
"os": [
3812
+
"linux"
3813
+
],
3814
+
"engines": {
3815
+
"node": ">= 12.0.0"
3816
+
},
3817
+
"funding": {
3818
+
"type": "opencollective",
3819
+
"url": "https://opencollective.com/parcel"
3820
+
}
3821
+
},
3822
+
"node_modules/lightningcss-linux-arm64-musl": {
3823
+
"version": "1.30.1",
3824
+
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz",
3825
+
"integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==",
3826
+
"cpu": [
3827
+
"arm64"
3828
+
],
3829
+
"license": "MPL-2.0",
3830
+
"optional": true,
3831
+
"os": [
3832
+
"linux"
3833
+
],
3834
+
"engines": {
3835
+
"node": ">= 12.0.0"
3836
+
},
3837
+
"funding": {
3838
+
"type": "opencollective",
3839
+
"url": "https://opencollective.com/parcel"
3840
+
}
3841
+
},
3842
+
"node_modules/lightningcss-linux-x64-gnu": {
3843
+
"version": "1.30.1",
3844
+
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz",
3845
+
"integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==",
3846
+
"cpu": [
3847
+
"x64"
3848
+
],
3849
+
"license": "MPL-2.0",
3850
+
"optional": true,
3851
+
"os": [
3852
+
"linux"
3853
+
],
3854
+
"engines": {
3855
+
"node": ">= 12.0.0"
3856
+
},
3857
+
"funding": {
3858
+
"type": "opencollective",
3859
+
"url": "https://opencollective.com/parcel"
3860
+
}
3861
+
},
3862
+
"node_modules/lightningcss-linux-x64-musl": {
3863
+
"version": "1.30.1",
3864
+
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz",
3865
+
"integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==",
3866
+
"cpu": [
3867
+
"x64"
3868
+
],
3869
+
"license": "MPL-2.0",
3870
+
"optional": true,
3871
+
"os": [
3872
+
"linux"
3873
+
],
3874
+
"engines": {
3875
+
"node": ">= 12.0.0"
3876
+
},
3877
+
"funding": {
3878
+
"type": "opencollective",
3879
+
"url": "https://opencollective.com/parcel"
3880
+
}
3881
+
},
3882
+
"node_modules/lightningcss-win32-arm64-msvc": {
3883
+
"version": "1.30.1",
3884
+
"resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz",
3885
+
"integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==",
3886
+
"cpu": [
3887
+
"arm64"
3888
+
],
3889
+
"license": "MPL-2.0",
3890
+
"optional": true,
3891
+
"os": [
3892
+
"win32"
3893
+
],
3894
+
"engines": {
3895
+
"node": ">= 12.0.0"
3896
+
},
3897
+
"funding": {
3898
+
"type": "opencollective",
3899
+
"url": "https://opencollective.com/parcel"
3900
+
}
3901
+
},
3902
+
"node_modules/lightningcss-win32-x64-msvc": {
3903
+
"version": "1.30.1",
3904
+
"resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz",
3905
+
"integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==",
3906
+
"cpu": [
3907
+
"x64"
3908
+
],
3909
+
"license": "MPL-2.0",
3910
+
"optional": true,
3911
+
"os": [
3912
+
"win32"
3913
+
],
3914
+
"engines": {
3915
+
"node": ">= 12.0.0"
3916
+
},
3917
+
"funding": {
3918
+
"type": "opencollective",
3919
+
"url": "https://opencollective.com/parcel"
3920
+
}
3921
+
},
3922
+
"node_modules/loupe": {
3923
+
"version": "3.2.0",
3924
+
"resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.0.tgz",
3925
+
"integrity": "sha512-2NCfZcT5VGVNX9mSZIxLRkEAegDGBpuQZBy13desuHeVORmBDyAET4TkJr4SjqQy3A8JDofMN6LpkK8Xcm/dlw==",
3926
+
"dev": true,
3927
+
"license": "MIT"
3928
+
},
3929
+
"node_modules/lru-cache": {
3930
+
"version": "5.1.1",
3931
+
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
3932
+
"integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
3933
+
"license": "ISC",
3934
+
"dependencies": {
3935
+
"yallist": "^3.0.2"
3936
+
}
3937
+
},
3938
+
"node_modules/lz-string": {
3939
+
"version": "1.5.0",
3940
+
"resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz",
3941
+
"integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
3942
+
"dev": true,
3943
+
"license": "MIT",
3944
+
"bin": {
3945
+
"lz-string": "bin/bin.js"
3946
+
}
3947
+
},
3948
+
"node_modules/magic-string": {
3949
+
"version": "0.30.17",
3950
+
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz",
3951
+
"integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==",
3952
+
"license": "MIT",
3953
+
"dependencies": {
3954
+
"@jridgewell/sourcemap-codec": "^1.5.0"
3955
+
}
3956
+
},
3957
+
"node_modules/minipass": {
3958
+
"version": "7.1.2",
3959
+
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
3960
+
"integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
3961
+
"license": "ISC",
3962
+
"engines": {
3963
+
"node": ">=16 || 14 >=14.17"
3964
+
}
3965
+
},
3966
+
"node_modules/minizlib": {
3967
+
"version": "3.0.2",
3968
+
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz",
3969
+
"integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==",
3970
+
"license": "MIT",
3971
+
"dependencies": {
3972
+
"minipass": "^7.1.2"
3973
+
},
3974
+
"engines": {
3975
+
"node": ">= 18"
3976
+
}
3977
+
},
3978
+
"node_modules/mkdirp": {
3979
+
"version": "3.0.1",
3980
+
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz",
3981
+
"integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==",
3982
+
"license": "MIT",
3983
+
"bin": {
3984
+
"mkdirp": "dist/cjs/src/bin.js"
3985
+
},
3986
+
"engines": {
3987
+
"node": ">=10"
3988
+
},
3989
+
"funding": {
3990
+
"url": "https://github.com/sponsors/isaacs"
3991
+
}
3992
+
},
3993
+
"node_modules/ms": {
3994
+
"version": "2.1.3",
3995
+
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
3996
+
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
3997
+
"license": "MIT"
3998
+
},
3999
+
"node_modules/multiformats": {
4000
+
"version": "9.9.0",
4001
+
"resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz",
4002
+
"integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==",
4003
+
"license": "(Apache-2.0 AND MIT)"
4004
+
},
4005
+
"node_modules/nanoid": {
4006
+
"version": "3.3.11",
4007
+
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
4008
+
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
4009
+
"funding": [
4010
+
{
4011
+
"type": "github",
4012
+
"url": "https://github.com/sponsors/ai"
4013
+
}
4014
+
],
4015
+
"license": "MIT",
4016
+
"bin": {
4017
+
"nanoid": "bin/nanoid.cjs"
4018
+
},
4019
+
"engines": {
4020
+
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
4021
+
}
4022
+
},
4023
+
"node_modules/node-releases": {
4024
+
"version": "2.0.19",
4025
+
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
4026
+
"integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==",
4027
+
"license": "MIT"
4028
+
},
4029
+
"node_modules/normalize-path": {
4030
+
"version": "3.0.0",
4031
+
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
4032
+
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
4033
+
"license": "MIT",
4034
+
"engines": {
4035
+
"node": ">=0.10.0"
4036
+
}
4037
+
},
4038
+
"node_modules/nwsapi": {
4039
+
"version": "2.2.21",
4040
+
"resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.21.tgz",
4041
+
"integrity": "sha512-o6nIY3qwiSXl7/LuOU0Dmuctd34Yay0yeuZRLFmDPrrdHpXKFndPj3hM+YEPVHYC5fx2otBx4Ilc/gyYSAUaIA==",
4042
+
"dev": true,
4043
+
"license": "MIT"
4044
+
},
4045
+
"node_modules/parse5": {
4046
+
"version": "7.3.0",
4047
+
"resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz",
4048
+
"integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==",
4049
+
"dev": true,
4050
+
"license": "MIT",
4051
+
"dependencies": {
4052
+
"entities": "^6.0.0"
4053
+
},
4054
+
"funding": {
4055
+
"url": "https://github.com/inikulin/parse5?sponsor=1"
4056
+
}
4057
+
},
4058
+
"node_modules/pathe": {
4059
+
"version": "2.0.3",
4060
+
"resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
4061
+
"integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
4062
+
"dev": true,
4063
+
"license": "MIT"
4064
+
},
4065
+
"node_modules/pathval": {
4066
+
"version": "2.0.1",
4067
+
"resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz",
4068
+
"integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==",
4069
+
"dev": true,
4070
+
"license": "MIT",
4071
+
"engines": {
4072
+
"node": ">= 14.16"
4073
+
}
4074
+
},
4075
+
"node_modules/picocolors": {
4076
+
"version": "1.1.1",
4077
+
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
4078
+
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
4079
+
"license": "ISC"
4080
+
},
4081
+
"node_modules/picomatch": {
4082
+
"version": "2.3.1",
4083
+
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
4084
+
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
4085
+
"license": "MIT",
4086
+
"engines": {
4087
+
"node": ">=8.6"
4088
+
},
4089
+
"funding": {
4090
+
"url": "https://github.com/sponsors/jonschlinkert"
4091
+
}
4092
+
},
4093
+
"node_modules/postcss": {
4094
+
"version": "8.5.6",
4095
+
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
4096
+
"integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
4097
+
"funding": [
4098
+
{
4099
+
"type": "opencollective",
4100
+
"url": "https://opencollective.com/postcss/"
4101
+
},
4102
+
{
4103
+
"type": "tidelift",
4104
+
"url": "https://tidelift.com/funding/github/npm/postcss"
4105
+
},
4106
+
{
4107
+
"type": "github",
4108
+
"url": "https://github.com/sponsors/ai"
4109
+
}
4110
+
],
4111
+
"license": "MIT",
4112
+
"dependencies": {
4113
+
"nanoid": "^3.3.11",
4114
+
"picocolors": "^1.1.1",
4115
+
"source-map-js": "^1.2.1"
4116
+
},
4117
+
"engines": {
4118
+
"node": "^10 || ^12 || >=14"
4119
+
}
4120
+
},
4121
+
"node_modules/prettier": {
4122
+
"version": "3.6.2",
4123
+
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz",
4124
+
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
4125
+
"license": "MIT",
4126
+
"bin": {
4127
+
"prettier": "bin/prettier.cjs"
4128
+
},
4129
+
"engines": {
4130
+
"node": ">=14"
4131
+
},
4132
+
"funding": {
4133
+
"url": "https://github.com/prettier/prettier?sponsor=1"
4134
+
}
4135
+
},
4136
+
"node_modules/pretty-format": {
4137
+
"version": "27.5.1",
4138
+
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
4139
+
"integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
4140
+
"dev": true,
4141
+
"license": "MIT",
4142
+
"dependencies": {
4143
+
"ansi-regex": "^5.0.1",
4144
+
"ansi-styles": "^5.0.0",
4145
+
"react-is": "^17.0.1"
4146
+
},
4147
+
"engines": {
4148
+
"node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
4149
+
}
4150
+
},
4151
+
"node_modules/punycode": {
4152
+
"version": "2.3.1",
4153
+
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
4154
+
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
4155
+
"dev": true,
4156
+
"license": "MIT",
4157
+
"engines": {
4158
+
"node": ">=6"
4159
+
}
4160
+
},
4161
+
"node_modules/react": {
4162
+
"version": "19.1.1",
4163
+
"resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz",
4164
+
"integrity": "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==",
4165
+
"license": "MIT",
4166
+
"engines": {
4167
+
"node": ">=0.10.0"
4168
+
}
4169
+
},
4170
+
"node_modules/react-dom": {
4171
+
"version": "19.1.1",
4172
+
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.1.tgz",
4173
+
"integrity": "sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==",
4174
+
"license": "MIT",
4175
+
"dependencies": {
4176
+
"scheduler": "^0.26.0"
4177
+
},
4178
+
"peerDependencies": {
4179
+
"react": "^19.1.1"
4180
+
}
4181
+
},
4182
+
"node_modules/react-is": {
4183
+
"version": "17.0.2",
4184
+
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
4185
+
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
4186
+
"dev": true,
4187
+
"license": "MIT"
4188
+
},
4189
+
"node_modules/react-refresh": {
4190
+
"version": "0.17.0",
4191
+
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz",
4192
+
"integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==",
4193
+
"dev": true,
4194
+
"license": "MIT",
4195
+
"engines": {
4196
+
"node": ">=0.10.0"
4197
+
}
4198
+
},
4199
+
"node_modules/react-remove-scroll": {
4200
+
"version": "2.7.1",
4201
+
"resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.1.tgz",
4202
+
"integrity": "sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==",
4203
+
"license": "MIT",
4204
+
"dependencies": {
4205
+
"react-remove-scroll-bar": "^2.3.7",
4206
+
"react-style-singleton": "^2.2.3",
4207
+
"tslib": "^2.1.0",
4208
+
"use-callback-ref": "^1.3.3",
4209
+
"use-sidecar": "^1.1.3"
4210
+
},
4211
+
"engines": {
4212
+
"node": ">=10"
4213
+
},
4214
+
"peerDependencies": {
4215
+
"@types/react": "*",
4216
+
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
4217
+
},
4218
+
"peerDependenciesMeta": {
4219
+
"@types/react": {
4220
+
"optional": true
4221
+
}
4222
+
}
4223
+
},
4224
+
"node_modules/react-remove-scroll-bar": {
4225
+
"version": "2.3.8",
4226
+
"resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz",
4227
+
"integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==",
4228
+
"license": "MIT",
4229
+
"dependencies": {
4230
+
"react-style-singleton": "^2.2.2",
4231
+
"tslib": "^2.0.0"
4232
+
},
4233
+
"engines": {
4234
+
"node": ">=10"
4235
+
},
4236
+
"peerDependencies": {
4237
+
"@types/react": "*",
4238
+
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
4239
+
},
4240
+
"peerDependenciesMeta": {
4241
+
"@types/react": {
4242
+
"optional": true
4243
+
}
4244
+
}
4245
+
},
4246
+
"node_modules/react-style-singleton": {
4247
+
"version": "2.2.3",
4248
+
"resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz",
4249
+
"integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==",
4250
+
"license": "MIT",
4251
+
"dependencies": {
4252
+
"get-nonce": "^1.0.0",
4253
+
"tslib": "^2.0.0"
4254
+
},
4255
+
"engines": {
4256
+
"node": ">=10"
4257
+
},
4258
+
"peerDependencies": {
4259
+
"@types/react": "*",
4260
+
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
4261
+
},
4262
+
"peerDependenciesMeta": {
4263
+
"@types/react": {
4264
+
"optional": true
4265
+
}
4266
+
}
4267
+
},
4268
+
"node_modules/readdirp": {
4269
+
"version": "3.6.0",
4270
+
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
4271
+
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
4272
+
"license": "MIT",
4273
+
"dependencies": {
4274
+
"picomatch": "^2.2.1"
4275
+
},
4276
+
"engines": {
4277
+
"node": ">=8.10.0"
4278
+
}
4279
+
},
4280
+
"node_modules/recast": {
4281
+
"version": "0.23.11",
4282
+
"resolved": "https://registry.npmjs.org/recast/-/recast-0.23.11.tgz",
4283
+
"integrity": "sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==",
4284
+
"license": "MIT",
4285
+
"dependencies": {
4286
+
"ast-types": "^0.16.1",
4287
+
"esprima": "~4.0.0",
4288
+
"source-map": "~0.6.1",
4289
+
"tiny-invariant": "^1.3.3",
4290
+
"tslib": "^2.0.1"
4291
+
},
4292
+
"engines": {
4293
+
"node": ">= 4"
4294
+
}
4295
+
},
4296
+
"node_modules/recast/node_modules/source-map": {
4297
+
"version": "0.6.1",
4298
+
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
4299
+
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
4300
+
"license": "BSD-3-Clause",
4301
+
"engines": {
4302
+
"node": ">=0.10.0"
4303
+
}
4304
+
},
4305
+
"node_modules/resolve-pkg-maps": {
4306
+
"version": "1.0.0",
4307
+
"resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
4308
+
"integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
4309
+
"license": "MIT",
4310
+
"funding": {
4311
+
"url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
4312
+
}
4313
+
},
4314
+
"node_modules/rollup": {
4315
+
"version": "4.46.2",
4316
+
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.46.2.tgz",
4317
+
"integrity": "sha512-WMmLFI+Boh6xbop+OAGo9cQ3OgX9MIg7xOQjn+pTCwOkk+FNDAeAemXkJ3HzDJrVXleLOFVa1ipuc1AmEx1Dwg==",
4318
+
"license": "MIT",
4319
+
"dependencies": {
4320
+
"@types/estree": "1.0.8"
4321
+
},
4322
+
"bin": {
4323
+
"rollup": "dist/bin/rollup"
4324
+
},
4325
+
"engines": {
4326
+
"node": ">=18.0.0",
4327
+
"npm": ">=8.0.0"
4328
+
},
4329
+
"optionalDependencies": {
4330
+
"@rollup/rollup-android-arm-eabi": "4.46.2",
4331
+
"@rollup/rollup-android-arm64": "4.46.2",
4332
+
"@rollup/rollup-darwin-arm64": "4.46.2",
4333
+
"@rollup/rollup-darwin-x64": "4.46.2",
4334
+
"@rollup/rollup-freebsd-arm64": "4.46.2",
4335
+
"@rollup/rollup-freebsd-x64": "4.46.2",
4336
+
"@rollup/rollup-linux-arm-gnueabihf": "4.46.2",
4337
+
"@rollup/rollup-linux-arm-musleabihf": "4.46.2",
4338
+
"@rollup/rollup-linux-arm64-gnu": "4.46.2",
4339
+
"@rollup/rollup-linux-arm64-musl": "4.46.2",
4340
+
"@rollup/rollup-linux-loongarch64-gnu": "4.46.2",
4341
+
"@rollup/rollup-linux-ppc64-gnu": "4.46.2",
4342
+
"@rollup/rollup-linux-riscv64-gnu": "4.46.2",
4343
+
"@rollup/rollup-linux-riscv64-musl": "4.46.2",
4344
+
"@rollup/rollup-linux-s390x-gnu": "4.46.2",
4345
+
"@rollup/rollup-linux-x64-gnu": "4.46.2",
4346
+
"@rollup/rollup-linux-x64-musl": "4.46.2",
4347
+
"@rollup/rollup-win32-arm64-msvc": "4.46.2",
4348
+
"@rollup/rollup-win32-ia32-msvc": "4.46.2",
4349
+
"@rollup/rollup-win32-x64-msvc": "4.46.2",
4350
+
"fsevents": "~2.3.2"
4351
+
}
4352
+
},
4353
+
"node_modules/rrweb-cssom": {
4354
+
"version": "0.8.0",
4355
+
"resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz",
4356
+
"integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==",
4357
+
"dev": true,
4358
+
"license": "MIT"
4359
+
},
4360
+
"node_modules/safer-buffer": {
4361
+
"version": "2.1.2",
4362
+
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
4363
+
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
4364
+
"dev": true,
4365
+
"license": "MIT"
4366
+
},
4367
+
"node_modules/saxes": {
4368
+
"version": "6.0.0",
4369
+
"resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz",
4370
+
"integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==",
4371
+
"dev": true,
4372
+
"license": "ISC",
4373
+
"dependencies": {
4374
+
"xmlchars": "^2.2.0"
4375
+
},
4376
+
"engines": {
4377
+
"node": ">=v12.22.7"
4378
+
}
4379
+
},
4380
+
"node_modules/scheduler": {
4381
+
"version": "0.26.0",
4382
+
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz",
4383
+
"integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==",
4384
+
"license": "MIT"
4385
+
},
4386
+
"node_modules/semver": {
4387
+
"version": "6.3.1",
4388
+
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
4389
+
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
4390
+
"license": "ISC",
4391
+
"bin": {
4392
+
"semver": "bin/semver.js"
4393
+
}
4394
+
},
4395
+
"node_modules/seroval": {
4396
+
"version": "1.3.2",
4397
+
"resolved": "https://registry.npmjs.org/seroval/-/seroval-1.3.2.tgz",
4398
+
"integrity": "sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ==",
4399
+
"license": "MIT",
4400
+
"engines": {
4401
+
"node": ">=10"
4402
+
}
4403
+
},
4404
+
"node_modules/seroval-plugins": {
4405
+
"version": "1.3.2",
4406
+
"resolved": "https://registry.npmjs.org/seroval-plugins/-/seroval-plugins-1.3.2.tgz",
4407
+
"integrity": "sha512-0QvCV2lM3aj/U3YozDiVwx9zpH0q8A60CTWIv4Jszj/givcudPb48B+rkU5D51NJ0pTpweGMttHjboPa9/zoIQ==",
4408
+
"license": "MIT",
4409
+
"engines": {
4410
+
"node": ">=10"
4411
+
},
4412
+
"peerDependencies": {
4413
+
"seroval": "^1.0"
4414
+
}
4415
+
},
4416
+
"node_modules/siginfo": {
4417
+
"version": "2.0.0",
4418
+
"resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz",
4419
+
"integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==",
4420
+
"dev": true,
4421
+
"license": "ISC"
4422
+
},
4423
+
"node_modules/solid-js": {
4424
+
"version": "1.9.7",
4425
+
"resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.9.7.tgz",
4426
+
"integrity": "sha512-/saTKi8iWEM233n5OSi1YHCCuh66ZIQ7aK2hsToPe4tqGm7qAejU1SwNuTPivbWAYq7SjuHVVYxxuZQNRbICiw==",
4427
+
"license": "MIT",
4428
+
"dependencies": {
4429
+
"csstype": "^3.1.0",
4430
+
"seroval": "~1.3.0",
4431
+
"seroval-plugins": "~1.3.0"
4432
+
}
4433
+
},
4434
+
"node_modules/source-map": {
4435
+
"version": "0.7.6",
4436
+
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz",
4437
+
"integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==",
4438
+
"license": "BSD-3-Clause",
4439
+
"engines": {
4440
+
"node": ">= 12"
4441
+
}
4442
+
},
4443
+
"node_modules/source-map-js": {
4444
+
"version": "1.2.1",
4445
+
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
4446
+
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
4447
+
"license": "BSD-3-Clause",
4448
+
"engines": {
4449
+
"node": ">=0.10.0"
4450
+
}
4451
+
},
4452
+
"node_modules/stackback": {
4453
+
"version": "0.0.2",
4454
+
"resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
4455
+
"integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==",
4456
+
"dev": true,
4457
+
"license": "MIT"
4458
+
},
4459
+
"node_modules/std-env": {
4460
+
"version": "3.9.0",
4461
+
"resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz",
4462
+
"integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==",
4463
+
"dev": true,
4464
+
"license": "MIT"
4465
+
},
4466
+
"node_modules/strip-literal": {
4467
+
"version": "3.0.0",
4468
+
"resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.0.0.tgz",
4469
+
"integrity": "sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==",
4470
+
"dev": true,
4471
+
"license": "MIT",
4472
+
"dependencies": {
4473
+
"js-tokens": "^9.0.1"
4474
+
},
4475
+
"funding": {
4476
+
"url": "https://github.com/sponsors/antfu"
4477
+
}
4478
+
},
4479
+
"node_modules/strip-literal/node_modules/js-tokens": {
4480
+
"version": "9.0.1",
4481
+
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz",
4482
+
"integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==",
4483
+
"dev": true,
4484
+
"license": "MIT"
4485
+
},
4486
+
"node_modules/symbol-tree": {
4487
+
"version": "3.2.4",
4488
+
"resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
4489
+
"integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==",
4490
+
"dev": true,
4491
+
"license": "MIT"
4492
+
},
4493
+
"node_modules/tailwindcss": {
4494
+
"version": "4.1.11",
4495
+
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.11.tgz",
4496
+
"integrity": "sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA==",
4497
+
"license": "MIT"
4498
+
},
4499
+
"node_modules/tapable": {
4500
+
"version": "2.2.2",
4501
+
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.2.tgz",
4502
+
"integrity": "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==",
4503
+
"license": "MIT",
4504
+
"engines": {
4505
+
"node": ">=6"
4506
+
}
4507
+
},
4508
+
"node_modules/tar": {
4509
+
"version": "7.4.3",
4510
+
"resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz",
4511
+
"integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==",
4512
+
"license": "ISC",
4513
+
"dependencies": {
4514
+
"@isaacs/fs-minipass": "^4.0.0",
4515
+
"chownr": "^3.0.0",
4516
+
"minipass": "^7.1.2",
4517
+
"minizlib": "^3.0.1",
4518
+
"mkdirp": "^3.0.1",
4519
+
"yallist": "^5.0.0"
4520
+
},
4521
+
"engines": {
4522
+
"node": ">=18"
4523
+
}
4524
+
},
4525
+
"node_modules/tar/node_modules/yallist": {
4526
+
"version": "5.0.0",
4527
+
"resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
4528
+
"integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==",
4529
+
"license": "BlueOak-1.0.0",
4530
+
"engines": {
4531
+
"node": ">=18"
4532
+
}
4533
+
},
4534
+
"node_modules/tiny-invariant": {
4535
+
"version": "1.3.3",
4536
+
"resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz",
4537
+
"integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==",
4538
+
"license": "MIT"
4539
+
},
4540
+
"node_modules/tiny-warning": {
4541
+
"version": "1.0.3",
4542
+
"resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
4543
+
"integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==",
4544
+
"license": "MIT"
4545
+
},
4546
+
"node_modules/tinybench": {
4547
+
"version": "2.9.0",
4548
+
"resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz",
4549
+
"integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==",
4550
+
"dev": true,
4551
+
"license": "MIT"
4552
+
},
4553
+
"node_modules/tinyexec": {
4554
+
"version": "0.3.2",
4555
+
"resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz",
4556
+
"integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==",
4557
+
"dev": true,
4558
+
"license": "MIT"
4559
+
},
4560
+
"node_modules/tinyglobby": {
4561
+
"version": "0.2.14",
4562
+
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz",
4563
+
"integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==",
4564
+
"license": "MIT",
4565
+
"dependencies": {
4566
+
"fdir": "^6.4.4",
4567
+
"picomatch": "^4.0.2"
4568
+
},
4569
+
"engines": {
4570
+
"node": ">=12.0.0"
4571
+
},
4572
+
"funding": {
4573
+
"url": "https://github.com/sponsors/SuperchupuDev"
4574
+
}
4575
+
},
4576
+
"node_modules/tinyglobby/node_modules/fdir": {
4577
+
"version": "6.4.6",
4578
+
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz",
4579
+
"integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==",
4580
+
"license": "MIT",
4581
+
"peerDependencies": {
4582
+
"picomatch": "^3 || ^4"
4583
+
},
4584
+
"peerDependenciesMeta": {
4585
+
"picomatch": {
4586
+
"optional": true
4587
+
}
4588
+
}
4589
+
},
4590
+
"node_modules/tinyglobby/node_modules/picomatch": {
4591
+
"version": "4.0.3",
4592
+
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
4593
+
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
4594
+
"license": "MIT",
4595
+
"engines": {
4596
+
"node": ">=12"
4597
+
},
4598
+
"funding": {
4599
+
"url": "https://github.com/sponsors/jonschlinkert"
4600
+
}
4601
+
},
4602
+
"node_modules/tinypool": {
4603
+
"version": "1.1.1",
4604
+
"resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz",
4605
+
"integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==",
4606
+
"dev": true,
4607
+
"license": "MIT",
4608
+
"engines": {
4609
+
"node": "^18.0.0 || >=20.0.0"
4610
+
}
4611
+
},
4612
+
"node_modules/tinyrainbow": {
4613
+
"version": "2.0.0",
4614
+
"resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz",
4615
+
"integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==",
4616
+
"dev": true,
4617
+
"license": "MIT",
4618
+
"engines": {
4619
+
"node": ">=14.0.0"
4620
+
}
4621
+
},
4622
+
"node_modules/tinyspy": {
4623
+
"version": "4.0.3",
4624
+
"resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.3.tgz",
4625
+
"integrity": "sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==",
4626
+
"dev": true,
4627
+
"license": "MIT",
4628
+
"engines": {
4629
+
"node": ">=14.0.0"
4630
+
}
4631
+
},
4632
+
"node_modules/tlds": {
4633
+
"version": "1.259.0",
4634
+
"resolved": "https://registry.npmjs.org/tlds/-/tlds-1.259.0.tgz",
4635
+
"integrity": "sha512-AldGGlDP0PNgwppe2quAvuBl18UcjuNtOnDuUkqhd6ipPqrYYBt3aTxK1QTsBVknk97lS2JcafWMghjGWFtunw==",
4636
+
"license": "MIT",
4637
+
"bin": {
4638
+
"tlds": "bin.js"
4639
+
}
4640
+
},
4641
+
"node_modules/tldts": {
4642
+
"version": "6.1.86",
4643
+
"resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz",
4644
+
"integrity": "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==",
4645
+
"dev": true,
4646
+
"license": "MIT",
4647
+
"dependencies": {
4648
+
"tldts-core": "^6.1.86"
4649
+
},
4650
+
"bin": {
4651
+
"tldts": "bin/cli.js"
4652
+
}
4653
+
},
4654
+
"node_modules/tldts-core": {
4655
+
"version": "6.1.86",
4656
+
"resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.86.tgz",
4657
+
"integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==",
4658
+
"dev": true,
4659
+
"license": "MIT"
4660
+
},
4661
+
"node_modules/to-regex-range": {
4662
+
"version": "5.0.1",
4663
+
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
4664
+
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
4665
+
"license": "MIT",
4666
+
"dependencies": {
4667
+
"is-number": "^7.0.0"
4668
+
},
4669
+
"engines": {
4670
+
"node": ">=8.0"
4671
+
}
4672
+
},
4673
+
"node_modules/tough-cookie": {
4674
+
"version": "5.1.2",
4675
+
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz",
4676
+
"integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==",
4677
+
"dev": true,
4678
+
"license": "BSD-3-Clause",
4679
+
"dependencies": {
4680
+
"tldts": "^6.1.32"
4681
+
},
4682
+
"engines": {
4683
+
"node": ">=16"
4684
+
}
4685
+
},
4686
+
"node_modules/tr46": {
4687
+
"version": "5.1.1",
4688
+
"resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz",
4689
+
"integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==",
4690
+
"dev": true,
4691
+
"license": "MIT",
4692
+
"dependencies": {
4693
+
"punycode": "^2.3.1"
4694
+
},
4695
+
"engines": {
4696
+
"node": ">=18"
4697
+
}
4698
+
},
4699
+
"node_modules/tslib": {
4700
+
"version": "2.8.1",
4701
+
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
4702
+
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
4703
+
"license": "0BSD"
4704
+
},
4705
+
"node_modules/tsx": {
4706
+
"version": "4.20.3",
4707
+
"resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.3.tgz",
4708
+
"integrity": "sha512-qjbnuR9Tr+FJOMBqJCW5ehvIo/buZq7vH7qD7JziU98h6l3qGy0a/yPFjwO+y0/T7GFpNgNAvEcPPVfyT8rrPQ==",
4709
+
"license": "MIT",
4710
+
"dependencies": {
4711
+
"esbuild": "~0.25.0",
4712
+
"get-tsconfig": "^4.7.5"
4713
+
},
4714
+
"bin": {
4715
+
"tsx": "dist/cli.mjs"
4716
+
},
4717
+
"engines": {
4718
+
"node": ">=18.0.0"
4719
+
},
4720
+
"optionalDependencies": {
4721
+
"fsevents": "~2.3.3"
4722
+
}
4723
+
},
4724
+
"node_modules/typescript": {
4725
+
"version": "5.9.2",
4726
+
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz",
4727
+
"integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
4728
+
"dev": true,
4729
+
"license": "Apache-2.0",
4730
+
"bin": {
4731
+
"tsc": "bin/tsc",
4732
+
"tsserver": "bin/tsserver"
4733
+
},
4734
+
"engines": {
4735
+
"node": ">=14.17"
4736
+
}
4737
+
},
4738
+
"node_modules/uint8arrays": {
4739
+
"version": "3.0.0",
4740
+
"resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.0.0.tgz",
4741
+
"integrity": "sha512-HRCx0q6O9Bfbp+HHSfQQKD7wU70+lydKVt4EghkdOvlK/NlrF90z+eXV34mUd48rNvVJXwkrMSPpCATkct8fJA==",
4742
+
"license": "MIT",
4743
+
"dependencies": {
4744
+
"multiformats": "^9.4.2"
4745
+
}
4746
+
},
4747
+
"node_modules/unplugin": {
4748
+
"version": "2.3.5",
4749
+
"resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.5.tgz",
4750
+
"integrity": "sha512-RyWSb5AHmGtjjNQ6gIlA67sHOsWpsbWpwDokLwTcejVdOjEkJZh7QKu14J00gDDVSh8kGH4KYC/TNBceXFZhtw==",
4751
+
"license": "MIT",
4752
+
"dependencies": {
4753
+
"acorn": "^8.14.1",
4754
+
"picomatch": "^4.0.2",
4755
+
"webpack-virtual-modules": "^0.6.2"
4756
+
},
4757
+
"engines": {
4758
+
"node": ">=18.12.0"
4759
+
}
4760
+
},
4761
+
"node_modules/unplugin/node_modules/picomatch": {
4762
+
"version": "4.0.3",
4763
+
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
4764
+
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
4765
+
"license": "MIT",
4766
+
"engines": {
4767
+
"node": ">=12"
4768
+
},
4769
+
"funding": {
4770
+
"url": "https://github.com/sponsors/jonschlinkert"
4771
+
}
4772
+
},
4773
+
"node_modules/update-browserslist-db": {
4774
+
"version": "1.1.3",
4775
+
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
4776
+
"integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==",
4777
+
"funding": [
4778
+
{
4779
+
"type": "opencollective",
4780
+
"url": "https://opencollective.com/browserslist"
4781
+
},
4782
+
{
4783
+
"type": "tidelift",
4784
+
"url": "https://tidelift.com/funding/github/npm/browserslist"
4785
+
},
4786
+
{
4787
+
"type": "github",
4788
+
"url": "https://github.com/sponsors/ai"
4789
+
}
4790
+
],
4791
+
"license": "MIT",
4792
+
"dependencies": {
4793
+
"escalade": "^3.2.0",
4794
+
"picocolors": "^1.1.1"
4795
+
},
4796
+
"bin": {
4797
+
"update-browserslist-db": "cli.js"
4798
+
},
4799
+
"peerDependencies": {
4800
+
"browserslist": ">= 4.21.0"
4801
+
}
4802
+
},
4803
+
"node_modules/use-callback-ref": {
4804
+
"version": "1.3.3",
4805
+
"resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz",
4806
+
"integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==",
4807
+
"license": "MIT",
4808
+
"dependencies": {
4809
+
"tslib": "^2.0.0"
4810
+
},
4811
+
"engines": {
4812
+
"node": ">=10"
4813
+
},
4814
+
"peerDependencies": {
4815
+
"@types/react": "*",
4816
+
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
4817
+
},
4818
+
"peerDependenciesMeta": {
4819
+
"@types/react": {
4820
+
"optional": true
4821
+
}
4822
+
}
4823
+
},
4824
+
"node_modules/use-sidecar": {
4825
+
"version": "1.1.3",
4826
+
"resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz",
4827
+
"integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==",
4828
+
"license": "MIT",
4829
+
"dependencies": {
4830
+
"detect-node-es": "^1.1.0",
4831
+
"tslib": "^2.0.0"
4832
+
},
4833
+
"engines": {
4834
+
"node": ">=10"
4835
+
},
4836
+
"peerDependencies": {
4837
+
"@types/react": "*",
4838
+
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
4839
+
},
4840
+
"peerDependenciesMeta": {
4841
+
"@types/react": {
4842
+
"optional": true
4843
+
}
4844
+
}
4845
+
},
4846
+
"node_modules/use-sync-external-store": {
4847
+
"version": "1.5.0",
4848
+
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz",
4849
+
"integrity": "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==",
4850
+
"license": "MIT",
4851
+
"peerDependencies": {
4852
+
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
4853
+
}
4854
+
},
4855
+
"node_modules/vite": {
4856
+
"version": "6.3.5",
4857
+
"resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz",
4858
+
"integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==",
4859
+
"license": "MIT",
4860
+
"dependencies": {
4861
+
"esbuild": "^0.25.0",
4862
+
"fdir": "^6.4.4",
4863
+
"picomatch": "^4.0.2",
4864
+
"postcss": "^8.5.3",
4865
+
"rollup": "^4.34.9",
4866
+
"tinyglobby": "^0.2.13"
4867
+
},
4868
+
"bin": {
4869
+
"vite": "bin/vite.js"
4870
+
},
4871
+
"engines": {
4872
+
"node": "^18.0.0 || ^20.0.0 || >=22.0.0"
4873
+
},
4874
+
"funding": {
4875
+
"url": "https://github.com/vitejs/vite?sponsor=1"
4876
+
},
4877
+
"optionalDependencies": {
4878
+
"fsevents": "~2.3.3"
4879
+
},
4880
+
"peerDependencies": {
4881
+
"@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
4882
+
"jiti": ">=1.21.0",
4883
+
"less": "*",
4884
+
"lightningcss": "^1.21.0",
4885
+
"sass": "*",
4886
+
"sass-embedded": "*",
4887
+
"stylus": "*",
4888
+
"sugarss": "*",
4889
+
"terser": "^5.16.0",
4890
+
"tsx": "^4.8.1",
4891
+
"yaml": "^2.4.2"
4892
+
},
4893
+
"peerDependenciesMeta": {
4894
+
"@types/node": {
4895
+
"optional": true
4896
+
},
4897
+
"jiti": {
4898
+
"optional": true
4899
+
},
4900
+
"less": {
4901
+
"optional": true
4902
+
},
4903
+
"lightningcss": {
4904
+
"optional": true
4905
+
},
4906
+
"sass": {
4907
+
"optional": true
4908
+
},
4909
+
"sass-embedded": {
4910
+
"optional": true
4911
+
},
4912
+
"stylus": {
4913
+
"optional": true
4914
+
},
4915
+
"sugarss": {
4916
+
"optional": true
4917
+
},
4918
+
"terser": {
4919
+
"optional": true
4920
+
},
4921
+
"tsx": {
4922
+
"optional": true
4923
+
},
4924
+
"yaml": {
4925
+
"optional": true
4926
+
}
4927
+
}
4928
+
},
4929
+
"node_modules/vite-node": {
4930
+
"version": "3.2.4",
4931
+
"resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz",
4932
+
"integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==",
4933
+
"dev": true,
4934
+
"license": "MIT",
4935
+
"dependencies": {
4936
+
"cac": "^6.7.14",
4937
+
"debug": "^4.4.1",
4938
+
"es-module-lexer": "^1.7.0",
4939
+
"pathe": "^2.0.3",
4940
+
"vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0"
4941
+
},
4942
+
"bin": {
4943
+
"vite-node": "vite-node.mjs"
4944
+
},
4945
+
"engines": {
4946
+
"node": "^18.0.0 || ^20.0.0 || >=22.0.0"
4947
+
},
4948
+
"funding": {
4949
+
"url": "https://opencollective.com/vitest"
4950
+
}
4951
+
},
4952
+
"node_modules/vite/node_modules/fdir": {
4953
+
"version": "6.4.6",
4954
+
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz",
4955
+
"integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==",
4956
+
"license": "MIT",
4957
+
"peerDependencies": {
4958
+
"picomatch": "^3 || ^4"
4959
+
},
4960
+
"peerDependenciesMeta": {
4961
+
"picomatch": {
4962
+
"optional": true
4963
+
}
4964
+
}
4965
+
},
4966
+
"node_modules/vite/node_modules/picomatch": {
4967
+
"version": "4.0.3",
4968
+
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
4969
+
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
4970
+
"license": "MIT",
4971
+
"engines": {
4972
+
"node": ">=12"
4973
+
},
4974
+
"funding": {
4975
+
"url": "https://github.com/sponsors/jonschlinkert"
4976
+
}
4977
+
},
4978
+
"node_modules/vitest": {
4979
+
"version": "3.2.4",
4980
+
"resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.4.tgz",
4981
+
"integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==",
4982
+
"dev": true,
4983
+
"license": "MIT",
4984
+
"dependencies": {
4985
+
"@types/chai": "^5.2.2",
4986
+
"@vitest/expect": "3.2.4",
4987
+
"@vitest/mocker": "3.2.4",
4988
+
"@vitest/pretty-format": "^3.2.4",
4989
+
"@vitest/runner": "3.2.4",
4990
+
"@vitest/snapshot": "3.2.4",
4991
+
"@vitest/spy": "3.2.4",
4992
+
"@vitest/utils": "3.2.4",
4993
+
"chai": "^5.2.0",
4994
+
"debug": "^4.4.1",
4995
+
"expect-type": "^1.2.1",
4996
+
"magic-string": "^0.30.17",
4997
+
"pathe": "^2.0.3",
4998
+
"picomatch": "^4.0.2",
4999
+
"std-env": "^3.9.0",
5000
+
"tinybench": "^2.9.0",
5001
+
"tinyexec": "^0.3.2",
5002
+
"tinyglobby": "^0.2.14",
5003
+
"tinypool": "^1.1.1",
5004
+
"tinyrainbow": "^2.0.0",
5005
+
"vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0",
5006
+
"vite-node": "3.2.4",
5007
+
"why-is-node-running": "^2.3.0"
5008
+
},
5009
+
"bin": {
5010
+
"vitest": "vitest.mjs"
5011
+
},
5012
+
"engines": {
5013
+
"node": "^18.0.0 || ^20.0.0 || >=22.0.0"
5014
+
},
5015
+
"funding": {
5016
+
"url": "https://opencollective.com/vitest"
5017
+
},
5018
+
"peerDependencies": {
5019
+
"@edge-runtime/vm": "*",
5020
+
"@types/debug": "^4.1.12",
5021
+
"@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
5022
+
"@vitest/browser": "3.2.4",
5023
+
"@vitest/ui": "3.2.4",
5024
+
"happy-dom": "*",
5025
+
"jsdom": "*"
5026
+
},
5027
+
"peerDependenciesMeta": {
5028
+
"@edge-runtime/vm": {
5029
+
"optional": true
5030
+
},
5031
+
"@types/debug": {
5032
+
"optional": true
5033
+
},
5034
+
"@types/node": {
5035
+
"optional": true
5036
+
},
5037
+
"@vitest/browser": {
5038
+
"optional": true
5039
+
},
5040
+
"@vitest/ui": {
5041
+
"optional": true
5042
+
},
5043
+
"happy-dom": {
5044
+
"optional": true
5045
+
},
5046
+
"jsdom": {
5047
+
"optional": true
5048
+
}
5049
+
}
5050
+
},
5051
+
"node_modules/vitest/node_modules/picomatch": {
5052
+
"version": "4.0.3",
5053
+
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
5054
+
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
5055
+
"dev": true,
5056
+
"license": "MIT",
5057
+
"engines": {
5058
+
"node": ">=12"
5059
+
},
5060
+
"funding": {
5061
+
"url": "https://github.com/sponsors/jonschlinkert"
5062
+
}
5063
+
},
5064
+
"node_modules/w3c-xmlserializer": {
5065
+
"version": "5.0.0",
5066
+
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz",
5067
+
"integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==",
5068
+
"dev": true,
5069
+
"license": "MIT",
5070
+
"dependencies": {
5071
+
"xml-name-validator": "^5.0.0"
5072
+
},
5073
+
"engines": {
5074
+
"node": ">=18"
5075
+
}
5076
+
},
5077
+
"node_modules/web-vitals": {
5078
+
"version": "4.2.4",
5079
+
"resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-4.2.4.tgz",
5080
+
"integrity": "sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==",
5081
+
"dev": true,
5082
+
"license": "Apache-2.0"
5083
+
},
5084
+
"node_modules/webidl-conversions": {
5085
+
"version": "7.0.0",
5086
+
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
5087
+
"integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
5088
+
"dev": true,
5089
+
"license": "BSD-2-Clause",
5090
+
"engines": {
5091
+
"node": ">=12"
5092
+
}
5093
+
},
5094
+
"node_modules/webpack-virtual-modules": {
5095
+
"version": "0.6.2",
5096
+
"resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz",
5097
+
"integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==",
5098
+
"license": "MIT"
5099
+
},
5100
+
"node_modules/whatwg-encoding": {
5101
+
"version": "3.1.1",
5102
+
"resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz",
5103
+
"integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==",
5104
+
"dev": true,
5105
+
"license": "MIT",
5106
+
"dependencies": {
5107
+
"iconv-lite": "0.6.3"
5108
+
},
5109
+
"engines": {
5110
+
"node": ">=18"
5111
+
}
5112
+
},
5113
+
"node_modules/whatwg-mimetype": {
5114
+
"version": "4.0.0",
5115
+
"resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz",
5116
+
"integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==",
5117
+
"dev": true,
5118
+
"license": "MIT",
5119
+
"engines": {
5120
+
"node": ">=18"
5121
+
}
5122
+
},
5123
+
"node_modules/whatwg-url": {
5124
+
"version": "14.2.0",
5125
+
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz",
5126
+
"integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==",
5127
+
"dev": true,
5128
+
"license": "MIT",
5129
+
"dependencies": {
5130
+
"tr46": "^5.1.0",
5131
+
"webidl-conversions": "^7.0.0"
5132
+
},
5133
+
"engines": {
5134
+
"node": ">=18"
5135
+
}
5136
+
},
5137
+
"node_modules/why-is-node-running": {
5138
+
"version": "2.3.0",
5139
+
"resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz",
5140
+
"integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==",
5141
+
"dev": true,
5142
+
"license": "MIT",
5143
+
"dependencies": {
5144
+
"siginfo": "^2.0.0",
5145
+
"stackback": "0.0.2"
5146
+
},
5147
+
"bin": {
5148
+
"why-is-node-running": "cli.js"
5149
+
},
5150
+
"engines": {
5151
+
"node": ">=8"
5152
+
}
5153
+
},
5154
+
"node_modules/ws": {
5155
+
"version": "8.18.3",
5156
+
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
5157
+
"integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
5158
+
"dev": true,
5159
+
"license": "MIT",
5160
+
"engines": {
5161
+
"node": ">=10.0.0"
5162
+
},
5163
+
"peerDependencies": {
5164
+
"bufferutil": "^4.0.1",
5165
+
"utf-8-validate": ">=5.0.2"
5166
+
},
5167
+
"peerDependenciesMeta": {
5168
+
"bufferutil": {
5169
+
"optional": true
5170
+
},
5171
+
"utf-8-validate": {
5172
+
"optional": true
5173
+
}
5174
+
}
5175
+
},
5176
+
"node_modules/xml-name-validator": {
5177
+
"version": "5.0.0",
5178
+
"resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz",
5179
+
"integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==",
5180
+
"dev": true,
5181
+
"license": "Apache-2.0",
5182
+
"engines": {
5183
+
"node": ">=18"
5184
+
}
5185
+
},
5186
+
"node_modules/xmlchars": {
5187
+
"version": "2.2.0",
5188
+
"resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
5189
+
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
5190
+
"dev": true,
5191
+
"license": "MIT"
5192
+
},
5193
+
"node_modules/yallist": {
5194
+
"version": "3.1.1",
5195
+
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
5196
+
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
5197
+
"license": "ISC"
5198
+
},
5199
+
"node_modules/zod": {
5200
+
"version": "3.25.76",
5201
+
"resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
5202
+
"integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
5203
+
"license": "MIT",
5204
+
"funding": {
5205
+
"url": "https://github.com/sponsors/colinhacks"
5206
+
}
5207
+
}
5208
+
}
5209
+
}
+40
package.json
+40
package.json
···
1
+
{
2
+
"name": "forumtest",
3
+
"private": true,
4
+
"type": "module",
5
+
"scripts": {
6
+
"dev": "vite --port 3000",
7
+
"start": "vite --port 3000",
8
+
"build": "vite build && tsc",
9
+
"serve": "vite preview",
10
+
"test": "vitest run"
11
+
},
12
+
"dependencies": {
13
+
"@atproto/api": "^0.16.0",
14
+
"@radix-ui/react-dialog": "^1.1.14",
15
+
"@radix-ui/react-icons": "^1.3.2",
16
+
"@radix-ui/react-popover": "^1.1.14",
17
+
"@radix-ui/react-select": "^2.2.5",
18
+
"@tailwindcss/vite": "^4.1.11",
19
+
"@tanstack/react-query": "^5.84.1",
20
+
"@tanstack/react-router": "^1.130.2",
21
+
"@tanstack/react-router-devtools": "^1.130.2",
22
+
"@tanstack/router-plugin": "^1.121.2",
23
+
"idb-keyval": "^6.2.2",
24
+
"react": "^19.0.0",
25
+
"react-dom": "^19.0.0",
26
+
"tailwindcss": "^4.1.11"
27
+
},
28
+
"devDependencies": {
29
+
"@testing-library/dom": "^10.4.0",
30
+
"@testing-library/react": "^16.2.0",
31
+
"@types/react": "^19.0.8",
32
+
"@types/react-dom": "^19.0.3",
33
+
"@vitejs/plugin-react": "^4.3.4",
34
+
"jsdom": "^26.0.0",
35
+
"typescript": "^5.7.2",
36
+
"vite": "^6.3.5",
37
+
"vitest": "^3.0.5",
38
+
"web-vitals": "^4.2.4"
39
+
}
40
+
}
+1
public/.well-known/atproto-did
+1
public/.well-known/atproto-did
···
1
+
did:plc:cjfima2v3vnyfuzieu7bvjx7
public/favicon.ico
public/favicon.ico
This is a binary file and will not be displayed.
public/logo192.png
public/logo192.png
This is a binary file and will not be displayed.
public/logo512.png
public/logo512.png
This is a binary file and will not be displayed.
+25
public/manifest.json
+25
public/manifest.json
···
1
+
{
2
+
"short_name": "ForumTest",
3
+
"name": "ForumTest",
4
+
"icons": [
5
+
{
6
+
"src": "favicon.ico",
7
+
"sizes": "64x64 32x32 24x24 16x16",
8
+
"type": "image/x-icon"
9
+
},
10
+
{
11
+
"src": "logo192.png",
12
+
"type": "image/png",
13
+
"sizes": "192x192"
14
+
},
15
+
{
16
+
"src": "logo512.png",
17
+
"type": "image/png",
18
+
"sizes": "512x512"
19
+
}
20
+
],
21
+
"start_url": ".",
22
+
"display": "standalone",
23
+
"theme_color": "#000000",
24
+
"background_color": "#ffffff"
25
+
}
+3
public/robots.txt
+3
public/robots.txt
+53
src/App.css
+53
src/App.css
···
1
+
@import "tailwindcss";
2
+
.stretched-link::after {
3
+
position: absolute;
4
+
top: 0;
5
+
right: 0;
6
+
bottom: 0;
7
+
left: 0;
8
+
z-index: 1; /* This makes the link's clickable area cover the content */
9
+
content: "";
10
+
}
11
+
.forum-grid {
12
+
display: grid;
13
+
grid-template-columns: repeat(auto-fill, minmax(270px, 1fr));
14
+
gap: 1.5rem;
15
+
}
16
+
.App {
17
+
text-align: center;
18
+
}
19
+
20
+
.App-logo {
21
+
height: 40vmin;
22
+
pointer-events: none;
23
+
}
24
+
25
+
@media (prefers-reduced-motion: no-preference) {
26
+
.App-logo {
27
+
animation: App-logo-spin infinite 20s linear;
28
+
}
29
+
}
30
+
31
+
.App-header {
32
+
background-color: #282c34;
33
+
min-height: 100vh;
34
+
display: flex;
35
+
flex-direction: column;
36
+
align-items: center;
37
+
justify-content: center;
38
+
font-size: calc(10px + 2vmin);
39
+
color: white;
40
+
}
41
+
42
+
.App-link {
43
+
color: #61dafb;
44
+
}
45
+
46
+
@keyframes App-logo-spin {
47
+
from {
48
+
transform: rotate(0deg);
49
+
}
50
+
to {
51
+
transform: rotate(360deg);
52
+
}
53
+
}
+53
src/components/DefaultCatchBoundary.tsx
+53
src/components/DefaultCatchBoundary.tsx
···
1
+
import {
2
+
ErrorComponent,
3
+
Link,
4
+
rootRouteId,
5
+
useMatch,
6
+
useRouter,
7
+
} from '@tanstack/react-router'
8
+
import type { ErrorComponentProps } from '@tanstack/react-router'
9
+
10
+
export function DefaultCatchBoundary({ error }: ErrorComponentProps) {
11
+
const router = useRouter()
12
+
const isRoot = useMatch({
13
+
strict: false,
14
+
select: (state) => state.id === rootRouteId,
15
+
})
16
+
17
+
console.error('DefaultCatchBoundary Error:', error)
18
+
19
+
return (
20
+
<div className="min-w-0 flex-1 p-4 flex flex-col items-center justify-center gap-6">
21
+
<ErrorComponent error={error} />
22
+
<div className="flex gap-2 items-center flex-wrap">
23
+
<button
24
+
onClick={() => {
25
+
router.invalidate()
26
+
}}
27
+
className={`px-2 py-1 bg-gray-600 dark:bg-gray-700 rounded text-white uppercase font-extrabold`}
28
+
>
29
+
Try Again
30
+
</button>
31
+
{isRoot ? (
32
+
<Link
33
+
to="/"
34
+
className={`px-2 py-1 bg-gray-600 dark:bg-gray-700 rounded text-white uppercase font-extrabold`}
35
+
>
36
+
Home
37
+
</Link>
38
+
) : (
39
+
<Link
40
+
to="/"
41
+
className={`px-2 py-1 bg-gray-600 dark:bg-gray-700 rounded text-white uppercase font-extrabold`}
42
+
onClick={(e) => {
43
+
e.preventDefault()
44
+
window.history.back()
45
+
}}
46
+
>
47
+
Go Back
48
+
</Link>
49
+
)}
50
+
</div>
51
+
</div>
52
+
)
53
+
}
+16
src/components/Header.tsx
+16
src/components/Header.tsx
···
1
+
import { Link } from "@tanstack/react-router";
2
+
import Login from "./Login";
3
+
import { SearchBox } from "./Search";
4
+
5
+
6
+
7
+
export default function Header(){
8
+
9
+
10
+
return <div className="flex flex-row h-10 items-center px-2 sticky top-0 bg-gray-700 z-50">
11
+
<Link to="/"><span className=" text-gray-50 font-bold">ForumTest</span></Link>
12
+
{/* <div className="spacer flex-1" /> */}
13
+
<SearchBox />
14
+
<Login compact />
15
+
</div>
16
+
}
+214
src/components/Login.tsx
+214
src/components/Login.tsx
···
1
+
import React, { useEffect, useState, useRef } from 'react';
2
+
import { useAuth } from '@/providers/PassAuthProvider';
3
+
4
+
interface LoginProps {
5
+
compact?: boolean;
6
+
}
7
+
8
+
export default function Login({ compact = false }: LoginProps) {
9
+
const { loginStatus, login, logout, loading, authed } = useAuth();
10
+
const [user, setUser] = useState('');
11
+
const [password, setPassword] = useState('');
12
+
const [serviceURL, setServiceURL] = useState('bsky.social');
13
+
const [showLoginForm, setShowLoginForm] = useState(false);
14
+
const formRef = useRef<HTMLDivElement>(null);
15
+
16
+
useEffect(() => {
17
+
function handleClickOutside(event: MouseEvent) {
18
+
if (formRef.current && !formRef.current.contains(event.target as Node)) {
19
+
setShowLoginForm(false);
20
+
}
21
+
}
22
+
23
+
if (showLoginForm) {
24
+
document.addEventListener('mousedown', handleClickOutside);
25
+
}
26
+
27
+
return () => {
28
+
document.removeEventListener('mousedown', handleClickOutside);
29
+
};
30
+
}, [showLoginForm]);
31
+
32
+
if (loading) {
33
+
return (
34
+
<div className="flex items-center justify-center p-6 text-gray-500 dark:text-gray-400">
35
+
Loading...
36
+
</div>
37
+
);
38
+
}
39
+
40
+
if (compact) {
41
+
if (authed) {
42
+
return (
43
+
<button
44
+
onClick={logout}
45
+
className="text-sm bg-gray-600 hover:bg-gray-700 text-white rounded px-3 py-1 font-medium transition-colors"
46
+
>
47
+
Log out
48
+
</button>
49
+
);
50
+
} else {
51
+
return (
52
+
<div className="relative" ref={formRef}>
53
+
<button
54
+
onClick={() => setShowLoginForm(!showLoginForm)}
55
+
className="text-sm bg-gray-600 hover:bg-gray-700 text-white rounded px-3 py-1 font-medium transition-colors"
56
+
>
57
+
Log in
58
+
</button>
59
+
{showLoginForm && (
60
+
<div className="absolute top-full right-0 mt-2 w-80 bg-white dark:bg-gray-900 rounded-lg shadow-lg border border-gray-200 dark:border-gray-700 p-4 z-50">
61
+
<form
62
+
onSubmit={e => {
63
+
e.preventDefault();
64
+
login(user, password, `https://${serviceURL}`);
65
+
setShowLoginForm(false);
66
+
}}
67
+
className="flex flex-col gap-3"
68
+
>
69
+
<p className="text-xs text-gray-500 dark:text-gray-400">sorry for the temporary login,<br />oauth will come soon enough i swear</p>
70
+
<input
71
+
type="text"
72
+
placeholder="Username"
73
+
value={user}
74
+
onChange={e => setUser(e.target.value)}
75
+
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"
76
+
autoComplete="username"
77
+
/>
78
+
<input
79
+
type="password"
80
+
placeholder="Password"
81
+
value={password}
82
+
onChange={e => setPassword(e.target.value)}
83
+
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"
84
+
autoComplete="current-password"
85
+
/>
86
+
<input
87
+
type="text"
88
+
placeholder="bsky.social"
89
+
value={serviceURL}
90
+
onChange={e => setServiceURL(e.target.value)}
91
+
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"
92
+
/>
93
+
<button
94
+
type="submit"
95
+
className="bg-gray-600 hover:bg-gray-700 text-white rounded px-4 py-2 font-medium text-sm transition-colors"
96
+
>
97
+
Log in
98
+
</button>
99
+
</form>
100
+
</div>
101
+
)}
102
+
</div>
103
+
);
104
+
}
105
+
}
106
+
107
+
return (
108
+
<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">
109
+
{authed ? (
110
+
<div className="flex flex-col items-center justify-center text-center">
111
+
<p className="text-lg font-semibold mb-6 text-gray-800 dark:text-gray-100">You are logged in!</p>
112
+
<button
113
+
onClick={logout}
114
+
className="bg-gray-600 hover:bg-gray-700 text-white rounded px-6 py-2 font-semibold text-base transition-colors"
115
+
>
116
+
Log out
117
+
</button>
118
+
</div>
119
+
) : (
120
+
<form
121
+
onSubmit={e => {
122
+
e.preventDefault();
123
+
login(user, password, `https://${serviceURL}`);
124
+
}}
125
+
className="flex flex-col gap-4"
126
+
>
127
+
<p className="text-sm text-gray-500 dark:text-gray-400 mb-2">sorry for the temporary login,<br />oauth will come soon enough i swear</p>
128
+
<input
129
+
type="text"
130
+
placeholder="Username"
131
+
value={user}
132
+
onChange={e => setUser(e.target.value)}
133
+
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"
134
+
autoComplete="username"
135
+
/>
136
+
<input
137
+
type="password"
138
+
placeholder="Password"
139
+
value={password}
140
+
onChange={e => setPassword(e.target.value)}
141
+
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"
142
+
autoComplete="current-password"
143
+
/>
144
+
<input
145
+
type="text"
146
+
placeholder="bsky.social"
147
+
value={serviceURL}
148
+
onChange={e => setServiceURL(e.target.value)}
149
+
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"
150
+
/>
151
+
<button
152
+
type="submit"
153
+
className="bg-gray-600 hover:bg-gray-700 text-white rounded px-6 py-2 font-semibold text-base transition-colors mt-2"
154
+
>
155
+
Log in
156
+
</button>
157
+
</form>
158
+
)}
159
+
</div>
160
+
);
161
+
}
162
+
163
+
export const ProfileThing = () => {
164
+
const { agent, loading, loginStatus, authed } = useAuth();
165
+
const [response, setResponse] = useState<any>(null);
166
+
167
+
useEffect(() => {
168
+
if (loginStatus && agent && !loading && authed) {
169
+
fetchUser();
170
+
}
171
+
}, [loginStatus, agent, loading, authed]);
172
+
173
+
const fetchUser = async () => {
174
+
if (!agent) {
175
+
console.error("Agent is null or undefined");
176
+
return;
177
+
}
178
+
const res = await agent.app.bsky.actor.getProfile({
179
+
actor: agent.assertDid,
180
+
});
181
+
setResponse(res.data);
182
+
};
183
+
184
+
if (!authed) {
185
+
return (
186
+
<div className="inline-block">
187
+
<span className="text-gray-100 text-base font-medium px-1.5">Login</span>
188
+
</div>
189
+
);
190
+
}
191
+
192
+
if (!response) {
193
+
return (
194
+
<div className="flex flex-col items-start gap-1.5">
195
+
<span className="w-5 h-5 border-2 border-gray-200 dark:border-gray-600 border-t-transparent rounded-full animate-spin inline-block" />
196
+
<span className="text-gray-100">Loading... </span>
197
+
</div>
198
+
);
199
+
}
200
+
201
+
return (
202
+
<div className="flex flex-row items-start gap-1.5">
203
+
<img
204
+
src={response?.avatar}
205
+
alt="avatar"
206
+
className="w-[30px] h-[30px] rounded-full object-cover"
207
+
/>
208
+
<div>
209
+
<div className="text-gray-100 text-xs">{response?.displayName}</div>
210
+
<div className="text-gray-100 text-xs">@{response?.handle}</div>
211
+
</div>
212
+
</div>
213
+
);
214
+
};
+25
src/components/NotFound.tsx
+25
src/components/NotFound.tsx
···
1
+
import { Link } from '@tanstack/react-router'
2
+
3
+
export function NotFound({ children }: { children?: any }) {
4
+
return (
5
+
<div className="space-y-2 p-2">
6
+
<div className="text-gray-600 dark:text-gray-400">
7
+
{children || <p>The page you are looking for does not exist.</p>}
8
+
</div>
9
+
<p className="flex items-center gap-2 flex-wrap">
10
+
<button
11
+
onClick={() => window.history.back()}
12
+
className="bg-emerald-500 text-white px-2 py-1 rounded uppercase font-black text-sm"
13
+
>
14
+
Go back
15
+
</button>
16
+
<Link
17
+
to="/"
18
+
className="bg-cyan-600 text-white px-2 py-1 rounded uppercase font-black text-sm"
19
+
>
20
+
Start Over
21
+
</Link>
22
+
</p>
23
+
</div>
24
+
)
25
+
}
+5
src/components/PostError.tsx
+5
src/components/PostError.tsx
+26
src/components/Search.tsx
+26
src/components/Search.tsx
···
1
+
import { useNavigate } from '@tanstack/react-router'
2
+
import { useState } from 'react'
3
+
4
+
export function SearchBox() {
5
+
const navigate = useNavigate()
6
+
const [query, setQuery] = useState('')
7
+
8
+
function handleSubmit(e: React.FormEvent) {
9
+
e.preventDefault()
10
+
if (query.trim()) {
11
+
navigate({ to: '/search', search: { q: query.trim() } })
12
+
}
13
+
}
14
+
15
+
return (
16
+
<form onSubmit={handleSubmit} className="w-full max-w-md mx-auto">
17
+
<input
18
+
type="text"
19
+
value={query}
20
+
onChange={e => setQuery(e.target.value)}
21
+
placeholder="Search..."
22
+
className=" text-sm my-2 w-full border border-gray-500 rounded-lg px-2 py-1 focus:outline-none focus:ring text-gray-50 bg-gray-800"
23
+
/>
24
+
</form>
25
+
)
26
+
}
+5
src/components/UserError.tsx
+5
src/components/UserError.tsx
+49
src/helpers/cachedidentityresolver.ts
+49
src/helpers/cachedidentityresolver.ts
···
1
+
export type ResolvedIdentity =
2
+
| {
3
+
handle: string
4
+
did: string
5
+
pdsUrl: string
6
+
bskyPds: boolean
7
+
}
8
+
| undefined
9
+
const HANDLE_DID_CACHE_TIMEOUT = 60 * 60 * 1000; // 1 hour
10
+
export async function cachedResolveIdentity({
11
+
didOrHandle,
12
+
cacheTimeout = HANDLE_DID_CACHE_TIMEOUT,
13
+
get,
14
+
set,
15
+
}: {
16
+
didOrHandle: string;
17
+
cacheTimeout?: number;
18
+
get: (key: string) => any;
19
+
set: (key: string, value: string) => void;
20
+
}): Promise<ResolvedIdentity|undefined> {
21
+
const isDidInput = didOrHandle.startsWith("did:");
22
+
const cacheKey = `handleDid:${didOrHandle}`;
23
+
const now = Date.now();
24
+
const cached = get(cacheKey);
25
+
if (
26
+
cached &&
27
+
cached.value &&
28
+
cached.time &&
29
+
now - cached.time < cacheTimeout
30
+
) {
31
+
try {
32
+
return JSON.parse(cached.value);
33
+
} catch {}
34
+
}
35
+
const url = `https://free-fly-24.deno.dev/?${
36
+
isDidInput
37
+
? `did=${encodeURIComponent(didOrHandle)}`
38
+
: `handle=${encodeURIComponent(didOrHandle)}`
39
+
}`;
40
+
const res = await fetch(url);
41
+
if (!res.ok) throw new Error("Failed to resolve handle/did");
42
+
const data = await res.json();
43
+
set(cacheKey, JSON.stringify(data));
44
+
// also cache by did if input was handle
45
+
if (!isDidInput && data.did) {
46
+
set(`handleDid:${data.did}`, JSON.stringify(data));
47
+
}
48
+
return data;
49
+
}
+23
src/helpers/esquery.ts
+23
src/helpers/esquery.ts
···
1
+
export async function esavQuery<T = unknown>(
2
+
esQuery: object,
3
+
options?: {
4
+
endpoint?: string;
5
+
signal?: AbortSignal;
6
+
}
7
+
): Promise<T> {
8
+
const endpoint = options?.endpoint ?? "https://esav.whey.party/xrpc/com.example.prototypeESQuery";
9
+
const q = encodeURIComponent(JSON.stringify(esQuery));
10
+
const url = `${endpoint}?q=${q}`;
11
+
12
+
const res = await fetch(url, {
13
+
method: "GET",
14
+
signal: options?.signal,
15
+
});
16
+
17
+
if (!res.ok) {
18
+
const errText = await res.text();
19
+
throw new Error(`ESAV query failed: ${res.status} ${res.statusText} - ${errText}`);
20
+
}
21
+
22
+
return res.json();
23
+
}
+44
src/logo.svg
+44
src/logo.svg
···
1
+
<?xml version="1.0" encoding="UTF-8"?>
2
+
<svg id="Layer_1"
3
+
xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 841.9 595.3">
4
+
<!-- Generator: Adobe Illustrator 29.3.0, SVG Export Plug-In . SVG Version: 2.1.0 Build 146) -->
5
+
<defs>
6
+
<style>
7
+
.st0 {
8
+
fill: #9ae7fc;
9
+
}
10
+
11
+
.st1 {
12
+
fill: #61dafb;
13
+
}
14
+
</style>
15
+
</defs>
16
+
<g>
17
+
<path class="st1" d="M666.3,296.5c0-32.5-40.7-63.3-103.1-82.4,14.4-63.6,8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6,0,8.3.9,11.4,2.6,13.6,7.8,19.5,37.5,14.9,75.7-1.1,9.4-2.9,19.3-5.1,29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50,32.6-30.3,63.2-46.9,84-46.9v-22.3c-27.5,0-63.5,19.6-99.9,53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7,0,51.4,16.5,84,46.6-14,14.7-28,31.4-41.3,49.9-22.6,2.4-44,6.1-63.6,11-2.3-10-4-19.7-5.2-29-4.7-38.2,1.1-67.9,14.6-75.8,3-1.8,6.9-2.6,11.5-2.6v-22.3c-8.4,0-16,1.8-22.6,5.6-28.1,16.2-34.4,66.7-19.9,130.1-62.2,19.2-102.7,49.9-102.7,82.3s40.7,63.3,103.1,82.4c-14.4,63.6-8,114.2,20.2,130.4,6.5,3.8,14.1,5.6,22.5,5.6,27.5,0,63.5-19.6,99.9-53.6,36.4,33.8,72.4,53.2,99.9,53.2,8.4,0,16-1.8,22.6-5.6,28.1-16.2,34.4-66.7,19.9-130.1,62-19.1,102.5-49.9,102.5-82.3zm-130.2-66.7c-3.7,12.9-8.3,26.2-13.5,39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4,14.2,2.1,27.9,4.7,41,7.9zm-45.8,106.5c-7.8,13.5-15.8,26.3-24.1,38.2-14.9,1.3-30,2-45.2,2s-30.2-.7-45-1.9c-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8,6.2-13.4,13.2-26.8,20.7-39.9,7.8-13.5,15.8-26.3,24.1-38.2,14.9-1.3,30-2,45.2-2s30.2.7,45,1.9c8.3,11.9,16.4,24.6,24.2,38,7.6,13.1,14.5,26.4,20.8,39.8-6.3,13.4-13.2,26.8-20.7,39.9zm32.3-13c5.4,13.4,10,26.8,13.8,39.8-13.1,3.2-26.9,5.9-41.2,8,4.9-7.7,9.8-15.6,14.4-23.7,4.6-8,8.9-16.1,13-24.1zm-101.4,106.7c-9.3-9.6-18.6-20.3-27.8-32,9,.4,18.2.7,27.5.7s18.7-.2,27.8-.7c-9,11.7-18.3,22.4-27.5,32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9,3.7-12.9,8.3-26.2,13.5-39.5,4.1,8,8.4,16,13.1,24s9.5,15.8,14.4,23.4zm73.9-208.1c9.3,9.6,18.6,20.3,27.8,32-9-.4-18.2-.7-27.5-.7s-18.7.2-27.8.7c9-11.7,18.3-22.4,27.5-32zm-74,58.9c-4.9,7.7-9.8,15.6-14.4,23.7-4.6,8-8.9,16-13,24-5.4-13.4-10-26.8-13.8-39.8,13.1-3.1,26.9-5.8,41.2-7.9zm-90.5,125.2c-35.4-15.1-58.3-34.9-58.3-50.6s22.9-35.6,58.3-50.6c8.6-3.7,18-7,27.7-10.1,5.7,19.6,13.2,40,22.5,60.9-9.2,20.8-16.6,41.1-22.2,60.6-9.9-3.1-19.3-6.5-28-10.2zm53.8,142.9c-13.6-7.8-19.5-37.5-14.9-75.7,1.1-9.4,2.9-19.3,5.1-29.4,19.6,4.8,41,8.5,63.5,10.9,13.5,18.5,27.5,35.3,41.6,50-32.6,30.3-63.2,46.9-84,46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7,38.2-1.1,67.9-14.6,75.8-3,1.8-6.9,2.6-11.5,2.6-20.7,0-51.4-16.5-84-46.6,14-14.7,28-31.4,41.3-49.9,22.6-2.4,44-6.1,63.6-11,2.3,10.1,4.1,19.8,5.2,29.1zm38.5-66.7c-8.6,3.7-18,7-27.7,10.1-5.7-19.6-13.2-40-22.5-60.9,9.2-20.8,16.6-41.1,22.2-60.6,9.9,3.1,19.3,6.5,28.1,10.2,35.4,15.1,58.3,34.9,58.3,50.6,0,15.7-23,35.6-58.4,50.6zm-264.9-268.7z"/>
18
+
<circle class="st1" cx="420.9" cy="296.5" r="45.7"/>
19
+
<path class="st1" d="M520.5,78.1"/>
20
+
</g>
21
+
<circle class="st0" cx="420.8" cy="296.6" r="43"/>
22
+
<path class="st1" d="M466.1,296.6c0,25-20.2,45.2-45.2,45.2s-45.2-20.2-45.2-45.2,20.2-45.2,45.2-45.2,45.2,20.2,45.2,45.2ZM386,295.6v-6.3c0-1.1,1.2-5.1,1.8-6.2,1-1.9,2.9-3.5,4.6-4.7l-3.4-3.4c4-3.6,9.4-3.7,13.7-.7,1.9-4.7,6.6-7.1,11.6-6.7l-.8,4.2c5.9.2,13.1,4.1,13.1,10.8s0,.5-.7.7c-1.7.3-3.4-.4-5-.6s-1.2-.4-1.2.3,2.5,4.1,3,5.5,1,3.5.8,5.3c-5.6-.8-10.5-3.2-14.8-6.7.3,2.6,4.1,21.7,5.3,21.9s.8-.6,1-1.1,1.3-6.3,1.3-6.7c0-1-1.7-1.8-2.2-2.8-1.2-2.7,1.3-4.7,3.7-3.3s5.2,6.2,7.5,7.3,13,1.4,14.8,3.3-2.9,4.6-1.5,7.6c6.7-2.6,13.5-3.3,20.6-2.5,3.1-9.7,3.1-20.3-.9-29.8-7.3,0-14.7-3.6-17.2-10.8-2.5-7.2-.7-8.6-1.3-9.3-.8-1-6.3.6-7.4-1.5s.3-1.1-.2-1.4-1.9-.6-2.6-.8c-26-6.4-51.3,15.7-49.7,42.1,0,1.6,1.6,10.3,2.4,11.1s4.8,0,6.3,0,3.7.3,5,.5c2.9.4,7.2,2.4,9.4,2.5s2.4-.8,2.7-2.4c.4-2.6.5-7.4.5-10.1s-1-7.8-1.3-11.6c-.9-.2-.7,0-.9.5-.7,1.3-1.1,3.2-1.9,4.8s-5.2,8.7-5.7,9-.7-.5-.8-.8c-1.6-3.5-2-7.9-1.9-11.8-.9-1-5.4,4.9-6.7,5.3l-.8-.4v-.3h-.2ZM455.6,276.4c1.1-1.2-6-8.9-7.2-10-3-2.7-5.4-4.5-3.5,1.4s5.7,7.8,10.6,8.5h.1ZM410.9,270.1c-.4-.5-6.1,2.9-5.5,4.6,1.9-1.3,5.9-1.7,5.5-4.6ZM400.4,276.4c-.3-2.4-6.3-2.7-7.2-1s1.6,1.4,1.9,1.4c1.8.3,3.5-.6,5.2-.4h.1ZM411.3,276.8c3.8,1.3,6.6,3.6,10.9,3.7s0-3-1.2-3.9c-2.2-1.7-5.1-2.4-7.8-2.4s-1.6-.3-1.4.4c2.8.6,7.3.7,8.4,3.8-2.3-.3-3.9-1.6-6.2-2s-2.5-.5-2.6.3h0ZM420.6,290.3c-.8-5.1-5.7-10.8-10.9-11.6s-1.3-.4-.8.5,4.7,3.2,5.7,4,4.5,4.2,2.1,3.8-8.4-7.8-9.4-6.7c.2.9,1.1,1.9,1.7,2.7,3,3.8,6.9,6.8,11.8,7.4h-.2ZM395.3,279.8c-5,1.1-6.9,6.3-6.7,11,.7.8,5-3.8,5.4-4.5s2.7-4.6,1.1-4-2.9,4.4-4.2,4.6.2-2.1.4-2.5c1.1-1.6,2.9-3.1,4-4.6h0ZM400.4,281.5c-.4-.5-2,1.3-2.3,1.7-2.9,3.9-2.6,10.2-1.5,14.8.8.2.8-.3,1.2-.7,3-3.8,5.5-10.5,4.5-15.4-2.1,3.1-3.1,7.3-3.6,11h-1.3c0-4,1.9-7.7,3-11.4h0ZM426.9,305.9c0-1.7-1.7-1.4-2.5-1.9s-1.3-1.9-3-1.4c1.3,2.1,3,3.2,5.5,3.4h0ZM417.2,308.5c7.6.7,5.5-1.9,1.4-5.5-1.3-.3-1.5,4.5-1.4,5.5ZM437,309.7c-3.5-.3-7.8-2-11.2-2.1s-1.3,0-1.9.7c4,1.3,8.4,1.7,12.1,4l1-2.5h0ZM420.5,312.8c-7.3,0-15.1,3.7-20.4,8.8s-4.8,5.3-4.8,6.2c0,1.8,8.6,6.2,10.5,6.8,12.1,4.8,27.5,3.5,38.2-4.2s3.1-2.7,0-6.2c-5.7-6.6-14.7-11.4-23.4-11.3h-.1ZM398.7,316.9c-1.4-1.4-5-1.9-7-2.1s-5.3-.3-6.9.6l13.9,1.4h0ZM456.9,314.8h-7.4c-.9,0-4.9,1.1-6,1.6s-.8.6,0,.5c2.4,0,5.1-1,7.6-1.3s3.5.2,5.1,0,1.3-.3.6-.8h0Z"/>
23
+
<path class="st0" d="M386,295.6l.8.4c1.3-.3,5.8-6.2,6.7-5.3,0,3.9.3,8.3,1.9,11.8s0,1.2.8.8,5.1-7.8,5.7-9,1.3-3.5,1.9-4.8,0-.7.9-.5c.3,3.8,1.2,7.8,1.3,11.6s0,7.5-.5,10.1-1.1,2.4-2.7,2.4-6.5-2.1-9.4-2.5-3.7-.5-5-.5-5.4,1.1-6.3,0-2.2-9.5-2.4-11.1c-1.5-26.4,23.7-48.5,49.7-42.1s2.2.4,2.6.8,0,1,.2,1.4c1.1,2,6.5.5,7.4,1.5s.4,6.9,1.3,9.3c2.5,7.2,10,10.9,17.2,10.8,4,9.4,4,20.1.9,29.8-7.2-.7-13.9,0-20.6,2.5-1.3-3.1,4.1-5.1,1.5-7.6s-11.8-1.9-14.8-3.3-5.4-6.1-7.5-7.3-4.9.6-3.7,3.3,2.1,1.8,2.2,2.8-1,6.2-1.3,6.7-.3,1.3-1,1.1c-1.1-.3-5-19.3-5.3-21.9,4.3,3.5,9.2,5.9,14.8,6.7.2-1.9-.3-3.5-.8-5.3s-3-5.1-3-5.5c0-.8.9-.3,1.2-.3,1.6,0,3.3.8,5,.6s.7.3.7-.7c0-6.6-7.2-10.6-13.1-10.8l.8-4.2c-5.1-.3-9.6,2-11.6,6.7-4.3-3-9.8-3-13.7.7l3.4,3.4c-1.8,1.3-3.5,2.8-4.6,4.7s-1.8,5.1-1.8,6.2v6.6h.2ZM431.6,265c7.8,2.1,8.7-3.5.2-1.3l-.2,1.3ZM432.4,270.9c.3.6,6.4-.4,5.8-2.3s-4.6.6-5.7.6l-.2,1.7h.1ZM434.5,276c.8,1.2,5.7-1.8,5.5-2.7-.4-1.9-6.6,1.2-5.5,2.7ZM442.9,276.4c-.9-.9-5,2.8-4.6,4,.6,2.4,5.7-3,4.6-4ZM445.1,279.9c-.3.2-3.1,4.6-1.5,5s3.5-3.4,3.5-4-1.3-1.3-2-.9h0ZM448.9,287.4c2.1.8,3.8-5.1,2.3-5.5-1.9-.6-2.6,5.1-2.3,5.5ZM457.3,288.6c.5-1.7,1.1-4.7-1-5.5-1,.3-.6,3.9-.6,4.8l.3.5,1.3.2h0Z"/>
24
+
<path class="st0" d="M455.6,276.4c-5-.8-9.1-3.6-10.6-8.5s.5-4,3.5-1.4,8.3,8.7,7.2,10h-.1Z"/>
25
+
<path class="st0" d="M420.6,290.3c-4.9-.6-8.9-3.6-11.8-7.4s-1.5-1.8-1.7-2.7c1-1,8.5,6.6,9.4,6.7,2.4.4-1.8-3.5-2.1-3.8-1-.8-5.4-3.5-5.7-4-.4-.8.5-.5.8-.5,5.2.8,10.1,6.6,10.9,11.6h.2Z"/>
26
+
<path class="st0" d="M400.4,281.5c-1.1,3.7-3,7.3-3,11.4h1.3c.5-3.7,1.5-7.8,3.6-11,1,4.8-1.5,11.6-4.5,15.4s-.4.8-1.2.7c-1.1-4.5-1.3-10.8,1.5-14.8s1.9-2.2,2.3-1.7h0Z"/>
27
+
<path class="st0" d="M411.3,276.8c0-.8,2.1-.4,2.6-.3,2.4.4,4,1.7,6.2,2-1.2-3.1-5.7-3.2-8.4-3.8,0-.8.9-.4,1.4-.4,2.8,0,5.6.7,7.8,2.4,2.2,1.7,4,4,1.2,3.9-4.3,0-7.1-2.4-10.9-3.7h0Z"/>
28
+
<path class="st0" d="M395.3,279.8c-1.1,1.6-3,3-4,4.6s-1.9,2.8-.4,2.5,2.8-4,4.2-4.6-.9,3.6-1.1,4c-.4.7-4.7,5.2-5.4,4.5-.2-4.6,1.8-9.9,6.7-11h0Z"/>
29
+
<path class="st0" d="M437,309.7l-1,2.5c-3.6-2.3-8-2.8-12.1-4,.5-.7,1.1-.7,1.9-.7,3.4,0,7.8,1.8,11.2,2.1h0Z"/>
30
+
<path class="st0" d="M417.2,308.5c0-1,0-5.8,1.4-5.5,4,3.5,6.1,6.2-1.4,5.5Z"/>
31
+
<path class="st0" d="M400.4,276.4c-1.8-.3-3.5.7-5.2.4s-2.3-.8-1.9-1.4c.8-1.6,6.9-1.4,7.2,1h-.1Z"/>
32
+
<path class="st0" d="M410.9,270.1c.4,3-3.6,3.3-5.5,4.6-.6-1.8,5-5.1,5.5-4.6Z"/>
33
+
<path class="st0" d="M426.9,305.9c-2.5-.2-4.1-1.3-5.5-3.4,1.7-.4,2,.8,3,1.4s2.6.3,2.5,1.9h0Z"/>
34
+
<path class="st1" d="M432.4,270.9l.2-1.7c1.1,0,5.1-2.2,5.7-.6s-5.5,2.9-5.8,2.3h-.1Z"/>
35
+
<path class="st1" d="M431.6,265l.2-1.3c8.4-2.1,7.7,3.4-.2,1.3Z"/>
36
+
<path class="st1" d="M434.5,276c-1.1-1.5,5.1-4.6,5.5-2.7s-4.6,4-5.5,2.7Z"/>
37
+
<path class="st1" d="M442.9,276.4c1.1,1.1-4,6.4-4.6,4s3.7-4.9,4.6-4Z"/>
38
+
<path class="st1" d="M445.1,279.9c.7-.4,2.1,0,2,.9s-2.4,4.4-3.5,4,1.3-4.8,1.5-5h0Z"/>
39
+
<path class="st1" d="M448.9,287.4c-.3-.3.4-6.1,2.3-5.5,1.4.4-.2,6.2-2.3,5.5Z"/>
40
+
<path class="st1" d="M457.3,288.6l-1.3-.2-.3-.5c0-.9-.4-4.6.6-4.8,2.1.8,1.5,3.8,1,5.5h0Z"/>
41
+
<path class="st0" d="M420.5,312.8c8.9,0,17.9,4.7,23.4,11.3,5.6,6.6,3.8,3.5,0,6.2-10.7,7.7-26.1,9-38.2,4.2-1.9-.8-10.5-5.1-10.5-6.8s4-5.3,4.8-6.2c5.3-5,13.1-8.6,20.4-8.8h.1Z"/>
42
+
<path class="st0" d="M398.7,316.9l-13.9-1.4c1.7-1,5-.8,6.9-.6s5.6.7,7,2.1h0Z"/>
43
+
<path class="st0" d="M456.9,314.8c.7.5,0,.8-.6.8-1.6.2-3.5-.2-5.1,0-2.4.3-5.2,1.2-7.6,1.3s-1.1,0,0-.5,5.1-1.6,6-1.6h7.4,0Z"/>
44
+
</svg>
+48
src/main.tsx
+48
src/main.tsx
···
1
+
import { StrictMode } from "react";
2
+
import ReactDOM from "react-dom/client";
3
+
import { RouterProvider, createRouter } from "@tanstack/react-router";
4
+
5
+
// Import the generated route tree
6
+
import { routeTree } from "./routeTree.gen";
7
+
8
+
import "./styles.css";
9
+
import reportWebVitals from "./reportWebVitals.ts";
10
+
import { AuthProvider } from "./providers/PassAuthProvider.tsx";
11
+
import { PersistentStoreProvider } from "./providers/PersistentStoreProvider.tsx";
12
+
13
+
// Create a new router instance
14
+
const router = createRouter({
15
+
routeTree,
16
+
context: {},
17
+
defaultPreload: "intent",
18
+
scrollRestoration: true,
19
+
defaultStructuralSharing: true,
20
+
defaultPreloadStaleTime: 0,
21
+
});
22
+
23
+
// Register the router instance for type safety
24
+
declare module "@tanstack/react-router" {
25
+
interface Register {
26
+
router: typeof router;
27
+
}
28
+
}
29
+
30
+
// Render the app
31
+
const rootElement = document.getElementById("app");
32
+
if (rootElement && !rootElement.innerHTML) {
33
+
const root = ReactDOM.createRoot(rootElement);
34
+
root.render(
35
+
<StrictMode>
36
+
<PersistentStoreProvider>
37
+
<AuthProvider>
38
+
<RouterProvider router={router} />
39
+
</AuthProvider>
40
+
</PersistentStoreProvider>
41
+
</StrictMode>
42
+
);
43
+
}
44
+
45
+
// If you want to start measuring performance in your app, pass a function
46
+
// to log results (for example: reportWebVitals(console.log))
47
+
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
48
+
reportWebVitals();
+144
src/providers/PassAuthProvider.tsx
+144
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
+
}
59
+
else {
60
+
const apiAgent = new AtpAgent({ service: 'https://api.bsky.app' });
61
+
setAgent(apiAgent);
62
+
setLoginStatus(true);
63
+
setLoading(false);
64
+
setAuthed(false);
65
+
}
66
+
} catch (e) {
67
+
console.log('Failed to auto-login:', e);
68
+
} finally {
69
+
setLoading(false);
70
+
}
71
+
};
72
+
73
+
initialize();
74
+
}, [increment]);
75
+
76
+
const login = async (user: string, password: string, service: string = 'https://bsky.social') => {
77
+
try {
78
+
let sessionthing
79
+
const apiAgent = new AtpAgent({
80
+
service: service,
81
+
persistSession: (evt, sess) => {
82
+
sessionthing = sess;
83
+
},
84
+
});
85
+
await apiAgent.login({ identifier: user, password });
86
+
console.log("!!!8!!! agent logged on")
87
+
88
+
localStorage.setItem('service', service);
89
+
// await AsyncStorage.setItem('user', user);
90
+
// await AsyncStorage.setItem('password', password);
91
+
if (sessionthing) {
92
+
localStorage.setItem('sess', JSON.stringify(sessionthing));
93
+
} else {
94
+
localStorage.setItem('sess', '{}');
95
+
}
96
+
97
+
setAgent(apiAgent);
98
+
setLoginStatus(true);
99
+
setAuthed(true);
100
+
} catch (e) {
101
+
console.error('Login failed:', e);
102
+
}
103
+
};
104
+
105
+
const logout = async () => {
106
+
if (!agent) {
107
+
console.error("Agent is null or undefined");
108
+
return;
109
+
}
110
+
setLoading(true);
111
+
try {
112
+
// check if its even in async storage before removing
113
+
if (localStorage.getItem('service') && localStorage.getItem('sess')) {
114
+
localStorage.removeItem('service');
115
+
localStorage.removeItem('sess');
116
+
}
117
+
await agent.logout();
118
+
console.log("!!!8!!! agent logout")
119
+
setLoginStatus(false);
120
+
setAuthed(undefined);
121
+
await agent.com.atproto.server.deleteSession();
122
+
console.log("!!!8!!! agent deltesession")
123
+
//setAgent(null);
124
+
setIncrement(increment + 1);
125
+
} catch (e) {
126
+
console.error("Logout failed:", e);
127
+
} finally {
128
+
setLoading(false);
129
+
}
130
+
};
131
+
132
+
// why the hell are we doing this
133
+
/*if (loading) {
134
+
return <div><span>Laoding...ae</span></div>;
135
+
}*/
136
+
137
+
return (
138
+
<AuthContext.Provider value={{ agent, loginStatus, login, logout, loading, authed }}>
139
+
{children}
140
+
</AuthContext.Provider>
141
+
);
142
+
};
143
+
144
+
export const useAuth = () => useContext(AuthContext);
+51
src/providers/PersistentStoreProvider.tsx
+51
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>(null);
16
+
17
+
export const PersistentStoreProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
18
+
const get = useCallback(async (key: string): Promise<PersistentValue | null> => {
19
+
if (typeof window === 'undefined') return null;
20
+
const raw = await idbGet(key);
21
+
if (!raw) return null;
22
+
try {
23
+
return JSON.parse(raw) as PersistentValue;
24
+
} catch {
25
+
return null;
26
+
}
27
+
}, []);
28
+
29
+
const set = useCallback(async (key: string, value: string) => {
30
+
if (typeof window === 'undefined') return;
31
+
const entry: PersistentValue = { value, time: Date.now() };
32
+
await idbSet(key, JSON.stringify(entry));
33
+
}, []);
34
+
35
+
const remove = useCallback(async (key: string) => {
36
+
if (typeof window === 'undefined') return;
37
+
await idbDel(key);
38
+
}, []);
39
+
40
+
return (
41
+
<PersistentStoreContext.Provider value={{ get, set, remove }}>
42
+
{children}
43
+
</PersistentStoreContext.Provider>
44
+
);
45
+
};
46
+
47
+
export const usePersistentStore = (): PersistentStoreContextType => {
48
+
const context = useContext(PersistentStoreContext);
49
+
if (!context) throw new Error('usePersistentStore must be used within a PersistentStoreProvider');
50
+
return context;
51
+
};
+24
src/providers/StringStoreProvider.tsx
+24
src/providers/StringStoreProvider.tsx
···
1
+
import React, { createContext, useContext, useState } from 'react';
2
+
3
+
type StringStoreContextType = {
4
+
value: string;
5
+
setString: (newVal: string) => void;
6
+
};
7
+
8
+
const StringStoreContext = createContext<StringStoreContextType | null>(null);
9
+
10
+
export const StringStoreProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
11
+
const [value, setValue] = useState('');
12
+
13
+
return (
14
+
<StringStoreContext.Provider value={{ value, setString: setValue }}>
15
+
{children}
16
+
</StringStoreContext.Provider>
17
+
);
18
+
};
19
+
20
+
export const useStringStore = (): StringStoreContextType => {
21
+
const context = useContext(StringStoreContext);
22
+
if (!context) throw new Error('useStringStore must be used within a StringStoreProvider');
23
+
return context;
24
+
};
+13
src/reportWebVitals.ts
+13
src/reportWebVitals.ts
···
1
+
const reportWebVitals = (onPerfEntry?: () => void) => {
2
+
if (onPerfEntry && onPerfEntry instanceof Function) {
3
+
import('web-vitals').then(({ onCLS, onINP, onFCP, onLCP, onTTFB }) => {
4
+
onCLS(onPerfEntry)
5
+
onINP(onPerfEntry)
6
+
onFCP(onPerfEntry)
7
+
onLCP(onPerfEntry)
8
+
onTTFB(onPerfEntry)
9
+
})
10
+
}
11
+
}
12
+
13
+
export default reportWebVitals
+156
src/routeTree.gen.ts
+156
src/routeTree.gen.ts
···
1
+
/* eslint-disable */
2
+
3
+
// @ts-nocheck
4
+
5
+
// noinspection JSUnusedGlobalSymbols
6
+
7
+
// This file was automatically generated by TanStack Router.
8
+
// You should NOT make any changes in this file as it will be overwritten.
9
+
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
10
+
11
+
import { Route as rootRouteImport } from './routes/__root'
12
+
import { Route as SearchRouteImport } from './routes/search'
13
+
import { Route as IndexRouteImport } from './routes/index'
14
+
import { Route as FForumHandleRouteImport } from './routes/f/$forumHandle'
15
+
import { Route as FForumHandleIndexRouteImport } from './routes/f/$forumHandle/index'
16
+
import { Route as FForumHandleTUserHandleTopicRKeyRouteImport } from './routes/f/$forumHandle/t/$userHandle/$topicRKey'
17
+
18
+
const SearchRoute = SearchRouteImport.update({
19
+
id: '/search',
20
+
path: '/search',
21
+
getParentRoute: () => rootRouteImport,
22
+
} as any)
23
+
const IndexRoute = IndexRouteImport.update({
24
+
id: '/',
25
+
path: '/',
26
+
getParentRoute: () => rootRouteImport,
27
+
} as any)
28
+
const FForumHandleRoute = FForumHandleRouteImport.update({
29
+
id: '/f/$forumHandle',
30
+
path: '/f/$forumHandle',
31
+
getParentRoute: () => rootRouteImport,
32
+
} as any)
33
+
const FForumHandleIndexRoute = FForumHandleIndexRouteImport.update({
34
+
id: '/',
35
+
path: '/',
36
+
getParentRoute: () => FForumHandleRoute,
37
+
} as any)
38
+
const FForumHandleTUserHandleTopicRKeyRoute =
39
+
FForumHandleTUserHandleTopicRKeyRouteImport.update({
40
+
id: '/t/$userHandle/$topicRKey',
41
+
path: '/t/$userHandle/$topicRKey',
42
+
getParentRoute: () => FForumHandleRoute,
43
+
} as any)
44
+
45
+
export interface FileRoutesByFullPath {
46
+
'/': typeof IndexRoute
47
+
'/search': typeof SearchRoute
48
+
'/f/$forumHandle': typeof FForumHandleRouteWithChildren
49
+
'/f/$forumHandle/': typeof FForumHandleIndexRoute
50
+
'/f/$forumHandle/t/$userHandle/$topicRKey': typeof FForumHandleTUserHandleTopicRKeyRoute
51
+
}
52
+
export interface FileRoutesByTo {
53
+
'/': typeof IndexRoute
54
+
'/search': typeof SearchRoute
55
+
'/f/$forumHandle': typeof FForumHandleIndexRoute
56
+
'/f/$forumHandle/t/$userHandle/$topicRKey': typeof FForumHandleTUserHandleTopicRKeyRoute
57
+
}
58
+
export interface FileRoutesById {
59
+
__root__: typeof rootRouteImport
60
+
'/': typeof IndexRoute
61
+
'/search': typeof SearchRoute
62
+
'/f/$forumHandle': typeof FForumHandleRouteWithChildren
63
+
'/f/$forumHandle/': typeof FForumHandleIndexRoute
64
+
'/f/$forumHandle/t/$userHandle/$topicRKey': typeof FForumHandleTUserHandleTopicRKeyRoute
65
+
}
66
+
export interface FileRouteTypes {
67
+
fileRoutesByFullPath: FileRoutesByFullPath
68
+
fullPaths:
69
+
| '/'
70
+
| '/search'
71
+
| '/f/$forumHandle'
72
+
| '/f/$forumHandle/'
73
+
| '/f/$forumHandle/t/$userHandle/$topicRKey'
74
+
fileRoutesByTo: FileRoutesByTo
75
+
to:
76
+
| '/'
77
+
| '/search'
78
+
| '/f/$forumHandle'
79
+
| '/f/$forumHandle/t/$userHandle/$topicRKey'
80
+
id:
81
+
| '__root__'
82
+
| '/'
83
+
| '/search'
84
+
| '/f/$forumHandle'
85
+
| '/f/$forumHandle/'
86
+
| '/f/$forumHandle/t/$userHandle/$topicRKey'
87
+
fileRoutesById: FileRoutesById
88
+
}
89
+
export interface RootRouteChildren {
90
+
IndexRoute: typeof IndexRoute
91
+
SearchRoute: typeof SearchRoute
92
+
FForumHandleRoute: typeof FForumHandleRouteWithChildren
93
+
}
94
+
95
+
declare module '@tanstack/react-router' {
96
+
interface FileRoutesByPath {
97
+
'/search': {
98
+
id: '/search'
99
+
path: '/search'
100
+
fullPath: '/search'
101
+
preLoaderRoute: typeof SearchRouteImport
102
+
parentRoute: typeof rootRouteImport
103
+
}
104
+
'/': {
105
+
id: '/'
106
+
path: '/'
107
+
fullPath: '/'
108
+
preLoaderRoute: typeof IndexRouteImport
109
+
parentRoute: typeof rootRouteImport
110
+
}
111
+
'/f/$forumHandle': {
112
+
id: '/f/$forumHandle'
113
+
path: '/f/$forumHandle'
114
+
fullPath: '/f/$forumHandle'
115
+
preLoaderRoute: typeof FForumHandleRouteImport
116
+
parentRoute: typeof rootRouteImport
117
+
}
118
+
'/f/$forumHandle/': {
119
+
id: '/f/$forumHandle/'
120
+
path: '/'
121
+
fullPath: '/f/$forumHandle/'
122
+
preLoaderRoute: typeof FForumHandleIndexRouteImport
123
+
parentRoute: typeof FForumHandleRoute
124
+
}
125
+
'/f/$forumHandle/t/$userHandle/$topicRKey': {
126
+
id: '/f/$forumHandle/t/$userHandle/$topicRKey'
127
+
path: '/t/$userHandle/$topicRKey'
128
+
fullPath: '/f/$forumHandle/t/$userHandle/$topicRKey'
129
+
preLoaderRoute: typeof FForumHandleTUserHandleTopicRKeyRouteImport
130
+
parentRoute: typeof FForumHandleRoute
131
+
}
132
+
}
133
+
}
134
+
135
+
interface FForumHandleRouteChildren {
136
+
FForumHandleIndexRoute: typeof FForumHandleIndexRoute
137
+
FForumHandleTUserHandleTopicRKeyRoute: typeof FForumHandleTUserHandleTopicRKeyRoute
138
+
}
139
+
140
+
const FForumHandleRouteChildren: FForumHandleRouteChildren = {
141
+
FForumHandleIndexRoute: FForumHandleIndexRoute,
142
+
FForumHandleTUserHandleTopicRKeyRoute: FForumHandleTUserHandleTopicRKeyRoute,
143
+
}
144
+
145
+
const FForumHandleRouteWithChildren = FForumHandleRoute._addFileChildren(
146
+
FForumHandleRouteChildren,
147
+
)
148
+
149
+
const rootRouteChildren: RootRouteChildren = {
150
+
IndexRoute: IndexRoute,
151
+
SearchRoute: SearchRoute,
152
+
FForumHandleRoute: FForumHandleRouteWithChildren,
153
+
}
154
+
export const routeTree = rootRouteImport
155
+
._addFileChildren(rootRouteChildren)
156
+
._addFileTypes<FileRouteTypes>()
+13
src/routes/__root.tsx
+13
src/routes/__root.tsx
···
1
+
import Header from '@/components/Header'
2
+
import { Outlet, createRootRoute } from '@tanstack/react-router'
3
+
import { TanStackRouterDevtools } from '@tanstack/react-router-devtools'
4
+
5
+
export const Route = createRootRoute({
6
+
component: () => (
7
+
<>
8
+
<Header />
9
+
<Outlet />
10
+
<TanStackRouterDevtools />
11
+
</>
12
+
),
13
+
})
+271
src/routes/f/$forumHandle.tsx
+271
src/routes/f/$forumHandle.tsx
···
1
+
import {
2
+
cachedResolveIdentity,
3
+
type ResolvedIdentity,
4
+
} from "@/helpers/cachedidentityresolver";
5
+
import { esavQuery } from "@/helpers/esquery";
6
+
import { usePersistentStore } from "@/providers/PersistentStoreProvider";
7
+
import { createFileRoute, Link, useLoaderData, useNavigate } from "@tanstack/react-router";
8
+
import { Outlet } from "@tanstack/react-router";
9
+
import { useEffect, useState } from "react";
10
+
11
+
export const Route = createFileRoute("/f/$forumHandle")({
12
+
loader: ({ params }) => {
13
+
console.log("[loader] params.forumHandle:", params.forumHandle);
14
+
return { forumHandle: params.forumHandle };
15
+
},
16
+
component: ForumHeader,
17
+
});
18
+
19
+
type ForumDoc = {
20
+
$type: "com.example.ft.forum.definition";
21
+
$metadata: {
22
+
uri: string;
23
+
did: string;
24
+
};
25
+
displayName?: string;
26
+
description?: string;
27
+
$raw?: {
28
+
avatar?: { ref?: { $link: string } };
29
+
banner?: { ref?: { $link: string } };
30
+
};
31
+
};
32
+
33
+
function ForumHeaderContentSkeleton() {
34
+
return (
35
+
<>
36
+
<div className="w-full flex flex-col items-center pt-6">
37
+
<div className="w-full max-w-5xl rounded-2xl bg-gray-800 border border-t-0 shadow-2xl overflow-hidden">
38
+
<div className="relative w-full h-32 bg-gray-700/50">
39
+
<div className="absolute inset-0 bg-black/60" />
40
+
<div className="relative z-10 flex items-center p-6 h-full">
41
+
<div className="flex items-center gap-4 max-w-1/2">
42
+
<div className="w-16 h-16 rounded-full bg-gray-700 animate-pulse" />
43
+
<div>
44
+
<div className="h-8 w-48 bg-gray-700 rounded-md animate-pulse" />
45
+
<div className="mt-2 h-4 w-32 bg-gray-700 rounded-md animate-pulse" />
46
+
</div>
47
+
</div>
48
+
<div className="ml-auto text-end max-w-1/2 space-y-2">
49
+
<div className="h-4 w-full bg-gray-700 rounded-md animate-pulse" />
50
+
<div className="h-4 w-10/12 ml-auto bg-gray-700 rounded-md animate-pulse" />
51
+
</div>
52
+
</div>
53
+
</div>
54
+
<div className="flex items-center justify-between pl-3 pr-[6px] py-1.5">
55
+
<div className="flex flex-wrap items-center gap-3 text-sm">
56
+
{[...Array(6)].map((_, i) => (
57
+
<div key={i} className="h-5 w-20 bg-gray-700 rounded animate-pulse" />
58
+
))}
59
+
</div>
60
+
<div className="relative w-48">
61
+
<div className="h-[34px] w-full bg-gray-700 rounded-[11px] animate-pulse" />
62
+
</div>
63
+
</div>
64
+
</div>
65
+
</div>
66
+
</>
67
+
);
68
+
}
69
+
function ForumHeaderSearch() {
70
+
const navigate = useNavigate();
71
+
const [query, setQuery] = useState("");
72
+
73
+
function handleSubmit(e: React.FormEvent) {
74
+
e.preventDefault();
75
+
if (query.trim()) {
76
+
navigate({ to: "/search", search: { q: query.trim() } });
77
+
}
78
+
}
79
+
80
+
return (
81
+
<form onSubmit={handleSubmit} className="relative w-48">
82
+
<input
83
+
type="text"
84
+
value={query}
85
+
onChange={(e) => setQuery(e.target.value)}
86
+
placeholder="Search…"
87
+
className="w-full rounded-[11px] border border-gray-700 bg-gray-900 px-2.5 py-1.5 pr-9 text-sm text-gray-100 placeholder-gray-400 focus:outline-none focus:ring-1 focus:ring-blue-500"
88
+
/>
89
+
<svg
90
+
className="absolute right-2 top-2.5 h-4 w-4 text-gray-400 pointer-events-none"
91
+
xmlns="http://www.w3.org/2000/svg"
92
+
fill="none"
93
+
viewBox="0 0 24 24"
94
+
stroke="currentColor"
95
+
>
96
+
<path
97
+
strokeLinecap="round"
98
+
strokeLinejoin="round"
99
+
strokeWidth={2}
100
+
d="M21 21l-4.35-4.35M11 19a8 8 0 100-16 8 8 0 000 16z"
101
+
/>
102
+
</svg>
103
+
</form>
104
+
);
105
+
}
106
+
function ForumHeaderContent({ forumDoc, identity, forumHandle }:{ forumDoc:ForumDoc, identity: ResolvedIdentity, forumHandle: string }) {
107
+
const did = identity?.did;
108
+
const bannerCid = forumDoc?.$raw?.banner?.ref?.$link;
109
+
const avatarCid = forumDoc?.$raw?.avatar?.ref?.$link;
110
+
const bannerUrl =
111
+
did && bannerCid
112
+
? `${identity?.pdsUrl}/xrpc/com.atproto.sync.getBlob?did=${did}&cid=${bannerCid}`
113
+
: null;
114
+
const avatarUrl =
115
+
did && avatarCid
116
+
? `${identity?.pdsUrl}/xrpc/com.atproto.sync.getBlob?did=${did}&cid=${avatarCid}`
117
+
: null;
118
+
119
+
return (
120
+
<div className="w-full flex flex-col items-center pt-6">
121
+
<div className="w-full max-w-5xl rounded-2xl bg-gray-800 border border-t-0 shadow-2xl overflow-hidden">
122
+
<div className="relative w-full h-32">
123
+
{bannerUrl ? (
124
+
<div
125
+
className="absolute inset-0 bg-cover bg-center"
126
+
style={{ backgroundImage: `url(${bannerUrl})` }}
127
+
/>
128
+
) : (
129
+
<div className="absolute inset-0 bg-gray-700/50" />
130
+
)}
131
+
<div className="absolute inset-0 bg-black/60" />
132
+
<div className="relative z-10 flex items-center p-6 h-full">
133
+
<div className="flex items-center gap-4 max-w-1/2">
134
+
{/*//@ts-ignore */}
135
+
<Link to={`/f/${forumHandle}`} className="flex items-center gap-4 no-underline">
136
+
{avatarUrl ? (
137
+
<img
138
+
src={avatarUrl}
139
+
alt="Forum avatar"
140
+
className="w-16 h-16 rounded-full border border-gray-700 object-cover"
141
+
/>
142
+
) : (
143
+
<div className="w-16 h-16 rounded-full bg-gray-700 flex items-center justify-center text-gray-400">
144
+
?
145
+
</div>
146
+
)}
147
+
<div>
148
+
<div className="text-white text-3xl font-bold">
149
+
{forumDoc.displayName || "Unnamed Forum"}
150
+
</div>
151
+
<div className="text-blue-300 font-mono">
152
+
/f/{decodeURIComponent(forumHandle || "")}
153
+
</div>
154
+
</div>
155
+
</Link>
156
+
</div>
157
+
<div className="ml-auto text-gray-300 text-base text-end max-w-1/2">
158
+
{forumDoc.description || "No description provided."}
159
+
</div>
160
+
</div>
161
+
</div>
162
+
163
+
<div className="flex items-center justify-between pl-3 pr-[6px] py-1.5">
164
+
<div className="flex flex-wrap items-center gap-3 text-sm text-gray-300 font-medium">
165
+
{[
166
+
"All Topics",
167
+
"Announcements",
168
+
"General",
169
+
"Support",
170
+
"Off-topic",
171
+
"Introductions",
172
+
"Guides",
173
+
"Feedback",
174
+
].map((label) => (
175
+
<button
176
+
key={label}
177
+
className="hover:underline hover:text-white transition"
178
+
onClick={() => console.log(`Clicked ${label}`)}
179
+
>
180
+
{label}
181
+
</button>
182
+
))}
183
+
</div>
184
+
185
+
<ForumHeaderSearch />
186
+
</div>
187
+
</div>
188
+
</div>
189
+
);
190
+
}
191
+
192
+
function ForumHeader() {
193
+
const { forumHandle } = useLoaderData({
194
+
from: "/f/$forumHandle",
195
+
});
196
+
const { get, set } = usePersistentStore();
197
+
const [forumDoc, setForumDoc] = useState<ForumDoc | null>(null);
198
+
const [error, setError] = useState<string | null>(null);
199
+
const [identity, setIdentity] = useState<ResolvedIdentity | null>(null);
200
+
201
+
useEffect(() => {
202
+
setForumDoc(null);
203
+
setError(null);
204
+
setIdentity(null);
205
+
206
+
async function loadForum() {
207
+
if (!forumHandle) return;
208
+
209
+
try {
210
+
const normalizedHandle = decodeURIComponent(forumHandle).replace(
211
+
/^@/,
212
+
""
213
+
);
214
+
const identity = await cachedResolveIdentity({
215
+
didOrHandle: normalizedHandle,
216
+
get,
217
+
set,
218
+
});
219
+
setIdentity(identity);
220
+
221
+
if (!identity) throw new Error("Could not resolve forum handle");
222
+
const resolvedDid = identity.did;
223
+
//setDid(resolvedDid);
224
+
225
+
const forumRes = await esavQuery<{
226
+
hits: { hits: { _source: ForumDoc }[] };
227
+
}>({
228
+
query: {
229
+
bool: {
230
+
must: [
231
+
{ term: { "$metadata.did": resolvedDid } },
232
+
{
233
+
term: {
234
+
"$metadata.collection": "com.example.ft.forum.definition",
235
+
},
236
+
},
237
+
{ term: { "$metadata.rkey": "self" } },
238
+
],
239
+
},
240
+
},
241
+
});
242
+
243
+
const doc = forumRes.hits.hits[0]?._source;
244
+
if (!doc) throw new Error("Forum definition not found.");
245
+
246
+
setForumDoc(doc);
247
+
} catch (e) {
248
+
setError((e as Error).message);
249
+
}
250
+
}
251
+
252
+
loadForum();
253
+
}, [forumHandle, get, set]);
254
+
255
+
if (error) return <div className="text-red-500 text-center pt-10">Error: {error}</div>;
256
+
257
+
return (
258
+
<>
259
+
{!forumDoc || !identity ? (
260
+
<ForumHeaderContentSkeleton />
261
+
) : (
262
+
<ForumHeaderContent
263
+
forumDoc={forumDoc}
264
+
identity={identity}
265
+
forumHandle={forumHandle}
266
+
/>
267
+
)}
268
+
<Outlet />
269
+
</>
270
+
);
271
+
}
+652
src/routes/f/$forumHandle/index.tsx
+652
src/routes/f/$forumHandle/index.tsx
···
1
+
import {
2
+
createFileRoute,
3
+
useLoaderData,
4
+
useNavigate,
5
+
Link,
6
+
} from "@tanstack/react-router";
7
+
import { useEffect, useState } from "react";
8
+
import {
9
+
cachedResolveIdentity,
10
+
type ResolvedIdentity,
11
+
} from "@/helpers/cachedidentityresolver";
12
+
import { usePersistentStore } from "@/providers/PersistentStoreProvider";
13
+
import { esavQuery } from "@/helpers/esquery";
14
+
import * as Select from "@radix-ui/react-select";
15
+
import * as Dialog from "@radix-ui/react-dialog";
16
+
import {
17
+
ChevronDownIcon,
18
+
CheckIcon,
19
+
Cross2Icon,
20
+
} from "@radix-ui/react-icons";
21
+
import { useAuth } from "@/providers/PassAuthProvider";
22
+
import { AtUri } from "@atproto/api";
23
+
24
+
type PostDoc = {
25
+
$type: "com.example.ft.topic.post";
26
+
$metadata: {
27
+
uri: string;
28
+
did: string;
29
+
rkey: string;
30
+
indexedAt: string;
31
+
};
32
+
forum: string;
33
+
text: string;
34
+
title: string;
35
+
reply?: any;
36
+
participants?: string[];
37
+
replyCount?: number;
38
+
[key: string]: any;
39
+
};
40
+
41
+
export const Route = createFileRoute("/f/$forumHandle/")({
42
+
loader: ({ params }) => ({ forumHandle: params.forumHandle }),
43
+
component: Forum,
44
+
});
45
+
46
+
function getRelativeTimeString(input: string | Date): string {
47
+
const date = typeof input === "string" ? new Date(input) : input;
48
+
const now = new Date();
49
+
if (isNaN(date.getTime())) return "invalid date";
50
+
const diff = (date.getTime() - now.getTime()) / 1000;
51
+
const units: [Intl.RelativeTimeFormatUnit, number][] = [
52
+
["year", 31536000],["month", 2592000],["week", 604800],["day", 86400],["hour", 3600],["minute", 60],["second", 1],
53
+
];
54
+
const formatter = new Intl.RelativeTimeFormat("en", { numeric: "auto" });
55
+
for (const [unit, secondsInUnit] of units) {
56
+
const value = Math.round(diff / secondsInUnit);
57
+
if (Math.abs(value) >= 1) return formatter.format(value, unit);
58
+
}
59
+
return "just now";
60
+
}
61
+
62
+
function ForumHeaderSkeleton() {
63
+
return (
64
+
<div className="flex flex-wrap items-center justify-between mb-4 gap-4 animate-pulse">
65
+
<div className="flex items-center gap-4">
66
+
<div className="flex items-center gap-2">
67
+
<div className="h-5 w-16 bg-gray-700 rounded-md" />
68
+
<div className="h-9 w-[150px] bg-gray-900 border border-gray-700 rounded-md" />
69
+
</div>
70
+
<div className="flex items-center gap-2">
71
+
<div className="h-5 w-16 bg-gray-700 rounded-md" />
72
+
<div className="h-9 w-[150px] bg-gray-900 border border-gray-700 rounded-md" />
73
+
</div>
74
+
</div>
75
+
<div className="ml-auto h-9 w-28 bg-gray-700 rounded-md" />
76
+
</div>
77
+
);
78
+
}
79
+
function TopicRowSkeleton() {
80
+
return (
81
+
<tr className="bg-gray-800 animate-pulse">
82
+
<td className="px-4 py-3 rounded-l-lg min-w-52">
83
+
<div className="space-y-2">
84
+
<div className="h-5 w-3/4 bg-gray-700 rounded-md" />
85
+
<div className="h-4 w-full bg-gray-600 rounded-md" />
86
+
</div>
87
+
</td>
88
+
89
+
<td className="px-4 py-3">
90
+
<div className="flex -space-x-2 justify-center">
91
+
<div className="w-6 h-6 rounded-full bg-gray-700 border-2 border-gray-800" />
92
+
<div className="w-6 h-6 rounded-full bg-gray-700 border-2 border-gray-800" />
93
+
<div className="w-6 h-6 rounded-full bg-gray-700 border-2 border-gray-800" />
94
+
</div>
95
+
</td>
96
+
97
+
<td className="px-4 py-3 text-center">
98
+
<div className="w-8 h-5 bg-gray-700 rounded-md mx-auto" />
99
+
</td>
100
+
101
+
<td className="px-4 py-3 text-center">
102
+
<div className="w-10 h-5 bg-gray-700 rounded-md mx-auto" />
103
+
</td>
104
+
105
+
<td className="px-4 py-3 text-right rounded-r-lg">
106
+
<div className="flex flex-col items-end space-y-1.5">
107
+
<div className="h-4 w-24 bg-gray-700 rounded-md" />
108
+
<div className="h-3 w-20 bg-gray-600 rounded-md" />
109
+
</div>
110
+
</td>
111
+
</tr>
112
+
);
113
+
}
114
+
115
+
export function Forum({ forumHandle: propHandle }: { forumHandle?: string }) {
116
+
const navigate = useNavigate();
117
+
const { agent, loading: authLoading } = useAuth();
118
+
const { forumHandle: routeHandle } = useLoaderData({ from: "/f/$forumHandle/" });
119
+
const forumHandle = propHandle ?? routeHandle;
120
+
121
+
const { get, set } = usePersistentStore();
122
+
const [posts, setPosts] = useState<PostDoc[]>([]);
123
+
const [error, setError] = useState<string | null>(null);
124
+
const [identity, setIdentity] = useState<ResolvedIdentity | null>(null);
125
+
const [participantAvatars, setParticipantAvatars] = useState<Record<string, { avatarCid?: string; pdsUrl: string; handle?: string }>>({});
126
+
const [postAuthors, setPostAuthors] = useState<Record<string, string>>({});
127
+
const [isLoading, setIsLoading] = useState(true);
128
+
129
+
const [selectedCategory, setSelectedCategory] = useState("uncategorized");
130
+
const [sortOrder, setSortOrder] = useState("latest");
131
+
const [isModalOpen, setIsModalOpen] = useState(false);
132
+
const [newTopicTitle, setNewTopicTitle] = useState("");
133
+
const [newTopicText, setNewTopicText] = useState("");
134
+
const [isSubmitting, setIsSubmitting] = useState(false);
135
+
const [formError, setFormError] = useState<string | null>(null);
136
+
137
+
useEffect(() => {
138
+
async function loadForum() {
139
+
if (!forumHandle) return;
140
+
141
+
setIsLoading(true);
142
+
setPosts([]);
143
+
setError(null);
144
+
145
+
try {
146
+
const normalizedHandle = decodeURIComponent(forumHandle).replace(
147
+
/^@/,
148
+
""
149
+
);
150
+
const identity = await cachedResolveIdentity({
151
+
didOrHandle: normalizedHandle,
152
+
get,
153
+
set,
154
+
});
155
+
setIdentity(identity);
156
+
157
+
if (!identity) throw new Error("Could not resolve forum handle");
158
+
const resolvedDid = identity.did;
159
+
160
+
const postRes = await esavQuery<{
161
+
hits: { hits: { _source: PostDoc }[] };
162
+
}>({
163
+
query: {
164
+
bool: {
165
+
must: [
166
+
{ term: { forum: resolvedDid } },
167
+
{
168
+
term: { "$metadata.collection": "com.example.ft.topic.post" },
169
+
},
170
+
{ bool: { must_not: [{ exists: { field: "root" } }] } },
171
+
],
172
+
},
173
+
},
174
+
sort: [
175
+
{
176
+
"$metadata.indexedAt": {
177
+
order: "desc",
178
+
},
179
+
},
180
+
],
181
+
size: 100,
182
+
});
183
+
184
+
const initialPosts = postRes.hits.hits.map((h) => h._source);
185
+
186
+
const postsWithReplies = await Promise.all(
187
+
initialPosts.map(async (post) => {
188
+
const topicUri = post["$metadata.uri"];
189
+
190
+
const repliesRes = await esavQuery<{
191
+
hits: { total: { value: number } };
192
+
aggregations: {
193
+
unique_dids: { buckets: { key: string }[] };
194
+
};
195
+
}>({
196
+
size: 0,
197
+
track_total_hits: true,
198
+
query: {
199
+
bool: {
200
+
must: [{ term: { root: topicUri } }],
201
+
},
202
+
},
203
+
aggs: {
204
+
unique_dids: {
205
+
terms: {
206
+
field: "$metadata.did",
207
+
size: 10000,
208
+
},
209
+
},
210
+
},
211
+
});
212
+
213
+
const replyCount = repliesRes.hits.total.value;
214
+
const replyDids = repliesRes.aggregations.unique_dids.buckets.map(
215
+
(bucket) => bucket.key
216
+
);
217
+
218
+
const allParticipants = Array.from(
219
+
new Set([post["$metadata.did"], ...replyDids])
220
+
);
221
+
222
+
return {
223
+
...post,
224
+
replyCount: replyCount,
225
+
participants: allParticipants,
226
+
};
227
+
})
228
+
);
229
+
230
+
setPosts(postsWithReplies);
231
+
232
+
const authorsToResolve = new Set(
233
+
// @ts-ignore
234
+
postsWithReplies.map((post) => post["$metadata.did"])
235
+
);
236
+
237
+
const participantsToResolve = new Set<string>();
238
+
postsWithReplies.forEach((post) => {
239
+
post.participants?.forEach((did) => {
240
+
if (did) participantsToResolve.add(did);
241
+
});
242
+
});
243
+
244
+
const peopleToResolve = new Set<string>([
245
+
...authorsToResolve,
246
+
...participantsToResolve,
247
+
]);
248
+
249
+
const resolvedAuthors: Record<string, string> = {};
250
+
await Promise.all(
251
+
Array.from(peopleToResolve).map(async (did) => {
252
+
try {
253
+
const identity = await cachedResolveIdentity({
254
+
didOrHandle: did,
255
+
get,
256
+
set,
257
+
});
258
+
if (identity?.handle) resolvedAuthors[did] = identity.handle;
259
+
} catch {}
260
+
})
261
+
);
262
+
263
+
setPostAuthors(resolvedAuthors);
264
+
} catch (e) {
265
+
setError((e as Error).message);
266
+
} finally {
267
+
setIsLoading(false);
268
+
}
269
+
}
270
+
271
+
loadForum();
272
+
}, [forumHandle, get, set]);
273
+
274
+
useEffect(() => {
275
+
if (!agent || authLoading || posts.length === 0) return;
276
+
277
+
const fetchAvatars = async () => {
278
+
const participantsToResolve = new Set<string>();
279
+
posts.forEach((post) => {
280
+
post.participants?.forEach((did) => {
281
+
if (did) participantsToResolve.add(did);
282
+
});
283
+
});
284
+
285
+
const avatarMap: Record<
286
+
string,
287
+
{ avatarCid?: string; pdsUrl: string; handle?: string }
288
+
> = {};
289
+
290
+
await Promise.all(
291
+
Array.from(participantsToResolve).map(async (did) => {
292
+
try {
293
+
const identity = await cachedResolveIdentity({
294
+
didOrHandle: did,
295
+
get,
296
+
set,
297
+
});
298
+
if (!identity) return;
299
+
300
+
let avatarCid: string | undefined;
301
+
try {
302
+
const profile = await agent.com.atproto.repo.getRecord({
303
+
repo: did,
304
+
collection: "app.bsky.actor.profile",
305
+
rkey: "self",
306
+
});
307
+
const rejason = JSON.parse(JSON.stringify(profile, null, 2));
308
+
avatarCid = rejason.data?.value?.avatar?.ref?.["$link"];
309
+
} catch {}
310
+
311
+
avatarMap[did] = {
312
+
avatarCid,
313
+
pdsUrl: identity.pdsUrl,
314
+
handle: identity.handle,
315
+
};
316
+
} catch {}
317
+
})
318
+
);
319
+
320
+
setParticipantAvatars(avatarMap);
321
+
};
322
+
323
+
fetchAvatars();
324
+
}, [agent, authLoading, posts, get, set]);
325
+
326
+
const handleCreateTopic = async () => {
327
+
if (!agent || !agent.did || !identity) {
328
+
setFormError("You must be logged in to create a topic.");
329
+
return;
330
+
}
331
+
if (!newTopicTitle.trim() || !newTopicText.trim()) {
332
+
setFormError("Title and text cannot be empty.");
333
+
return;
334
+
}
335
+
336
+
setIsSubmitting(true);
337
+
setFormError(null);
338
+
339
+
try {
340
+
const topicRecord = {
341
+
$type: "com.example.ft.topic.post",
342
+
title: newTopicTitle,
343
+
text: newTopicText,
344
+
createdAt: new Date().toISOString(),
345
+
forum: identity.did,
346
+
};
347
+
348
+
const response = await agent.com.atproto.repo.createRecord({
349
+
repo: agent?.did,
350
+
collection: "com.example.ft.topic.post",
351
+
record: topicRecord,
352
+
});
353
+
354
+
const postUri = new AtUri(response.data.uri);
355
+
356
+
setIsModalOpen(false);
357
+
setNewTopicTitle("");
358
+
setNewTopicText("");
359
+
navigate({
360
+
to: `/f/${forumHandle}/t/${agent?.did}/${postUri.rkey}`,
361
+
});
362
+
} catch (e) {
363
+
console.error("Failed to create topic:", e);
364
+
setFormError((e as Error).message);
365
+
} finally {
366
+
setIsSubmitting(false);
367
+
}
368
+
};
369
+
370
+
if (error) return <div className="text-red-500 p-8">Error: {error}</div>;
371
+
372
+
return (
373
+
<div className="w-full flex flex-col items-center pt-6 px-4">
374
+
<div className="w-full max-w-5xl">
375
+
{isLoading ? (
376
+
<ForumHeaderSkeleton />
377
+
) : (
378
+
<div className="flex flex-wrap items-center justify-between mb-4 gap-4">
379
+
<div className="flex items-center gap-2">
380
+
<span className="text-gray-100 text-sm">Category:</span>
381
+
<Select.Root
382
+
value={selectedCategory}
383
+
onValueChange={setSelectedCategory}
384
+
>
385
+
<Select.Trigger
386
+
className="inline-flex items-center justify-between rounded-md bg-gray-900 px-3 py-2 text-sm text-gray-100 border border-gray-700 w-[150px] focus:outline-none"
387
+
aria-label="Category"
388
+
>
389
+
<Select.Value placeholder="Select category" />
390
+
<Select.Icon className="text-gray-400">
391
+
<ChevronDownIcon />
392
+
</Select.Icon>
393
+
</Select.Trigger>
394
+
<Select.Portal>
395
+
<Select.Content className="z-50 overflow-hidden rounded-md bg-gray-800 text-gray-100 shadow-lg">
396
+
<Select.Viewport className="p-1">
397
+
{["uncategorized", "general", "meta", "support"].map(
398
+
(category) => (
399
+
<Select.Item
400
+
key={category}
401
+
value={category}
402
+
className="flex items-center px-3 py-2 text-sm hover:bg-gray-700 rounded-md cursor-pointer select-none"
403
+
>
404
+
<Select.ItemIndicator className="mr-2">
405
+
<CheckIcon className="h-3 w-3 text-gray-100" />
406
+
</Select.ItemIndicator>
407
+
<Select.ItemText>{category}</Select.ItemText>
408
+
</Select.Item>
409
+
)
410
+
)}
411
+
</Select.Viewport>
412
+
</Select.Content>
413
+
</Select.Portal>
414
+
</Select.Root>
415
+
</div>
416
+
417
+
<div className="flex items-center gap-2">
418
+
<span className="text-gray-100 text-sm">Sort by:</span>
419
+
<Select.Root value={sortOrder} onValueChange={setSortOrder}>
420
+
<Select.Trigger
421
+
className="inline-flex items-center justify-between rounded-md bg-gray-900 px-3 py-2 text-sm text-gray-100 border border-gray-700 w-[150px] focus:outline-none"
422
+
aria-label="Sort"
423
+
>
424
+
<Select.Value placeholder="Sort by" />
425
+
<Select.Icon className="text-gray-400">
426
+
<ChevronDownIcon />
427
+
</Select.Icon>
428
+
</Select.Trigger>
429
+
<Select.Portal>
430
+
<Select.Content className="z-50 overflow-hidden rounded-md bg-gray-800 text-gray-100 shadow-lg">
431
+
<Select.Viewport className="p-1">
432
+
{["latest", "top", "active", "views"].map((sort) => (
433
+
<Select.Item
434
+
key={sort}
435
+
value={sort}
436
+
className="flex items-center px-3 py-2 text-sm hover:bg-gray-700 rounded-md cursor-pointer select-none"
437
+
>
438
+
<Select.ItemIndicator className="mr-2">
439
+
<CheckIcon className="h-3 w-3 text-gray-100" />
440
+
</Select.ItemIndicator>
441
+
<Select.ItemText>{sort}</Select.ItemText>
442
+
</Select.Item>
443
+
))}
444
+
</Select.Viewport>
445
+
</Select.Content>
446
+
</Select.Portal>
447
+
</Select.Root>
448
+
</div>
449
+
450
+
<Dialog.Root open={isModalOpen} onOpenChange={setIsModalOpen}>
451
+
<Dialog.Trigger asChild>
452
+
<button
453
+
className="ml-auto bg-blue-600 hover:bg-blue-500 text-white px-4 py-2 rounded-md text-sm font-semibold transition disabled:bg-gray-500"
454
+
disabled={!identity}
455
+
title={
456
+
!identity ? "Loading forum..." : "Create a new topic"
457
+
}
458
+
>
459
+
+ New Topic
460
+
</button>
461
+
</Dialog.Trigger>
462
+
<Dialog.Portal>
463
+
<Dialog.Overlay className="bg-black/60 data-[state=open]:animate-overlayShow fixed inset-0 z-50" />
464
+
<Dialog.Content className="data-[state=open]:animate-contentShow fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 z-50 w-[90vw] max-w-lg p-6 bg-gray-800 text-gray-100 rounded-lg shadow-xl focus:outline-none">
465
+
<Dialog.Title className="text-xl font-bold mb-4">
466
+
Create New Topic in @{forumHandle}
467
+
</Dialog.Title>
468
+
<Dialog.Close asChild>
469
+
<button
470
+
className="absolute top-4 right-4 text-gray-400 hover:text-white"
471
+
aria-label="Close"
472
+
>
473
+
<Cross2Icon />
474
+
</button>
475
+
</Dialog.Close>
476
+
477
+
{!agent || !agent.did ? (
478
+
<div className="text-center py-4">
479
+
<p className="text-gray-300">
480
+
You must be logged in to create a new topic.
481
+
</p>
482
+
<span className="inline-block mt-4 bg-blue-600 hover:bg-blue-500 text-white px-4 py-2 rounded-md font-semibold">
483
+
Log In
484
+
</span>
485
+
</div>
486
+
) : (
487
+
<form
488
+
onSubmit={(e) => {
489
+
e.preventDefault();
490
+
handleCreateTopic();
491
+
}}
492
+
>
493
+
<fieldset disabled={isSubmitting} className="space-y-4">
494
+
<div>
495
+
<label
496
+
htmlFor="topic-title"
497
+
className="text-sm font-medium text-gray-300 block mb-1"
498
+
>
499
+
Topic Title
500
+
</label>
501
+
<input
502
+
id="topic-title"
503
+
value={newTopicTitle}
504
+
onChange={(e) => setNewTopicTitle(e.target.value)}
505
+
className="w-full p-2 bg-gray-900 border border-gray-700 rounded-md focus:ring-2 focus:ring-blue-500 focus:outline-none"
506
+
placeholder="A short, descriptive title"
507
+
required
508
+
/>
509
+
</div>
510
+
<div>
511
+
<label
512
+
htmlFor="topic-text"
513
+
className="text-sm font-medium text-gray-300 block mb-1"
514
+
>
515
+
Topic Content
516
+
</label>
517
+
<textarea
518
+
id="topic-text"
519
+
value={newTopicText}
520
+
onChange={(e) => setNewTopicText(e.target.value)}
521
+
className="w-full p-2 bg-gray-900 border border-gray-700 rounded-md focus:ring-2 focus:ring-blue-500 focus:outline-none"
522
+
rows={8}
523
+
placeholder="Write the main content of your topic here..."
524
+
required
525
+
/>
526
+
</div>
527
+
</fieldset>
528
+
{formError && (
529
+
<p className="text-red-400 text-sm mt-2">
530
+
{formError}
531
+
</p>
532
+
)}
533
+
<div className="flex justify-end gap-4 mt-6">
534
+
<Dialog.Close asChild>
535
+
<button
536
+
type="button"
537
+
className="px-4 py-2 rounded-md bg-gray-600 hover:bg-gray-500 font-semibold"
538
+
disabled={isSubmitting}
539
+
>
540
+
Cancel
541
+
</button>
542
+
</Dialog.Close>
543
+
<button
544
+
type="submit"
545
+
className="px-4 py-2 rounded-md bg-blue-600 hover:bg-blue-500 font-semibold disabled:bg-gray-500 disabled:cursor-not-allowed"
546
+
disabled={
547
+
isSubmitting ||
548
+
!newTopicTitle.trim() ||
549
+
!newTopicText.trim()
550
+
}
551
+
>
552
+
{isSubmitting ? "Creating..." : "Create Topic"}
553
+
</button>
554
+
</div>
555
+
</form>
556
+
)}
557
+
</Dialog.Content>
558
+
</Dialog.Portal>
559
+
</Dialog.Root>
560
+
</div>
561
+
)}
562
+
563
+
<table className="w-full table-auto border-separate border-spacing-y-2">
564
+
<thead>
565
+
<tr className="text-left text-sm text-gray-400">
566
+
<th className="px-4 py-2">Topic</th>
567
+
<th className="px-4 py-2 text-center">Participants</th>
568
+
<th className="px-4 py-2 text-center">Replies</th>
569
+
<th className="px-4 py-2 text-center">Views</th>
570
+
<th className="px-4 py-2 text-right">Last Post</th>
571
+
</tr>
572
+
</thead>
573
+
<tbody>
574
+
{isLoading ? (
575
+
Array.from({ length: 10 }).map((_, i) => <TopicRowSkeleton key={i} />)
576
+
) : posts.length > 0 ? (
577
+
posts.map((post) => (
578
+
<tr
579
+
onClick={() =>
580
+
navigate({
581
+
to: `/f/${forumHandle}/t/${post?.["$metadata.did"]}/${post?.["$metadata.rkey"]}`,
582
+
})
583
+
}
584
+
key={post?.["$metadata.uri"]}
585
+
className="bg-gray-800 hover:bg-gray-700/50 rounded-lg cursor-pointer transition-colors duration-150 group relative"
586
+
>
587
+
<td className="px-4 py-3 text-white rounded-l-lg">
588
+
<Link
589
+
// @ts-ignore
590
+
to={`/f/${forumHandle}/t/${post?.["$metadata.did"]}/${post?.["$metadata.rkey"]}`}
591
+
className="stretched-link"
592
+
>
593
+
<span className="sr-only">View topic:</span>
594
+
</Link>
595
+
<div className="font-semibold text-gray-50 line-clamp-1">{post.title}</div>
596
+
<div className="text-sm text-gray-400">#general • #meta</div>
597
+
</td>
598
+
<td className="px-4 py-3">
599
+
<div className="flex -space-x-2 justify-center">
600
+
{post.participants?.slice(0, 5).map((did) => {
601
+
const participant = participantAvatars[did];
602
+
const avatarUrl =
603
+
participant?.avatarCid && participant?.pdsUrl
604
+
? `${participant.pdsUrl}/xrpc/com.atproto.sync.getBlob?did=${did}&cid=${participant.avatarCid}`
605
+
: undefined;
606
+
return (
607
+
avatarUrl ?
608
+
<img
609
+
key={did}
610
+
src={avatarUrl}
611
+
alt={`@${participant?.handle || did.slice(0, 8)}`}
612
+
className="w-6 h-6 rounded-full border-2 border-gray-800 object-cover bg-gray-700"
613
+
title={`@${participant?.handle || did.slice(0, 8)}`}
614
+
/> : <div className="w-6 h-6 rounded-full border-2 border-gray-800 bg-gray-700" />
615
+
);
616
+
})}
617
+
</div>
618
+
</td>
619
+
<td className="px-4 py-3 text-center text-gray-100 font-medium">
620
+
{post.replyCount ?? 0}
621
+
</td>
622
+
<td className="px-4 py-3 text-center text-gray-300 font-medium">
623
+
idk
624
+
</td>
625
+
<td className="px-4 py-3 text-gray-400 text-right rounded-r-lg">
626
+
<div className="text-sm">
627
+
by{" "}
628
+
<span className="text-blue-400 hover:underline">
629
+
{postAuthors[post?.["$metadata.did"]]
630
+
? `@${postAuthors[post?.["$metadata.did"]]}`
631
+
: post?.["$metadata.did"].slice(4,12)}
632
+
</span>
633
+
</div>
634
+
<div className="text-xs">
635
+
{getRelativeTimeString(post?.["$metadata.indexedAt"])}
636
+
</div>
637
+
</td>
638
+
</tr>
639
+
))
640
+
) : (
641
+
<tr>
642
+
<td colSpan={5} className="text-center text-gray-500 py-10">
643
+
No topics have been posted yet. Be the first!
644
+
</td>
645
+
</tr>
646
+
)}
647
+
</tbody>
648
+
</table>
649
+
</div>
650
+
</div>
651
+
);
652
+
}
+606
src/routes/f/$forumHandle/t/$userHandle/$topicRKey.tsx
+606
src/routes/f/$forumHandle/t/$userHandle/$topicRKey.tsx
···
1
+
import {
2
+
createFileRoute,
3
+
useLoaderData,
4
+
Link,
5
+
} from "@tanstack/react-router";
6
+
import { useEffect, useMemo, useState, useCallback } from "react";
7
+
import { useAuth } from "@/providers/PassAuthProvider";
8
+
import { usePersistentStore } from "@/providers/PersistentStoreProvider";
9
+
import { esavQuery } from "@/helpers/esquery";
10
+
import {
11
+
cachedResolveIdentity,
12
+
type ResolvedIdentity,
13
+
} from "@/helpers/cachedidentityresolver";
14
+
import AtpAgent from "@atproto/api";
15
+
import {
16
+
ArrowLeftIcon,
17
+
ChatBubbleIcon,
18
+
FaceIcon,
19
+
PlusIcon,
20
+
Cross2Icon,
21
+
} from "@radix-ui/react-icons";
22
+
import * as Popover from "@radix-ui/react-popover";
23
+
24
+
type PostDoc = {
25
+
$type: "com.example.ft.topic.post";
26
+
$metadata: {
27
+
uri: string;
28
+
cid: string;
29
+
did: string;
30
+
rkey: string;
31
+
indexedAt: string;
32
+
};
33
+
forum: string;
34
+
text: string;
35
+
title?: string;
36
+
reply?: {
37
+
root: { uri: string; cid: string };
38
+
parent: { uri: string; cid: string };
39
+
};
40
+
[key: string]: any;
41
+
};
42
+
43
+
type ReactionDoc = {
44
+
$type: "com.example.ft.topic.reaction";
45
+
reactionEmoji: string;
46
+
reactionSubject: string;
47
+
};
48
+
49
+
type AuthorInfo = ResolvedIdentity & {
50
+
avatarCid?: string;
51
+
displayName?: string;
52
+
footer?: string;
53
+
};
54
+
55
+
const EMOJI_SELECTION = ["👍", "❤️", "😂", "🔥", "🤔", "🎉", "🙏", "🤯"];
56
+
57
+
export const Route = createFileRoute(
58
+
"/f/$forumHandle/t/$userHandle/$topicRKey"
59
+
)({
60
+
loader: ({ params }) => {
61
+
return {
62
+
forumHandle: decodeURIComponent(params.forumHandle),
63
+
userHandle: decodeURIComponent(params.userHandle),
64
+
topicRKey: params.topicRKey,
65
+
};
66
+
},
67
+
component: ForumTopic,
68
+
});
69
+
70
+
export function PostCardSkeleton() {
71
+
return (
72
+
<div className="flex w-full gap-4 bg-gray-800 border border-gray-700/50 rounded-xl p-4 animate-pulse">
73
+
<div className="w-32 flex-shrink-0 space-y-3">
74
+
<div className="w-12 h-12 rounded-full bg-gray-700 mx-auto" />
75
+
<div className="h-4 w-3/4 bg-gray-700 rounded-md mx-auto" />
76
+
<div className="h-3 w-1/2 bg-gray-700 rounded-md mx-auto" />
77
+
<div className="border-t border-gray-700 pt-3 mt-3 space-y-2">
78
+
<div className="h-3 w-full bg-gray-600 rounded" />
79
+
<div className="h-3 w-10/12 bg-gray-600 rounded" />
80
+
</div>
81
+
</div>
82
+
<div className="flex-grow space-y-4">
83
+
<div className="h-4 w-28 bg-gray-700 rounded-md" />
84
+
<div className="space-y-2.5">
85
+
<div className="h-4 w-full bg-gray-600 rounded" />
86
+
<div className="h-4 w-11/12 bg-gray-600 rounded" />
87
+
<div className="h-4 w-4/5 bg-gray-600 rounded" />
88
+
</div>
89
+
<div className="flex justify-between items-center pt-2">
90
+
<div className="h-6 w-16 bg-gray-700 rounded-md" />
91
+
<div className="h-8 w-20 bg-gray-700 rounded-md" />{" "}
92
+
</div>
93
+
</div>
94
+
</div>
95
+
);
96
+
}
97
+
98
+
function TopicPageSkeleton() {
99
+
return (
100
+
<div className="w-full flex flex-col items-center pt-6 px-4">
101
+
<div className="w-full max-w-5xl space-y-4">
102
+
<div className="animate-pulse">
103
+
<div className="h-5 w-48 bg-gray-700 rounded-md" />
104
+
<div className="h-8 w-3/4 bg-gray-700 rounded-md mt-4" />
105
+
</div>
106
+
<PostCardSkeleton />
107
+
<PostCardSkeleton />
108
+
<div className="p-4 bg-gray-800 rounded-xl border border-gray-700/50 animate-pulse">
109
+
<div className="h-6 w-32 bg-gray-700 rounded-md mb-3" />
110
+
<div className="h-28 w-full bg-gray-900 border border-gray-700 rounded-md" />
111
+
<div className="flex justify-end mt-3">
112
+
<div className="h-10 w-32 bg-gray-700 rounded-md" />
113
+
</div>
114
+
</div>
115
+
</div>
116
+
</div>
117
+
);
118
+
}
119
+
120
+
function UserInfoColumn({ author }: { author: AuthorInfo | null }) {
121
+
const avatarUrl =
122
+
author?.avatarCid && author?.pdsUrl
123
+
? `${author.pdsUrl}/xrpc/com.atproto.sync.getBlob?did=${author.did}&cid=${author.avatarCid}`
124
+
: undefined;
125
+
126
+
const authorDisplayName = author?.displayName || author?.handle || "Unknown";
127
+
const authorHandle = author?.handle ? `@${author.handle}` : "did:...";
128
+
129
+
return (
130
+
<div className="w-32 flex-shrink-0 text-center text-sm text-gray-400">
131
+
{avatarUrl ? (
132
+
<img
133
+
src={avatarUrl}
134
+
alt={authorDisplayName}
135
+
className="w-12 h-12 rounded-full object-cover bg-gray-700 mx-auto"
136
+
/>
137
+
) : (
138
+
<div className="w-12 h-12 rounded-full bg-gray-700 flex items-center justify-center text-gray-400 font-bold text-2xl mx-auto">
139
+
{authorDisplayName.charAt(0)}
140
+
</div>
141
+
)}
142
+
<div className="font-bold text-[15px] text-white mt-1 break-words whitespace-normal">
143
+
{authorDisplayName}
144
+
</div>
145
+
<div className="break-words whitespace-normal">{authorHandle}</div>
146
+
{author?.footer && (
147
+
<div className="border-t border-gray-700/80 mt-4 pt-3 text-xs text-gray-500 text-left whitespace-pre-wrap break-words">
148
+
{author.footer}
149
+
</div>
150
+
)}
151
+
</div>
152
+
);
153
+
}
154
+
155
+
function Reactions({ reactions }: { reactions: ReactionDoc[] }) {
156
+
const groupedReactions = useMemo(() => {
157
+
return reactions.reduce(
158
+
(acc, reaction) => {
159
+
acc[reaction.reactionEmoji] = (acc[reaction.reactionEmoji] || 0) + 1;
160
+
return acc;
161
+
},
162
+
{} as Record<string, number>
163
+
);
164
+
}, [reactions]);
165
+
166
+
if (!reactions || reactions.length === 0) return null;
167
+
168
+
return (
169
+
<div className="flex items-center gap-2">
170
+
{Object.entries(groupedReactions).map(([emoji, count]) => (
171
+
<button
172
+
key={emoji}
173
+
className="flex items-center gap-1.5 bg-gray-700/50 hover:bg-gray-700/80 px-2 py-1 rounded-full text-sm text-gray-300 transition-colors"
174
+
>
175
+
<span>{emoji}</span>
176
+
<span className="font-semibold">{count}</span>
177
+
</button>
178
+
))}
179
+
</div>
180
+
);
181
+
}
182
+
183
+
export function PostCard({
184
+
agent,
185
+
post,
186
+
author,
187
+
reactions,
188
+
index,
189
+
onSetReplyParent,
190
+
onNewReaction,
191
+
isCreatingReaction,
192
+
}: {
193
+
agent: AtpAgent | null;
194
+
post: PostDoc;
195
+
author: AuthorInfo | null;
196
+
reactions: ReactionDoc[];
197
+
index: number;
198
+
onSetReplyParent: (post: PostDoc) => void;
199
+
onNewReaction: (post: PostDoc, emoji: string) => Promise<void>;
200
+
isCreatingReaction: boolean;
201
+
}) {
202
+
const postUri = post["$metadata.uri"];
203
+
const postDate = new Date(post["$metadata.indexedAt"]);
204
+
205
+
return (
206
+
<div
207
+
id={postUri}
208
+
className="w-full bg-gray-800 border border-gray-700/50 rounded-xl flex gap-x-4 p-1"
209
+
>
210
+
<div className="bg-gray-800/50 p-3 rounded-l-lg">
211
+
<UserInfoColumn author={author} />
212
+
</div>
213
+
214
+
<div className="flex-grow flex flex-col py-3 pr-4">
215
+
<div className="flex justify-between items-center text-xs text-gray-500 mb-4 border-b border-gray-700/50 pb-2">
216
+
<span>{postDate.toLocaleString()}</span>
217
+
<a
218
+
href={`#${postUri}`}
219
+
className="font-mono hover:underline hover:text-gray-300"
220
+
>
221
+
#{index + 1}
222
+
</a>
223
+
</div>
224
+
225
+
<div className="flex-grow">
226
+
<p className="whitespace-pre-wrap text-gray-200 text-[15px] leading-relaxed">
227
+
{post.text}
228
+
</p>
229
+
</div>
230
+
231
+
<div className="flex justify-between items-center mt-4 pt-3 border-t border-gray-700/50">
232
+
<div className="flex items-center gap-1">
233
+
<Reactions reactions={reactions} />
234
+
<Popover.Root>
235
+
<Popover.Trigger asChild>
236
+
<button
237
+
disabled={isCreatingReaction || !agent || !agent.did}
238
+
className="flex items-center justify-center w-8 h-8 bg-gray-700/50 hover:bg-gray-700/80 rounded-full text-gray-400 hover:text-white transition-colors disabled:opacity-50"
239
+
aria-label="Add reaction"
240
+
>
241
+
<FaceIcon className="w-4 h-4" />
242
+
<PlusIcon className="w-3 h-3 -ml-1.5 mt-2" />
243
+
</button>
244
+
</Popover.Trigger>
245
+
<Popover.Portal>
246
+
<Popover.Content
247
+
sideOffset={5}
248
+
className="bg-gray-900 border border-gray-700 rounded-lg p-2 z-10 shadow-lg"
249
+
>
250
+
<div className="grid grid-cols-4 gap-1">
251
+
{EMOJI_SELECTION.map((emoji) => (
252
+
<Popover.Close key={emoji} asChild>
253
+
<button
254
+
onClick={() => onNewReaction(post, emoji)}
255
+
className="text-2xl p-1.5 rounded-md hover:bg-gray-700/80 transition-colors"
256
+
aria-label={`React with ${emoji}`}
257
+
>
258
+
{emoji}
259
+
</button>
260
+
</Popover.Close>
261
+
))}
262
+
</div>
263
+
</Popover.Content>
264
+
</Popover.Portal>
265
+
</Popover.Root>
266
+
</div>
267
+
<div className="spacer flex-1" />
268
+
<button
269
+
onClick={() => onSetReplyParent(post)}
270
+
className="flex items-center gap-2 bg-blue-600/20 hover:bg-blue-600/40 text-blue-300 px-3 py-1.5 rounded-md font-semibold text-sm transition"
271
+
>
272
+
<ChatBubbleIcon />
273
+
<span>Reply</span>
274
+
</button>
275
+
</div>
276
+
</div>
277
+
</div>
278
+
);
279
+
}
280
+
281
+
export function ForumTopic() {
282
+
const { forumHandle, userHandle, topicRKey } = useLoaderData({
283
+
from: "/f/$forumHandle/t/$userHandle/$topicRKey",
284
+
});
285
+
286
+
const { agent, loading: authLoading } = useAuth();
287
+
const { get, set } = usePersistentStore();
288
+
289
+
const [posts, setPosts] = useState<PostDoc[]>([]);
290
+
const [authors, setAuthors] = useState<Record<string, AuthorInfo>>({});
291
+
const [reactions, setReactions] = useState<Record<string, ReactionDoc[]>>({});
292
+
const [error, setError] = useState<string | null>(null);
293
+
const [isLoading, setIsLoading] = useState(true);
294
+
295
+
const [replyText, setReplyText] = useState("");
296
+
const [isSubmitting, setIsSubmitting] = useState(false);
297
+
const [replyingTo, setReplyingTo] = useState<PostDoc | null>(null);
298
+
const [isCreatingReaction, setIsCreatingReaction] = useState(false);
299
+
300
+
const loadTopic = useCallback(async () => {
301
+
setError(null);
302
+
try {
303
+
const authorIdentity = await cachedResolveIdentity({
304
+
didOrHandle: userHandle,
305
+
get,
306
+
set,
307
+
});
308
+
if (!authorIdentity) throw new Error("Could not find topic author.");
309
+
const topicUri = `at://${authorIdentity.did}/com.example.ft.topic.post/${topicRKey}`;
310
+
311
+
const [postRes, repliesRes] = await Promise.all([
312
+
esavQuery<{ hits: { hits: { _source: PostDoc }[] } }>({
313
+
query: { term: { "$metadata.uri": topicUri } },
314
+
size: 1,
315
+
}),
316
+
esavQuery<{ hits: { hits: { _source: PostDoc }[] } }>({
317
+
query: { term: { root: topicUri } },
318
+
sort: [{ "$metadata.indexedAt": "asc" }],
319
+
size: 100,
320
+
}),
321
+
]);
322
+
323
+
if (postRes.hits.hits.length === 0) throw new Error("Topic not found.");
324
+
const mainPost = postRes.hits.hits[0]._source;
325
+
const fetchedReplies = repliesRes.hits.hits.map((h) => h._source);
326
+
const allPosts = [mainPost, ...fetchedReplies];
327
+
setPosts(allPosts);
328
+
329
+
const postUris = allPosts.map((p) => p["$metadata.uri"]);
330
+
const authorDids = [...new Set(allPosts.map((p) => p["$metadata.did"]))];
331
+
332
+
const [reactionsRes, footersRes, pdsProfiles] = await Promise.all([
333
+
esavQuery<{ hits: { hits: { _source: ReactionDoc }[] } }>({
334
+
query: {
335
+
bool: {
336
+
must: [
337
+
{
338
+
term: {
339
+
"$metadata.collection": "com.example.ft.topic.reaction",
340
+
},
341
+
},
342
+
{ terms: { reactionSubject: postUris } },
343
+
],
344
+
},
345
+
},
346
+
_source: ["reactionSubject", "reactionEmoji"],
347
+
size: 1000,
348
+
}),
349
+
350
+
esavQuery<{
351
+
hits: {
352
+
hits: { _source: { "$metadata.did": string; footer: string } }[];
353
+
};
354
+
}>({
355
+
query: {
356
+
bool: {
357
+
must: [
358
+
{ term: { $type: "com.example.ft.user.profile" } },
359
+
{ terms: { "$metadata.did": authorDids } },
360
+
],
361
+
},
362
+
},
363
+
_source: ["$metadata.did", "footer"],
364
+
size: authorDids.length,
365
+
}),
366
+
367
+
Promise.all(
368
+
authorDids.map(async (did) => {
369
+
if (!agent) return { did, profile: null };
370
+
try {
371
+
const res = await agent.com.atproto.repo.getRecord({
372
+
repo: did,
373
+
collection: "app.bsky.actor.profile",
374
+
rkey: "self",
375
+
});
376
+
return {
377
+
did,
378
+
profile: JSON.parse(JSON.stringify(res.data.value)),
379
+
};
380
+
} catch (e) {
381
+
return { did, profile: null };
382
+
}
383
+
})
384
+
),
385
+
]);
386
+
387
+
const reactionsByPostUri = reactionsRes.hits.hits.reduce(
388
+
(acc, hit) => {
389
+
const reaction = hit._source;
390
+
(acc[reaction.reactionSubject] = acc[reaction.reactionSubject] || []).push(reaction);
391
+
return acc;
392
+
},
393
+
{} as Record<string, ReactionDoc[]>
394
+
);
395
+
setReactions(reactionsByPostUri);
396
+
397
+
const footersByDid = footersRes.hits.hits.reduce(
398
+
(acc, hit) => {
399
+
acc[hit._source["$metadata.did"]] = hit._source.footer;
400
+
return acc;
401
+
},
402
+
{} as Record<string, string>
403
+
);
404
+
405
+
const newAuthors: Record<string, AuthorInfo> = {};
406
+
await Promise.all(
407
+
authorDids.map(async (did) => {
408
+
const identity = await cachedResolveIdentity({
409
+
didOrHandle: did,
410
+
get,
411
+
set,
412
+
});
413
+
if (!identity) return;
414
+
const pdsProfile = pdsProfiles.find((p) => p.did === did)?.profile;
415
+
newAuthors[did] = {
416
+
...identity,
417
+
displayName: pdsProfile?.displayName,
418
+
avatarCid: pdsProfile?.avatar?.ref?.["$link"],
419
+
footer: footersByDid[did],
420
+
};
421
+
})
422
+
);
423
+
setAuthors(newAuthors);
424
+
} catch (e) {
425
+
setError((e as Error).message);
426
+
}
427
+
}, [topicRKey, userHandle, get, set, agent]);
428
+
429
+
useEffect(() => {
430
+
if (!authLoading) {
431
+
setIsLoading(true);
432
+
loadTopic().finally(() => setIsLoading(false));
433
+
}
434
+
}, [authLoading, loadTopic]);
435
+
436
+
const handleSetReplyParent = (post: PostDoc) => {
437
+
setReplyingTo(post);
438
+
document.getElementById("reply-box")?.focus();
439
+
};
440
+
441
+
const handleCreateReaction = async (post: PostDoc, emoji: string) => {
442
+
if (!agent?.did || isCreatingReaction) return;
443
+
setIsCreatingReaction(true);
444
+
const postUri = post["$metadata.uri"];
445
+
try {
446
+
await agent.com.atproto.repo.createRecord({
447
+
repo: agent.did,
448
+
collection: "com.example.ft.topic.reaction",
449
+
record: {
450
+
$type: "com.example.ft.topic.reaction",
451
+
reactionEmoji: emoji,
452
+
subject: postUri,
453
+
createdAt: new Date().toISOString(),
454
+
},
455
+
});
456
+
const newReaction: ReactionDoc = {
457
+
$type: "com.example.ft.topic.reaction",
458
+
reactionEmoji: emoji,
459
+
reactionSubject: postUri,
460
+
};
461
+
setReactions((prev) => ({
462
+
...prev,
463
+
[postUri]: [...(prev[postUri] || []), newReaction],
464
+
}));
465
+
} catch (e) {
466
+
console.error("Failed to create reaction", e);
467
+
setError("Failed to post reaction. Please try again.");
468
+
} finally {
469
+
setIsCreatingReaction(false);
470
+
}
471
+
};
472
+
473
+
const handleReply = async () => {
474
+
if (!agent?.did || isSubmitting || !replyText.trim() || posts.length === 0)
475
+
return;
476
+
setIsSubmitting(true);
477
+
setError(null);
478
+
try {
479
+
const rootPost = posts[0];
480
+
const rootRef = {
481
+
uri: rootPost["$metadata.uri"],
482
+
cid: rootPost["$metadata.cid"],
483
+
};
484
+
const parentPost = replyingTo || rootPost;
485
+
const parentRef = {
486
+
uri: parentPost["$metadata.uri"],
487
+
cid: parentPost["$metadata.cid"],
488
+
};
489
+
await agent.com.atproto.repo.createRecord({
490
+
repo: agent.did,
491
+
collection: "com.example.ft.topic.post",
492
+
record: {
493
+
$type: "com.example.ft.topic.post",
494
+
text: replyText,
495
+
forum: forumHandle,
496
+
reply: { root: rootRef, parent: parentRef },
497
+
createdAt: new Date().toISOString(),
498
+
},
499
+
});
500
+
setReplyText("");
501
+
setReplyingTo(null);
502
+
await loadTopic();
503
+
} catch (e) {
504
+
setError(`Failed to post reply: ${(e as Error).message}`);
505
+
} finally {
506
+
setIsSubmitting(false);
507
+
}
508
+
};
509
+
510
+
if (isLoading) return <TopicPageSkeleton />;
511
+
if (error)
512
+
return (
513
+
<div className="text-center text-red-500 pt-20 text-lg">
514
+
Error: {error}
515
+
</div>
516
+
);
517
+
if (posts.length === 0)
518
+
return (
519
+
<div className="text-center text-gray-400 pt-20 text-lg">
520
+
Topic not found.
521
+
</div>
522
+
);
523
+
524
+
const topicPost = posts[0];
525
+
const postIndexBeingRepliedTo = replyingTo
526
+
? posts.findIndex((p) => p["$metadata.uri"] === replyingTo["$metadata.uri"])
527
+
: -1;
528
+
529
+
return (
530
+
<div className="w-full flex flex-col items-center pt-6 px-4 pb-12">
531
+
<div className="w-full max-w-5xl space-y-4">
532
+
<div>
533
+
<Link
534
+
to="/f/$forumHandle"
535
+
params={{ forumHandle }}
536
+
className="inline-flex items-center gap-2 text-sm text-blue-300 hover:text-white hover:underline transition-colors"
537
+
>
538
+
<ArrowLeftIcon />
539
+
Back to /f/{forumHandle}
540
+
</Link>
541
+
{topicPost.title && (
542
+
<h1 className="text-3xl font-bold text-gray-50 mt-4 break-words">
543
+
{topicPost.title}
544
+
</h1>
545
+
)}
546
+
</div>
547
+
548
+
{posts.map((post, index) => (
549
+
<PostCard
550
+
agent={agent}
551
+
key={post["$metadata.uri"]}
552
+
post={post}
553
+
author={authors[post["$metadata.did"]]}
554
+
reactions={reactions[post["$metadata.uri"]] || []}
555
+
index={index}
556
+
onSetReplyParent={handleSetReplyParent}
557
+
onNewReaction={handleCreateReaction}
558
+
isCreatingReaction={isCreatingReaction}
559
+
/>
560
+
))}
561
+
562
+
{agent && !authLoading && (
563
+
<div className="p-4 bg-gray-800 rounded-xl border border-gray-700/50">
564
+
<div className="flex justify-between items-center mb-2">
565
+
<h3 className="text-lg font-semibold text-gray-200">
566
+
{replyingTo ? "Write a Reply" : "Reply to Topic"}
567
+
</h3>
568
+
{replyingTo && postIndexBeingRepliedTo !== -1 && (
569
+
<div className="flex items-center gap-2 text-sm bg-gray-700/60 px-3 py-1 rounded-full">
570
+
<span className="text-gray-400">
571
+
Replying to #{postIndexBeingRepliedTo + 1}
572
+
</span>
573
+
<button
574
+
onClick={() => setReplyingTo(null)}
575
+
className="text-gray-500 hover:text-white"
576
+
aria-label="Cancel reply"
577
+
>
578
+
<Cross2Icon />
579
+
</button>
580
+
</div>
581
+
)}
582
+
</div>
583
+
<textarea
584
+
id="reply-box"
585
+
value={replyText}
586
+
onChange={(e) => setReplyText(e.target.value)}
587
+
className="w-full p-3 bg-gray-900 border border-gray-700 rounded-md text-gray-200 focus:ring-2 focus:ring-blue-500 focus:outline-none transition"
588
+
rows={5}
589
+
placeholder="Share your thoughts..."
590
+
disabled={isSubmitting}
591
+
/>
592
+
<div className="flex justify-end mt-3">
593
+
<button
594
+
onClick={handleReply}
595
+
disabled={isSubmitting || !replyText.trim() || !agent?.did}
596
+
className="bg-blue-600 hover:bg-blue-500 text-white px-5 py-2 rounded-md font-semibold transition disabled:bg-gray-600 disabled:cursor-not-allowed"
597
+
>
598
+
{isSubmitting ? "Posting..." : "Submit Reply"}
599
+
</button>
600
+
</div>
601
+
</div>
602
+
)}
603
+
</div>
604
+
</div>
605
+
);
606
+
}
+204
src/routes/index.tsx
+204
src/routes/index.tsx
···
1
+
import { createFileRoute, Link } from "@tanstack/react-router";
2
+
import { useEffect, useState } from "react";
3
+
import "../App.css";
4
+
import { esavQuery } from "@/helpers/esquery";
5
+
import { usePersistentStore } from "@/providers/PersistentStoreProvider";
6
+
import { cachedResolveIdentity } from "@/helpers/cachedidentityresolver";
7
+
8
+
type ForumDoc = {
9
+
$type: "com.example.ft.forum.definition";
10
+
$metadata: {
11
+
collection: string;
12
+
uri: string;
13
+
did: string;
14
+
};
15
+
displayName?: string;
16
+
description?: string;
17
+
$raw?: {
18
+
avatar?: {
19
+
ref?: { $link: string };
20
+
};
21
+
banner?: {
22
+
ref?: { $link: string };
23
+
};
24
+
};
25
+
[key: string]: any;
26
+
};
27
+
28
+
type ResolvedForum = ForumDoc & {
29
+
resolvedIdentity?: {
30
+
handle: string;
31
+
pdsUrl: string;
32
+
};
33
+
};
34
+
35
+
export const Route = createFileRoute("/")({
36
+
component: Home,
37
+
});
38
+
39
+
function ForumCardSkeleton() {
40
+
return (
41
+
<div className="relative bg-zinc-900 rounded-2xl overflow-hidden border border-zinc-800 shadow-sm aspect-video animate-pulse">
42
+
<div className="absolute inset-0 bg-black/60" />
43
+
44
+
<div className="relative z-10 flex flex-col justify-between h-full p-5">
45
+
<div className="flex justify-between items-start gap-4">
46
+
<div className="flex flex-col">
47
+
<div className="h-5 w-40 bg-gray-700 rounded-md mb-2" />
48
+
<div className="h-7 w-56 bg-gray-700 rounded-md" />
49
+
</div>
50
+
<div className="w-12 h-12 rounded-full bg-gray-700 flex-shrink-0" />
51
+
</div>
52
+
53
+
<div className="flex flex-col gap-2 mt-4">
54
+
<div className="h-4 w-full bg-gray-600 rounded-md" />
55
+
<div className="h-4 w-3/4 bg-gray-600 rounded-md" />
56
+
<div className="h-3 w-1/2 bg-gray-700 rounded-md mt-2" />
57
+
</div>
58
+
</div>
59
+
</div>
60
+
);
61
+
}
62
+
63
+
function Home() {
64
+
const [forums, setForums] = useState<ResolvedForum[]>([]);
65
+
const [loading, setLoading] = useState(true);
66
+
const [error, setError] = useState<string | null>(null);
67
+
const { get, set } = usePersistentStore();
68
+
69
+
useEffect(() => {
70
+
async function fetchForums() {
71
+
try {
72
+
const res = await esavQuery<{
73
+
hits: { hits: { _source: ForumDoc }[] };
74
+
}>({
75
+
query: {
76
+
bool: {
77
+
must: [
78
+
{ term: { "$metadata.collection": "com.example.ft.forum.definition" } },
79
+
{ term: { "$metadata.rkey": "self" } },
80
+
],
81
+
},
82
+
},
83
+
size: 50,
84
+
});
85
+
86
+
const rawForums = res.hits.hits.map((hit) => hit._source);
87
+
88
+
const resolvedForums = (
89
+
await Promise.all(
90
+
rawForums.map(async (forum) => {
91
+
const did = forum?.["$metadata.did"];
92
+
if (!did) return null;
93
+
try {
94
+
const identity = await cachedResolveIdentity({ didOrHandle: did, get, set });
95
+
return identity ? { ...forum, resolvedIdentity: { handle: identity.handle, pdsUrl: identity.pdsUrl } } : null;
96
+
} catch (e) {
97
+
console.warn(`Failed to resolve identity for ${did}`, e);
98
+
return null;
99
+
}
100
+
})
101
+
)
102
+
).filter(Boolean) as ResolvedForum[];
103
+
104
+
setForums(resolvedForums);
105
+
} catch (err) {
106
+
setError((err as Error).message);
107
+
} finally {
108
+
setLoading(false);
109
+
}
110
+
}
111
+
112
+
fetchForums();
113
+
}, [get, set]);
114
+
115
+
return (
116
+
<div className="w-full flex flex-col items-center">
117
+
<div className="w-full max-w-7xl flex items-center flex-col">
118
+
<div className="w-full max-w-5xl mt-4 px-4 sm:px-0">
119
+
<div>
120
+
<span className="text-gray-50 font-bold text-2xl">Forums</span>
121
+
</div>
122
+
123
+
<div className="mt-4 w-full forum-grid">
124
+
{loading ? (
125
+
Array.from({ length: 6 }).map((_, i) => <ForumCardSkeleton key={i} />)
126
+
) : error ? (
127
+
<div className="text-red-500 col-span-full text-center py-10">Error: {error}</div>
128
+
) : (
129
+
forums.map((forum) => {
130
+
const did = forum?.["$metadata.did"];
131
+
const { resolvedIdentity } = forum;
132
+
if (!resolvedIdentity) return null;
133
+
134
+
const cidBanner = forum?.$raw?.banner?.ref?.$link;
135
+
const cidAvatar = forum?.$raw?.avatar?.ref?.$link;
136
+
137
+
const bannerUrl =
138
+
cidBanner && resolvedIdentity
139
+
? `${resolvedIdentity.pdsUrl}/xrpc/com.atproto.sync.getBlob?did=${did}&cid=${cidBanner}`
140
+
: null;
141
+
142
+
const avatarUrl =
143
+
cidAvatar && resolvedIdentity
144
+
? `${resolvedIdentity.pdsUrl}/xrpc/com.atproto.sync.getBlob?did=${did}&cid=${cidAvatar}`
145
+
: null;
146
+
147
+
return (
148
+
<Link
149
+
// @ts-ignore
150
+
to={`/f/@${resolvedIdentity.handle}`}
151
+
className="block"
152
+
key={forum?.$metadata?.uri}
153
+
>
154
+
<div
155
+
key={forum?.$metadata?.uri}
156
+
className="relative bg-zinc-900 rounded-2xl overflow-hidden border border-zinc-800 shadow-sm aspect-video hover:border-blue-500/50 transition-all duration-200"
157
+
>
158
+
{bannerUrl && (
159
+
<div
160
+
className="absolute inset-0 bg-cover bg-center"
161
+
style={{ backgroundImage: `url(${bannerUrl})` }}
162
+
/>
163
+
)}
164
+
<div className="absolute inset-0 bg-black/60" />
165
+
<div className="relative z-10 flex flex-col justify-between h-full p-5">
166
+
<div className="flex justify-between items-start gap-4">
167
+
<div className="flex flex-col">
168
+
{resolvedIdentity?.handle && (
169
+
<div className="text-blue-300 text-base font-mono mb-1">
170
+
/f/@{resolvedIdentity.handle}
171
+
</div>
172
+
)}
173
+
<div className="text-white text-2xl font-bold leading-tight">
174
+
{forum.displayName || 'Unnamed Forum'}
175
+
</div>
176
+
</div>
177
+
{avatarUrl && (
178
+
<img
179
+
src={avatarUrl}
180
+
alt="Avatar"
181
+
className="w-12 h-12 rounded-full object-cover border border-zinc-700 flex-shrink-0"
182
+
/>
183
+
)}
184
+
</div>
185
+
<div className="flex flex-col gap-2 mt-4">
186
+
<div className="text-sm text-gray-200 line-clamp-2">
187
+
{forum.description || 'No description available.'}
188
+
</div>
189
+
<div className="text-xs text-gray-400 font-medium">
190
+
0 members · ~0 topics · Active a while ago
191
+
</div>
192
+
</div>
193
+
</div>
194
+
</div>
195
+
</Link>
196
+
);
197
+
})
198
+
)}
199
+
</div>
200
+
</div>
201
+
</div>
202
+
</div>
203
+
);
204
+
}
+253
src/routes/search.tsx
+253
src/routes/search.tsx
···
1
+
import {
2
+
createFileRoute,
3
+
useSearch,
4
+
useNavigate,
5
+
Link,
6
+
} from "@tanstack/react-router";
7
+
import { useEffect, useState, useCallback, useMemo } from "react";
8
+
import { useAuth } from "@/providers/PassAuthProvider";
9
+
import { usePersistentStore } from "@/providers/PersistentStoreProvider";
10
+
import { esavQuery } from "@/helpers/esquery";
11
+
import {
12
+
cachedResolveIdentity,
13
+
type ResolvedIdentity,
14
+
} from "@/helpers/cachedidentityresolver";
15
+
import AtpAgent, { AtUri } from "@atproto/api";
16
+
import { ArrowRightIcon } from "@radix-ui/react-icons";
17
+
import { PostCard, PostCardSkeleton } from "@/routes/f/$forumHandle/t/$userHandle/$topicRKey"; // Adjust path as needed
18
+
19
+
type PostDoc = {
20
+
$type: "com.example.ft.topic.post";
21
+
$metadata: { uri: string; cid: string; did: string; rkey: string; indexedAt: string; };
22
+
forum: string;
23
+
text: string;
24
+
title?: string;
25
+
reply?: { root: { uri:string; cid:string; }; parent: { uri:string; cid:string; }; };
26
+
[key: string]: any;
27
+
};
28
+
type ReactionDoc = {
29
+
$type: "com.example.ft.topic.reaction";
30
+
reactionEmoji: string;
31
+
reactionSubject: string;
32
+
};
33
+
type AuthorInfo = ResolvedIdentity & {
34
+
avatarCid?: string;
35
+
displayName?: string;
36
+
footer?: string;
37
+
};
38
+
39
+
export const Route = createFileRoute("/search")({
40
+
validateSearch: (search: Record<string, unknown>) => ({ q: typeof search.q === "string" ? search.q : "" }),
41
+
component: SearchPage,
42
+
});
43
+
44
+
interface SearchResultCardProps {
45
+
agent: AtpAgent | null;
46
+
post: PostDoc;
47
+
author: AuthorInfo | null;
48
+
reactions: ReactionDoc[];
49
+
index: number;
50
+
onNewReaction: (post: PostDoc, emoji: string) => Promise<void>;
51
+
isCreatingReaction: boolean;
52
+
}
53
+
54
+
function SearchResultCard({ post, ...rest }: SearchResultCardProps) {
55
+
const navigate = useNavigate();
56
+
const [forumHandle, setForumHandle] = useState<string | undefined>(undefined)
57
+
const { get, set } = usePersistentStore();
58
+
59
+
const rootUri = useMemo(() => post.root || post["$metadata.uri"], [post]);
60
+
const postUri = post["$metadata.uri"];
61
+
62
+
const [threadLink, setThreadLink] = useState<{ to: string, hash: string } | null>(null);
63
+
64
+
useEffect(() => {
65
+
let isCancelled = false;
66
+
const buildLink = async () => {
67
+
try {
68
+
const rootAtUri = new AtUri(rootUri);
69
+
const authorIdentity = await cachedResolveIdentity({ didOrHandle: rootAtUri.hostname, get, set });
70
+
setForumHandle("@"+authorIdentity?.handle)
71
+
if (!isCancelled && authorIdentity?.handle) {
72
+
setThreadLink({
73
+
to: '/f/$forumHandle/t/$userHandle/$topicRKey',
74
+
hash: postUri,
75
+
});
76
+
}
77
+
} catch(e) {
78
+
console.error("Failed to build thread link for search result", e)
79
+
}
80
+
};
81
+
buildLink();
82
+
return () => { isCancelled = true; };
83
+
}, [rootUri, postUri, get, set]);
84
+
85
+
const handleNavigateToPost = () => {
86
+
if (!threadLink) return;
87
+
const rootAtUri = new AtUri(rootUri);
88
+
const authorIdentity = authors[rootAtUri.hostname];
89
+
if (!authorIdentity?.handle) return;
90
+
91
+
navigate({
92
+
to: threadLink.to,
93
+
params: {
94
+
forumHandle: post.forum,
95
+
userHandle: authorIdentity.handle,
96
+
topicRKey: rootAtUri.rkey,
97
+
},
98
+
hash: threadLink.hash
99
+
});
100
+
};
101
+
102
+
return (
103
+
<div className="bg-gray-800/50 border border-gray-700/50 rounded-xl">
104
+
<div className="flex justify-between items-center px-4 py-2.5 border-b border-gray-700/50">
105
+
<span className="text-sm text-gray-400">
106
+
From forum:{" "}
107
+
<Link
108
+
to="/f/$forumHandle"
109
+
params={{ forumHandle: post.forum }}
110
+
className="font-semibold text-blue-300 hover:underline"
111
+
>
112
+
/f/{forumHandle || post.root}
113
+
</Link>
114
+
</span>
115
+
{threadLink ? (
116
+
<Link
117
+
to={threadLink.to}
118
+
params={{
119
+
forumHandle: post.forum,
120
+
userHandle: authors[new AtUri(rootUri).hostname]?.handle || '', // Needs pre-fetched author handle
121
+
topicRKey: new AtUri(rootUri).rkey
122
+
}}
123
+
hash={threadLink.hash}
124
+
className="flex items-center gap-2 text-sm font-semibold text-blue-300 hover:text-white transition-colors"
125
+
>
126
+
View Full Thread <ArrowRightIcon />
127
+
</Link>
128
+
) : (
129
+
<span className="flex items-center gap-2 text-sm font-semibold text-gray-500">
130
+
View Full Thread <ArrowRightIcon />
131
+
</span>
132
+
)}
133
+
</div>
134
+
135
+
<PostCard
136
+
{...rest}
137
+
post={post}
138
+
onSetReplyParent={handleNavigateToPost}
139
+
/>
140
+
</div>
141
+
);
142
+
}
143
+
144
+
let authors: Record<string, AuthorInfo> = {};
145
+
146
+
export function SearchPage() {
147
+
const { q } = useSearch({ from: "/search" });
148
+
149
+
const { agent, loading: authLoading } = useAuth();
150
+
const { get, set } = usePersistentStore();
151
+
152
+
const [results, setResults] = useState<PostDoc[]>([]);
153
+
const [reactions, setReactions] = useState<Record<string, ReactionDoc[]>>({});
154
+
const [_authors, setAuthors] = useState<Record<string, AuthorInfo>>({});
155
+
const [error, setError] = useState<string | null>(null);
156
+
const [isLoading, setIsLoading] = useState(false);
157
+
const [isCreatingReaction, setIsCreatingReaction] = useState(false);
158
+
159
+
useEffect(() => {
160
+
authors = _authors;
161
+
}, [_authors]);
162
+
163
+
const performSearch = useCallback(async (query: string) => {
164
+
if (!query.trim()) { setResults([]); return; }
165
+
setIsLoading(true);
166
+
setError(null);
167
+
setResults([]);
168
+
setAuthors({});
169
+
setReactions({});
170
+
try {
171
+
const searchRes = await esavQuery<{ hits: { hits: { _source: PostDoc }[] } }>({
172
+
query: { bool: { must: { multi_match: { query: query, fields: ["text", "title^2"], }, }, filter: [ { term: { "$metadata.collection": "com.example.ft.topic.post" } }, ], }, },
173
+
sort: [ { _score: "desc" }, { "$metadata.indexedAt": "desc" } ],
174
+
size: 25,
175
+
});
176
+
const foundPosts = searchRes.hits.hits.map((hit) => hit._source);
177
+
if (foundPosts.length === 0) { setIsLoading(false); return; }
178
+
setResults(foundPosts);
179
+
180
+
const allUris = foundPosts.flatMap(p => [p["$metadata.uri"], p.reply?.root.uri]).filter(Boolean) as string[];
181
+
const uniqueUris = [...new Set(allUris)];
182
+
const allDids = [...new Set(uniqueUris.map(uri => new AtUri(uri).hostname))];
183
+
184
+
const [reactionsRes, footersRes, pdsProfiles] = await Promise.all([
185
+
esavQuery<{ hits: { hits: { _source: ReactionDoc }[] } }>({ query: { bool: { must: [{ term: { "$metadata.collection": "com.example.ft.topic.reaction" } }], filter: [{ terms: { reactionSubject: allUris.filter(u => u.includes('post')) } }], }, }, _source: ["reactionSubject", "reactionEmoji"], size: 1000, }),
186
+
esavQuery<{ hits: { hits: { _source: { "$metadata.did": string; footer: string } }[] } }>({ query: { bool: { must: [{ term: { $type: "com.example.ft.user.profile" } }], filter: [{ terms: { "$metadata.did": allDids } }], }, }, _source: ["$metadata.did", "footer"], size: allDids.length, }),
187
+
Promise.all(allDids.map(async (did) => { if (!agent) return { did, profile: null }; try { const res = await agent.com.atproto.repo.getRecord({ repo: did, collection: "app.bsky.actor.profile", rkey: "self", }); return { did, profile: JSON.parse(JSON.stringify(res.data.value)) }; } catch (e) { return { did, profile: null }; } })),
188
+
]);
189
+
190
+
const reactionsByPostUri = reactionsRes.hits.hits.reduce((acc, hit) => { const r = hit._source; (acc[r.reactionSubject] = acc[r.reactionSubject] || []).push(r); return acc; }, {} as Record<string, ReactionDoc[]>);
191
+
setReactions(reactionsByPostUri);
192
+
193
+
const footersByDid = footersRes.hits.hits.reduce((acc, hit) => { acc[hit._source["$metadata.did"]] = hit._source.footer; return acc; }, {} as Record<string, string>);
194
+
195
+
const newAuthors: Record<string, AuthorInfo> = {};
196
+
await Promise.all(allDids.map(async (did) => {
197
+
const identity = await cachedResolveIdentity({ didOrHandle: did, get, set });
198
+
if (!identity) return;
199
+
const pdsProfile = pdsProfiles.find((p) => p.did === did)?.profile;
200
+
newAuthors[did] = { ...identity, displayName: pdsProfile?.displayName, avatarCid: pdsProfile?.avatar?.ref?.["$link"], footer: footersByDid[did], };
201
+
}));
202
+
setAuthors(newAuthors);
203
+
} catch (e) { console.error("Search failed:", e); setError("An error occurred during the search."); } finally { setIsLoading(false); }
204
+
}, [agent, get, set]);
205
+
206
+
useEffect(() => {
207
+
if (!authLoading) performSearch(q);
208
+
}, [q, authLoading, performSearch]);
209
+
210
+
const handleCreateReaction = async (post: PostDoc, emoji: string) => {
211
+
if (!agent?.did || isCreatingReaction) return;
212
+
setIsCreatingReaction(true);
213
+
const postUri = post["$metadata.uri"];
214
+
try {
215
+
await agent.com.atproto.repo.createRecord({ repo: agent.did, collection: "com.example.ft.topic.reaction", record: { $type: "com.example.ft.topic.reaction", reactionEmoji: emoji, subject: postUri, createdAt: new Date().toISOString(), }, });
216
+
const newReaction: ReactionDoc = { $type: "com.example.ft.topic.reaction", reactionEmoji: emoji, reactionSubject: postUri };
217
+
setReactions((prev) => ({ ...prev, [postUri]: [...(prev[postUri] || []), newReaction] }));
218
+
} catch (e) { console.error("Failed to create reaction", e); setError("Failed to post reaction."); } finally { setIsCreatingReaction(false); }
219
+
};
220
+
221
+
const renderContent = () => {
222
+
if (isLoading) return <div className="space-y-4">{Array.from({ length: 3 }).map((_, i) => <PostCardSkeleton key={i} />)}</div>;
223
+
if (error) return <div className="text-center text-red-400 p-8">{error}</div>;
224
+
if (!q.trim()) return <div className="text-center text-gray-400 p-8">Enter a search term to begin.</div>;
225
+
if (results.length === 0) return <div className="text-center text-gray-400 p-8">No results found for "{q}".</div>;
226
+
return (
227
+
<div className="space-y-4">
228
+
{results.map((post, index) => (
229
+
<SearchResultCard
230
+
agent={agent}
231
+
key={post["$metadata.uri"]}
232
+
post={post}
233
+
author={_authors[post["$metadata.did"]] || null}
234
+
reactions={reactions[post["$metadata.uri"]] || []}
235
+
index={index}
236
+
onNewReaction={handleCreateReaction}
237
+
isCreatingReaction={isCreatingReaction}
238
+
/>
239
+
))}
240
+
</div>
241
+
);
242
+
};
243
+
244
+
return (
245
+
<div className="w-full flex flex-col items-center pt-6 px-4 pb-12">
246
+
<div className="w-full max-w-5xl space-y-4">
247
+
<h1 className="text-2xl font-bold text-gray-100 mb-2">Search Results</h1>
248
+
{q && <p className="text-gray-400">Showing results for: <span className="font-semibold text-gray-200">"{q}"</span></p>}
249
+
<div className="mt-6">{renderContent()}</div>
250
+
</div>
251
+
</div>
252
+
);
253
+
}
+14
src/styles.css
+14
src/styles.css
···
1
+
2
+
body {
3
+
margin: 0;
4
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
5
+
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
6
+
sans-serif;
7
+
-webkit-font-smoothing: antialiased;
8
+
-moz-osx-font-smoothing: grayscale;
9
+
}
10
+
11
+
code {
12
+
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
13
+
monospace;
14
+
}
+28
tsconfig.json
+28
tsconfig.json
···
1
+
{
2
+
"include": ["**/*.ts", "**/*.tsx"],
3
+
"compilerOptions": {
4
+
"target": "ES2022",
5
+
"jsx": "react-jsx",
6
+
"module": "ESNext",
7
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
8
+
"types": ["vite/client"],
9
+
10
+
/* Bundler mode */
11
+
"moduleResolution": "bundler",
12
+
"allowImportingTsExtensions": true,
13
+
"verbatimModuleSyntax": true,
14
+
"noEmit": true,
15
+
16
+
/* Linting */
17
+
"skipLibCheck": true,
18
+
"strict": true,
19
+
"noUnusedLocals": true,
20
+
"noUnusedParameters": true,
21
+
"noFallthroughCasesInSwitch": true,
22
+
"noUncheckedSideEffectImports": true,
23
+
"baseUrl": ".",
24
+
"paths": {
25
+
"@/*": ["./src/*"],
26
+
}
27
+
}
28
+
}
+19
vite.config.ts
+19
vite.config.ts
···
1
+
import { defineConfig } from 'vite'
2
+
import viteReact from '@vitejs/plugin-react'
3
+
import { TanStackRouterVite } from '@tanstack/router-plugin/vite'
4
+
import { resolve } from 'node:path'
5
+
import tailwindcss from "@tailwindcss/vite";
6
+
7
+
// https://vitejs.dev/config/
8
+
export default defineConfig({
9
+
plugins: [tailwindcss(),TanStackRouterVite({ autoCodeSplitting: true }), viteReact()],
10
+
test: {
11
+
globals: true,
12
+
environment: 'jsdom',
13
+
},
14
+
resolve: {
15
+
alias: {
16
+
'@': resolve(__dirname, './src'),
17
+
},
18
+
},
19
+
})