feature: add portal server ui library

Hee Sung Son committed Nov 18, 2025 at 12:31 UTC bca1e72ee435ac9ac0a48ae9562237f8301f7ecb
45 files changed +6908 -91
.gitignore
+2
@@ -12,6 +12,8 @@ chat
12
13 cmd/relay-server/dist/*
14 !cmd/relay-server/dist/.gitkeep
15 +cmd/relay-server/app/*
16 +!cmd/relay-server/app/.gitkeep
17
18 # Test binary, built with `go test -c`
19 *.test
Dockerfile
+1 -1
@@ -26,7 +26,7 @@ COPY . .
26
27 RUN --mount=type=cache,target=/go/pkg/mod \
28 --mount=type=cache,target=/root/.cache/go-build \
29 - make build-wasm compress-wasm
29 + make build-wasm
30
31 ARG TARGETPLATFORM
32 ARG TARGETOS
Makefile
+25 -2
@@ -1,6 +1,20 @@
1 SHELL := /bin/sh
2
3 -.PHONY: run build build-wasm compress-wasm build-server clean
3 +.PHONY: help run build build-wasm compress-wasm build-frontend build-server clean
4 +
5 +.DEFAULT_GOAL := help
6 +
7 +help:
8 + @echo "Available targets:"
9 + @echo " make build - Build everything (protoc, wasm, frontend, server, tunnel)"
10 + @echo " make build-protoc - Generate Go code from protobuf definitions"
11 + @echo " make build-wasm - Build WASM client with optimization"
12 + @echo " make compress-wasm - Compress WASM with brotli"
13 + @echo " make build-frontend - Build React frontend (Tailwind CSS 4)"
14 + @echo " make build-server - Build Go relay server (includes frontend build)"
15 + @echo " make build-tunnel - Build Portal Tunnel CLI"
16 + @echo " make run - Run relay server"
17 + @echo " make clean - Remove build artifacts"
18
19 run:
20 ./bin/relay-server
@@ -48,6 +62,7 @@ build-wasm:
62 @cp cmd/webclient/portal.mp4 cmd/relay-server/dist/portal.mp4
63
64 @echo "[wasm] build complete"
65 + @make compress-wasm
66
67 # Precompress content-addressed WASM with brotli
68 compress-wasm:
@@ -66,8 +81,15 @@ compress-wasm:
81 rm -f "$$WASM_FILE"; \
82 echo "[wasm] brotli: cmd/relay-server/dist/$$WASM_HASH.wasm.br"
83
84 +
85 +# Build React frontend with Tailwind CSS 4
86 +build-frontend:
87 + @echo "[frontend] building React frontend..."
88 + @cd cmd/relay-server/frontend && npm run build
89 + @echo "[frontend] build complete"
90 +
91 # Build Go relay server (embeds WASM from cmd/relay-server/static)
70 -build-server:
92 +build-server: build-frontend
93 @echo "[server] building Go portal..."
94 CGO_ENABLED=0 go build -trimpath -ldflags "-s -w" -o bin/relay-server ./cmd/relay-server
95
@@ -78,3 +100,4 @@ build-tunnel:
100
101 clean:
102 rm -rf bin
103 + rm -rf app
cmd/relay-server/app/.gitkeep
cmd/relay-server/frontend.go
+109 -12
@@ -10,11 +10,15 @@ import (
10 "sync"
11
12 "github.com/rs/zerolog/log"
13 + "gosuda.org/portal/portal"
14 )
15
16 //go:embed dist/*
17 var wasmFS embed.FS
18
19 +//go:embed app/*
20 +var appFS embed.FS
21 +
22 // portalHost is the host for portal frontend.
23 var portalHost = "localhost"
24
@@ -144,7 +148,7 @@ func createPortalMux() *http.ServeMux {
148
149 // Special handling for manifest.json - generate dynamically
150 if path == "manifest.json" {
147 - serveDynamicManifest(w, r)
151 + serveDynamicManifest(w)
152 return
153 }
154
@@ -170,6 +174,59 @@ func createPortalMux() *http.ServeMux {
174 return mux
175 }
176
177 +// servePortalHTMLWithSSR serves portal.html with SSR data injection
178 +func servePortalHTMLWithSSR(w http.ResponseWriter, r *http.Request, serv *portal.RelayServer) {
179 + setCORSHeaders(w)
180 +
181 + // Read portal.html from embedded FS
182 + fullPath := pathpkg.Join("app", "portal.html")
183 + htmlContent, err := appFS.ReadFile(fullPath)
184 + if err != nil {
185 + log.Error().Err(err).Msg("Failed to read portal.html")
186 + http.NotFound(w, r)
187 + return
188 + }
189 +
190 + // Inject SSR data
191 + injectedHTML := injectServerData(string(htmlContent), serv)
192 +
193 + // Set headers
194 + w.Header().Set("Content-Type", "text/html; charset=utf-8")
195 + w.Header().Set("Cache-Control", "no-cache, must-revalidate")
196 +
197 + // Send response
198 + w.WriteHeader(http.StatusOK)
199 + w.Write([]byte(injectedHTML))
200 +
201 + log.Debug().Msg("Served portal.html with SSR data")
202 +}
203 +
204 +// injectServerData injects server data into HTML for SSR
205 +func injectServerData(htmlContent string, serv *portal.RelayServer) string {
206 + // Get server data from lease manager
207 + rows := convertLeaseEntriesToRows(serv)
208 +
209 + // Marshal to JSON
210 + jsonData, err := json.Marshal(rows)
211 + if err != nil {
212 + log.Error().Err(err).Msg("Failed to marshal server data for SSR")
213 + jsonData = []byte("[]")
214 + }
215 +
216 + // Create SSR script tag
217 + ssrScript := `<script id="__SSR_DATA__" type="application/json">` + string(jsonData) + `</script>`
218 +
219 + // Inject before </head> tag
220 + injected := strings.Replace(htmlContent, "</head>", ssrScript+"\n</head>", 1)
221 +
222 + log.Debug().
223 + Int("rows", len(rows)).
224 + Int("jsonSize", len(jsonData)).
225 + Msg("Injected SSR data into HTML")
226 +
227 + return injected
228 +}
229 +
230 // servePortalStaticFile serves static files for portal frontend with caching
231 func servePortalStaticFile(w http.ResponseWriter, r *http.Request, filePath string) {
232 // Check if this is a content-addressed WASM file
@@ -194,7 +251,26 @@ func serveCompressedWasm(w http.ResponseWriter, r *http.Request, filePath string
251
252 if !ok {
253 log.Debug().Str("path", filePath).Msg("WASM file not in cache")
197 - http.NotFound(w, r)
254 + // Fallback: try to serve uncompressed WASM from embedded FS
255 + fullPath := pathpkg.Join("dist", filePath)
256 + data, err := wasmFS.ReadFile(fullPath)
257 + if err != nil {
258 + log.Debug().Err(err).Str("path", fullPath).Msg("WASM file not found in embedded FS")
259 + http.NotFound(w, r)
260 + return
261 + }
262 +
263 + // Serve uncompressed WASM
264 + setCORSHeaders(w)
265 + w.Header().Set("Cache-Control", "public, max-age=31536000, immutable")
266 + w.Header().Set("Content-Type", "application/wasm")
267 + w.Header().Set("Content-Length", strconv.Itoa(len(data)))
268 + w.WriteHeader(http.StatusOK)
269 + w.Write(data)
270 + log.Debug().
271 + Str("path", filePath).
272 + Int("size", len(data)).
273 + Msg("served uncompressed WASM from embedded FS")
274 return
275 }
276
@@ -227,22 +303,30 @@ func serveCompressedWasm(w http.ResponseWriter, r *http.Request, filePath string
303 Msg("served compressed WASM")
304 }
305
230 -// serveAdminStatic serves static files for admin UI from embedded FS
231 -func serveAdminStatic(w http.ResponseWriter, r *http.Request, path string) {
306 +// serveAppStatic serves static files for app UI (React app) from embedded FS
307 +// Falls back to portal.html with SSR when path is root or file not found
308 +func serveAppStatic(w http.ResponseWriter, r *http.Request, path string, serv *portal.RelayServer) {
309 // Prevent directory traversal
310 if strings.Contains(path, "..") {
311 http.Error(w, "Invalid path", http.StatusBadRequest)
312 return
313 }
314
238 - // Try to read from embedded FS
315 setCORSHeaders(w)
316
241 - fullPath := pathpkg.Join("static", path)
242 - data, err := assetsFS.ReadFile(fullPath)
317 + // If path is empty or "/", serve portal.html with SSR
318 + if path == "" || path == "/" {
319 + servePortalHTMLWithSSR(w, r, serv)
320 + return
321 + }
322 +
323 + // Try to read from embedded FS
324 + fullPath := pathpkg.Join("app", path)
325 + data, err := appFS.ReadFile(fullPath)
326 if err != nil {
244 - log.Debug().Err(err).Str("path", path).Msg("admin static file not found")
245 - http.NotFound(w, r)
327 + // File not found - fallback to portal.html with SSR for SPA routing
328 + log.Debug().Err(err).Str("path", path).Msg("app static file not found, falling back to SSR")
329 + servePortalHTMLWithSSR(w, r, serv)
330 return
331 }
332
@@ -260,7 +344,7 @@ func serveAdminStatic(w http.ResponseWriter, r *http.Request, path string) {
344 log.Debug().
345 Str("path", path).
346 Int("size", len(data)).
263 - Msg("served admin static file")
347 + Msg("served app static file")
348 }
349
350 // servePortalStatic serves static files for portal frontend with appropriate cache headers
@@ -408,7 +492,20 @@ func isPortalSubdomain(host string) bool {
492 if portalHost == "" {
493 return false
494 }
411 - return strings.HasSuffix(host, "."+portalHost)
495 +
496 + // Remove port from host for comparison
497 + hostWithoutPort := host
498 + if idx := strings.LastIndex(host, ":"); idx != -1 {
499 + hostWithoutPort = host[:idx]
500 + }
501 +
502 + // Remove port from portalHost for comparison
503 + portalHostWithoutPort := portalHost
504 + if idx := strings.LastIndex(portalHost, ":"); idx != -1 {
505 + portalHostWithoutPort = portalHost[:idx]
506 + }
507 +
508 + return strings.HasSuffix(hostWithoutPort, "."+portalHostWithoutPort)
509 }
510
511 // matchesWildcardPattern checks if a host matches a wildcard pattern (e.g., *.localhost:4017)
@@ -434,7 +531,7 @@ func isHexString(s string) bool {
531 }
532
533 // serveDynamicManifest generates and serves manifest.json dynamically
437 -func serveDynamicManifest(w http.ResponseWriter, r *http.Request) {
534 +func serveDynamicManifest(w http.ResponseWriter) {
535 setCORSHeaders(w)
536
537 // Find the content-addressed WASM file
cmd/relay-server/frontend/.eslintrc.cjs new
+18
@@ -0,0 +1,18 @@
1 +module.exports = {
2 + root: true,
3 + env: { browser: true, es2020: true },
4 + extends: [
5 + "eslint:recommended",
6 + "plugin:@typescript-eslint/recommended",
7 + "plugin:react-hooks/recommended",
8 + ],
9 + ignorePatterns: ["dist", ".eslintrc.cjs"],
10 + parser: "@typescript-eslint/parser",
11 + plugins: ["react-refresh"],
12 + rules: {
13 + "react-refresh/only-export-components": [
14 + "warn",
15 + { allowConstantExport: true },
16 + ],
17 + },
18 +};
cmd/relay-server/frontend/.gitignore new
+24
@@ -0,0 +1,24 @@
1 +# Logs
2 +logs
3 +*.log
4 +npm-debug.log*
5 +yarn-debug.log*
6 +yarn-error.log*
7 +pnpm-debug.log*
8 +lerna-debug.log*
9 +
10 +node_modules
11 +dist
12 +dist-ssr
13 +*.local
14 +
15 +# Editor directories and files
16 +.vscode/*
17 +!.vscode/extensions.json
18 +.idea
19 +.DS_Store
20 +*.suo
21 +*.ntvs*
22 +*.njsproj
23 +*.sln
24 +*.sw?
cmd/relay-server/frontend/README.md new
+227
@@ -0,0 +1,227 @@
1 +# Relay Server Frontend
2 +
3 +ServerShare-style frontend built with React + TypeScript + shadcn/ui, featuring dynamic GeoIP-based server filtering and SSR data integration.
4 +
5 +## Tech Stack
6 +
7 +- **React 19** - UI library
8 +- **TypeScript** - Type safety
9 +- **Vite 7** - Build tool
10 +- **Tailwind CSS 4** - CSS-first configuration styling
11 +- **shadcn/ui** - UI components (Radix UI-based)
12 +- **Lucide React** - Icons
13 +
14 +## Project Structure
15 +
16 +```
17 +frontend/
18 +├── src/
19 +│ ├── components/
20 +│ │ ├── ui/ # shadcn/ui base components
21 +│ │ │ ├── button.tsx
22 +│ │ │ ├── input.tsx
23 +│ │ │ └── select.tsx
24 +│ │ ├── Header.tsx # Header component
25 +│ │ ├── SearchBar.tsx # Search and filter bar (Country, Status, Sort By)
26 +│ │ ├── ServerCard.tsx # Server card component
27 +│ │ └── Pagination.tsx # Pagination component
28 +│ ├── hooks/
29 +│ │ └── useSSRData.ts # SSR data hook (reads __SSR_DATA__ from Go backend)
30 +│ ├── lib/
31 +│ │ ├── utils.ts # Utility functions
32 +│ │ └── countries.ts # ISO 3166-1 alpha-2 country code mapping (~200 countries)
33 +│ ├── App.tsx # Main app component (filter logic, dynamic country extraction)
34 +│ ├── main.tsx # Entry point
35 +│ └── index.css # Global styles and Tailwind CSS 4 configuration
36 +├── index.html
37 +├── package.json
38 +├── tsconfig.json
39 +└── vite.config.ts # @tailwindcss/vite plugin
40 +```
41 +
42 +## Key Features
43 +
44 +### 1. Server-Side Rendering (SSR)
45 +- Go backend injects server data into HTML via `<script id="__SSR_DATA__">` tag
46 +- Frontend reads SSR data using `useSSRData()` hook
47 +- Zero initial loading time for server list
48 +
49 +### 2. GeoIP Integration
50 +- Backend uses MaxMind GeoLite2-Country.mmdb database
51 +- Automatically detects server location based on IP address
52 +- Provides ISO 3166-1 alpha-2 country codes (e.g., "US", "KR", "JP")
53 +
54 +### 3. Dynamic Country Filtering
55 +- Extracts unique countries from currently connected servers
56 +- Only displays countries that actually have servers online
57 +- Full country mapping (~200 countries) in `lib/countries.ts`
58 +- Converts country codes to human-readable names
59 +
60 +### 4. Advanced Filter System
61 +Three Select dropdowns:
62 +- **Country**: Filter by GeoIP-detected location (dynamic list)
63 +- **Status**: Filter by online/offline status
64 +- **Sort By**: Sort by Description, Tags, or Owner
65 +
66 +### 5. Search Functionality
67 +Search across:
68 +- Server names
69 +- Descriptions
70 +- Tags
71 +
72 +### Tailwind CSS 4 Migration
73 +
74 +This project uses Tailwind CSS v4:
75 +
76 +- ✅ CSS-first configuration (`@theme` directive in `index.css`)
77 +- ✅ `@tailwindcss/vite` plugin
78 +- ✅ Removed `tailwind.config.js` (config moved to CSS)
79 +- ✅ Removed `postcss.config.js` (auto-handled)
80 +- ✅ `@import "tailwindcss"` syntax
81 +
82 +For details, see [Tailwind CSS v4 Official Documentation](https://tailwindcss.com/docs/upgrade-guide).
83 +
84 +## Installation and Build
85 +
86 +### Install Dependencies
87 +
88 +```bash
89 +cd cmd/relay-server/frontend
90 +npm install
91 +```
92 +
93 +### Development Server
94 +
95 +```bash
96 +npm run dev
97 +```
98 +
99 +Development server runs at `http://localhost:5173`.
100 +
101 +### Production Build
102 +
103 +```bash
104 +npm run build
105 +```
106 +
107 +Build output in `/dist` directory:
108 +- `portal.html` - Main HTML file (served by Go server with SSR data injection)
109 +- `assets/` - JS and CSS bundles
110 +
111 +### Using Makefile
112 +
113 +```bash
114 +# Install dependencies
115 +make install
116 +
117 +# Build
118 +make build
119 +
120 +# Development server
121 +make dev
122 +
123 +# Clean
124 +make clean
125 +```
126 +
127 +## Go Server Integration
128 +
129 +The relay-server serves the frontend at:
130 +
131 +- `/` - React frontend (ServerShare UI with SSR data)
132 +- `/app/` - React app static assets
133 +- `/healthz` - Health check endpoint
134 +- `/relay` - WebSocket relay endpoint
135 +
136 +### Running the Server
137 +
138 +```bash
139 +# Build frontend
140 +cd cmd/relay-server/frontend
141 +npm run build
142 +
143 +# Run server
144 +cd ../../..
145 +go run cmd/relay-server/*.go -port 4017
146 +```
147 +
148 +Or specify static directory:
149 +
150 +```bash
151 +STATIC_DIR=./dist go run cmd/relay-server/*.go -port 4017
152 +```
153 +
154 +### SSR Data Flow
155 +
156 +1. Go backend reads lease entries and GeoIP data
157 +2. Converts to JSON and injects into `portal.html` as `<script id="__SSR_DATA__">`
158 +3. React app reads SSR data via `useSSRData()` hook
159 +4. Displays server list with GeoIP-based filtering
160 +
161 +## Design System
162 +
163 +### Colors
164 +
165 +- **Primary**: `#47cdff` - Primary action buttons
166 +- **Background Light**: `#f5f8f8` - Light mode background
167 +- **Background Dark**: `#0f1e23` - Dark mode background (default)
168 +- **Green Status**: `#50E3C2` - Online status indicator
169 +
170 +### Components
171 +
172 +#### Header
173 +Navigation header with logo and "Add Your Server" button
174 +
175 +#### SearchBar
176 +Search input + three filter dropdowns:
177 +- Country (GeoIP-based, dynamic)
178 +- Status (All/Online/Offline)
179 +- Sort By (Default/Description/Tags/Owner)
180 +
181 +#### ServerCard
182 +Server information card displaying:
183 +- Thumbnail image
184 +- Online/offline status badge
185 +- Server name
186 +- Description
187 +- Tags (including country)
188 +- Owner information
189 +- Connect button
190 +
191 +#### Pagination
192 +Page navigation with previous/next buttons (6 items per page)
193 +
194 +## Implementation Status
195 +
196 +### Completed Features
197 +- ✅ Server-side rendering (SSR) with Go backend
198 +- ✅ GeoIP integration with MaxMind GeoLite2-Country database
199 +- ✅ Dynamic country filtering (shows only countries with connected servers)
200 +- ✅ Search functionality (name, description, tags)
201 +- ✅ Status filtering (online/offline)
202 +- ✅ Sort by Description, Tags, or Owner
203 +- ✅ Pagination (6 servers per page)
204 +- ✅ Dark mode UI (default)
205 +- ✅ Responsive design (mobile/tablet/desktop)
206 +- ✅ ISO 3166-1 alpha-2 country code mapping (~200 countries)
207 +- ✅ Radix UI Select components with proper value handling
208 +
209 +## Technical Notes
210 +
211 +### Radix UI Select Constraints
212 +- Select values cannot be empty strings (`""`)
213 +- Use meaningful defaults: `"all"`, `"default"` instead of `""`
214 +
215 +### GeoIP Detection
216 +- Detects country based on server IP address
217 +- Localhost (::1) connections show no country
218 +- Requires external IP addresses for proper country detection
219 +
220 +### Dynamic Country List
221 +- Extracts unique countries from connected servers using `useMemo` and `Set`
222 +- Updates automatically as servers connect/disconnect
223 +- Maps country codes to human-readable names via `COUNTRY_NAMES`
224 +
225 +## License
226 +
227 +This project is part of gosuda/portal.
cmd/relay-server/frontend/components.json new
+20
@@ -0,0 +1,20 @@
1 +{
2 + "$schema": "https://ui.shadcn.com/schema.json",
3 + "style": "new-york",
4 + "rsc": false,
5 + "tsx": true,
6 + "tailwind": {
7 + "config": "tailwind.config.ts",
8 + "css": "src/index.css",
9 + "baseColor": "zinc",
10 + "cssVariables": true,
11 + "prefix": ""
12 + },
13 + "aliases": {
14 + "components": "@/components",
15 + "utils": "@/lib/utils",
16 + "ui": "@/components/ui",
17 + "lib": "@/lib",
18 + "hooks": "@/hooks"
19 + }
20 +}
cmd/relay-server/frontend/index.html new
+28
@@ -0,0 +1,28 @@
1 +<!doctype html>
2 +<html lang="en" class="dark" style="color-scheme: dark;">
3 +
4 +<head>
5 + <meta charset="UTF-8" />
6 + <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7 + <meta name="color-scheme" content="dark" />
8 + <meta name="theme-color" content="#0f1e23" />
9 + <meta name="description"
10 + content="Transform your local services into web-accessible endpoints. Instant access from anywhere." />
11 + <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
12 + <title>Portal - Local to web. Instant access.</title>
13 + <style>
14 + /* Prevent flash of light mode */
15 + html,
16 + body {
17 + background-color: #0f1e23;
18 + color: #ffffff;
19 + }
20 + </style>
21 +</head>
22 +
23 +<body class="dark">
24 + <div id="root"></div>
25 + <script type="module" src="/src/main.tsx"></script>
26 +</body>
27 +
28 +</html>
\ No newline at end of file
cmd/relay-server/frontend/package-lock.json new
+5066
@@ -0,0 +1,5066 @@
1 +{
2 + "name": "relay-server-frontend",
3 + "version": "0.0.0",
4 + "lockfileVersion": 3,
5 + "requires": true,
6 + "packages": {
7 + "": {
8 + "name": "relay-server-frontend",
9 + "version": "0.0.0",
10 + "dependencies": {
11 + "@radix-ui/react-dialog": "^1.1.15",
12 + "@radix-ui/react-popover": "^1.1.15",
13 + "@radix-ui/react-select": "^2.2.6",
14 + "@radix-ui/react-slot": "^1.2.4",
15 + "class-variance-authority": "^0.7.1",
16 + "clsx": "^2.1.1",
17 + "cmdk": "^1.1.1",
18 + "lucide-react": "^0.553.0",
19 + "react": "^19.2.0",
20 + "react-dom": "^19.2.0",
21 + "tailwind-merge": "^3.4.0"
22 + },
23 + "devDependencies": {
24 + "@tailwindcss/vite": "^4.1.17",
25 + "@types/node": "^24.10.1",
26 + "@types/react": "^19.2.5",
27 + "@types/react-dom": "^19.2.3",
28 + "@typescript-eslint/eslint-plugin": "^8.46.4",
29 + "@typescript-eslint/parser": "^8.46.4",
30 + "@vitejs/plugin-react": "^5.1.1",
31 + "eslint": "^9.39.1",
32 + "eslint-plugin-react-hooks": "^7.0.1",
33 + "eslint-plugin-react-refresh": "^0.4.24",
34 + "tailwindcss": "^4.1.17",
35 + "typescript": "^5.9.3",
36 + "vite": "^7.2.2"
37 + }
38 + },
39 + "node_modules/@babel/code-frame": {
40 + "version": "7.27.1",
41 + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
42 + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==",
43 + "dev": true,
44 + "license": "MIT",
45 + "dependencies": {
46 + "@babel/helper-validator-identifier": "^7.27.1",
47 + "js-tokens": "^4.0.0",
48 + "picocolors": "^1.1.1"
49 + },
50 + "engines": {
51 + "node": ">=6.9.0"
52 + }
53 + },
54 + "node_modules/@babel/compat-data": {
55 + "version": "7.28.5",
56 + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz",
57 + "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==",
58 + "dev": true,
59 + "license": "MIT",
60 + "engines": {
61 + "node": ">=6.9.0"
62 + }
63 + },
64 + "node_modules/@babel/core": {
65 + "version": "7.28.5",
66 + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz",
67 + "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
68 + "dev": true,
69 + "license": "MIT",
70 + "dependencies": {
71 + "@babel/code-frame": "^7.27.1",
72 + "@babel/generator": "^7.28.5",
73 + "@babel/helper-compilation-targets": "^7.27.2",
74 + "@babel/helper-module-transforms": "^7.28.3",
75 + "@babel/helpers": "^7.28.4",
76 + "@babel/parser": "^7.28.5",
77 + "@babel/template": "^7.27.2",
78 + "@babel/traverse": "^7.28.5",
79 + "@babel/types": "^7.28.5",
80 + "@jridgewell/remapping": "^2.3.5",
81 + "convert-source-map": "^2.0.0",
82 + "debug": "^4.1.0",
83 + "gensync": "^1.0.0-beta.2",
84 + "json5": "^2.2.3",
85 + "semver": "^6.3.1"
86 + },
87 + "engines": {
88 + "node": ">=6.9.0"
89 + },
90 + "funding": {
91 + "type": "opencollective",
92 + "url": "https://opencollective.com/babel"
93 + }
94 + },
95 + "node_modules/@babel/core/node_modules/semver": {
96 + "version": "6.3.1",
97 + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
98 + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
99 + "dev": true,
100 + "license": "ISC",
101 + "bin": {
102 + "semver": "bin/semver.js"
103 + }
104 + },
105 + "node_modules/@babel/generator": {
106 + "version": "7.28.5",
107 + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz",
108 + "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==",
109 + "dev": true,
110 + "license": "MIT",
111 + "dependencies": {
112 + "@babel/parser": "^7.28.5",
113 + "@babel/types": "^7.28.5",
114 + "@jridgewell/gen-mapping": "^0.3.12",
115 + "@jridgewell/trace-mapping": "^0.3.28",
116 + "jsesc": "^3.0.2"
117 + },
118 + "engines": {
119 + "node": ">=6.9.0"
120 + }
121 + },
122 + "node_modules/@babel/helper-compilation-targets": {
123 + "version": "7.27.2",
124 + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz",
125 + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==",
126 + "dev": true,
127 + "license": "MIT",
128 + "dependencies": {
129 + "@babel/compat-data": "^7.27.2",
130 + "@babel/helper-validator-option": "^7.27.1",
131 + "browserslist": "^4.24.0",
132 + "lru-cache": "^5.1.1",
133 + "semver": "^6.3.1"
134 + },
135 + "engines": {
136 + "node": ">=6.9.0"
137 + }
138 + },
139 + "node_modules/@babel/helper-compilation-targets/node_modules/semver": {
140 + "version": "6.3.1",
141 + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
142 + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
143 + "dev": true,
144 + "license": "ISC",
145 + "bin": {
146 + "semver": "bin/semver.js"
147 + }
148 + },
149 + "node_modules/@babel/helper-globals": {
150 + "version": "7.28.0",
151 + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
152 + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
153 + "dev": true,
154 + "license": "MIT",
155 + "engines": {
156 + "node": ">=6.9.0"
157 + }
158 + },
159 + "node_modules/@babel/helper-module-imports": {
160 + "version": "7.27.1",
161 + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz",
162 + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==",
163 + "dev": true,
164 + "license": "MIT",
165 + "dependencies": {
166 + "@babel/traverse": "^7.27.1",
167 + "@babel/types": "^7.27.1"
168 + },
169 + "engines": {
170 + "node": ">=6.9.0"
171 + }
172 + },
173 + "node_modules/@babel/helper-module-transforms": {
174 + "version": "7.28.3",
175 + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz",
176 + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==",
177 + "dev": true,
178 + "license": "MIT",
179 + "dependencies": {
180 + "@babel/helper-module-imports": "^7.27.1",
181 + "@babel/helper-validator-identifier": "^7.27.1",
182 + "@babel/traverse": "^7.28.3"
183 + },
184 + "engines": {
185 + "node": ">=6.9.0"
186 + },
187 + "peerDependencies": {
188 + "@babel/core": "^7.0.0"
189 + }
190 + },
191 + "node_modules/@babel/helper-plugin-utils": {
192 + "version": "7.27.1",
193 + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz",
194 + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==",
195 + "dev": true,
196 + "license": "MIT",
197 + "engines": {
198 + "node": ">=6.9.0"
199 + }
200 + },
201 + "node_modules/@babel/helper-string-parser": {
202 + "version": "7.27.1",
203 + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
204 + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
205 + "dev": true,
206 + "license": "MIT",
207 + "engines": {
208 + "node": ">=6.9.0"
209 + }
210 + },
211 + "node_modules/@babel/helper-validator-identifier": {
212 + "version": "7.28.5",
213 + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
214 + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
215 + "dev": true,
216 + "license": "MIT",
217 + "engines": {
218 + "node": ">=6.9.0"
219 + }
220 + },
221 + "node_modules/@babel/helper-validator-option": {
222 + "version": "7.27.1",
223 + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz",
224 + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==",
225 + "dev": true,
226 + "license": "MIT",
227 + "engines": {
228 + "node": ">=6.9.0"
229 + }
230 + },
231 + "node_modules/@babel/helpers": {
232 + "version": "7.28.4",
233 + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz",
234 + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==",
235 + "dev": true,
236 + "license": "MIT",
237 + "dependencies": {
238 + "@babel/template": "^7.27.2",
239 + "@babel/types": "^7.28.4"
240 + },
241 + "engines": {
242 + "node": ">=6.9.0"
243 + }
244 + },
245 + "node_modules/@babel/parser": {
246 + "version": "7.28.5",
247 + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz",
248 + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==",
249 + "dev": true,
250 + "license": "MIT",
251 + "dependencies": {
252 + "@babel/types": "^7.28.5"
253 + },
254 + "bin": {
255 + "parser": "bin/babel-parser.js"
256 + },
257 + "engines": {
258 + "node": ">=6.0.0"
259 + }
260 + },
261 + "node_modules/@babel/plugin-transform-react-jsx-self": {
262 + "version": "7.27.1",
263 + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz",
264 + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==",
265 + "dev": true,
266 + "license": "MIT",
267 + "dependencies": {
268 + "@babel/helper-plugin-utils": "^7.27.1"
269 + },
270 + "engines": {
271 + "node": ">=6.9.0"
272 + },
273 + "peerDependencies": {
274 + "@babel/core": "^7.0.0-0"
275 + }
276 + },
277 + "node_modules/@babel/plugin-transform-react-jsx-source": {
278 + "version": "7.27.1",
279 + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz",
280 + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==",
281 + "dev": true,
282 + "license": "MIT",
283 + "dependencies": {
284 + "@babel/helper-plugin-utils": "^7.27.1"
285 + },
286 + "engines": {
287 + "node": ">=6.9.0"
288 + },
289 + "peerDependencies": {
290 + "@babel/core": "^7.0.0-0"
291 + }
292 + },
293 + "node_modules/@babel/template": {
294 + "version": "7.27.2",
295 + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz",
296 + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==",
297 + "dev": true,
298 + "license": "MIT",
299 + "dependencies": {
300 + "@babel/code-frame": "^7.27.1",
301 + "@babel/parser": "^7.27.2",
302 + "@babel/types": "^7.27.1"
303 + },
304 + "engines": {
305 + "node": ">=6.9.0"
306 + }
307 + },
308 + "node_modules/@babel/traverse": {
309 + "version": "7.28.5",
310 + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz",
311 + "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==",
312 + "dev": true,
313 + "license": "MIT",
314 + "dependencies": {
315 + "@babel/code-frame": "^7.27.1",
316 + "@babel/generator": "^7.28.5",
317 + "@babel/helper-globals": "^7.28.0",
318 + "@babel/parser": "^7.28.5",
319 + "@babel/template": "^7.27.2",
320 + "@babel/types": "^7.28.5",
321 + "debug": "^4.3.1"
322 + },
323 + "engines": {
324 + "node": ">=6.9.0"
325 + }
326 + },
327 + "node_modules/@babel/types": {
328 + "version": "7.28.5",
329 + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz",
330 + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==",
331 + "dev": true,
332 + "license": "MIT",
333 + "dependencies": {
334 + "@babel/helper-string-parser": "^7.27.1",
335 + "@babel/helper-validator-identifier": "^7.28.5"
336 + },
337 + "engines": {
338 + "node": ">=6.9.0"
339 + }
340 + },
341 + "node_modules/@esbuild/aix-ppc64": {
342 + "version": "0.25.12",
343 + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
344 + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==",
345 + "cpu": [
346 + "ppc64"
347 + ],
348 + "dev": true,
349 + "license": "MIT",
350 + "optional": true,
351 + "os": [
352 + "aix"
353 + ],
354 + "engines": {
355 + "node": ">=18"
356 + }
357 + },
358 + "node_modules/@esbuild/android-arm": {
359 + "version": "0.25.12",
360 + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz",
361 + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==",
362 + "cpu": [
363 + "arm"
364 + ],
365 + "dev": true,
366 + "license": "MIT",
367 + "optional": true,
368 + "os": [
369 + "android"
370 + ],
371 + "engines": {
372 + "node": ">=18"
373 + }
374 + },
375 + "node_modules/@esbuild/android-arm64": {
376 + "version": "0.25.12",
377 + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz",
378 + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==",
379 + "cpu": [
380 + "arm64"
381 + ],
382 + "dev": true,
383 + "license": "MIT",
384 + "optional": true,
385 + "os": [
386 + "android"
387 + ],
388 + "engines": {
389 + "node": ">=18"
390 + }
391 + },
392 + "node_modules/@esbuild/android-x64": {
393 + "version": "0.25.12",
394 + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz",
395 + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==",
396 + "cpu": [
397 + "x64"
398 + ],
399 + "dev": true,
400 + "license": "MIT",
401 + "optional": true,
402 + "os": [
403 + "android"
404 + ],
405 + "engines": {
406 + "node": ">=18"
407 + }
408 + },
409 + "node_modules/@esbuild/darwin-arm64": {
410 + "version": "0.25.12",
411 + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz",
412 + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==",
413 + "cpu": [
414 + "arm64"
415 + ],
416 + "dev": true,
417 + "license": "MIT",
418 + "optional": true,
419 + "os": [
420 + "darwin"
421 + ],
422 + "engines": {
423 + "node": ">=18"
424 + }
425 + },
426 + "node_modules/@esbuild/darwin-x64": {
427 + "version": "0.25.12",
428 + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz",
429 + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==",
430 + "cpu": [
431 + "x64"
432 + ],
433 + "dev": true,
434 + "license": "MIT",
435 + "optional": true,
436 + "os": [
437 + "darwin"
438 + ],
439 + "engines": {
440 + "node": ">=18"
441 + }
442 + },
443 + "node_modules/@esbuild/freebsd-arm64": {
444 + "version": "0.25.12",
445 + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz",
446 + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==",
447 + "cpu": [
448 + "arm64"
449 + ],
450 + "dev": true,
451 + "license": "MIT",
452 + "optional": true,
453 + "os": [
454 + "freebsd"
455 + ],
456 + "engines": {
457 + "node": ">=18"
458 + }
459 + },
460 + "node_modules/@esbuild/freebsd-x64": {
461 + "version": "0.25.12",
462 + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz",
463 + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==",
464 + "cpu": [
465 + "x64"
466 + ],
467 + "dev": true,
468 + "license": "MIT",
469 + "optional": true,
470 + "os": [
471 + "freebsd"
472 + ],
473 + "engines": {
474 + "node": ">=18"
475 + }
476 + },
477 + "node_modules/@esbuild/linux-arm": {
478 + "version": "0.25.12",
479 + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz",
480 + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==",
481 + "cpu": [
482 + "arm"
483 + ],
484 + "dev": true,
485 + "license": "MIT",
486 + "optional": true,
487 + "os": [
488 + "linux"
489 + ],
490 + "engines": {
491 + "node": ">=18"
492 + }
493 + },
494 + "node_modules/@esbuild/linux-arm64": {
495 + "version": "0.25.12",
496 + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz",
497 + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==",
498 + "cpu": [
499 + "arm64"
500 + ],
501 + "dev": true,
502 + "license": "MIT",
503 + "optional": true,
504 + "os": [
505 + "linux"
506 + ],
507 + "engines": {
508 + "node": ">=18"
509 + }
510 + },
511 + "node_modules/@esbuild/linux-ia32": {
512 + "version": "0.25.12",
513 + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz",
514 + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==",
515 + "cpu": [
516 + "ia32"
517 + ],
518 + "dev": true,
519 + "license": "MIT",
520 + "optional": true,
521 + "os": [
522 + "linux"
523 + ],
524 + "engines": {
525 + "node": ">=18"
526 + }
527 + },
528 + "node_modules/@esbuild/linux-loong64": {
529 + "version": "0.25.12",
530 + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz",
531 + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==",
532 + "cpu": [
533 + "loong64"
534 + ],
535 + "dev": true,
536 + "license": "MIT",
537 + "optional": true,
538 + "os": [
539 + "linux"
540 + ],
541 + "engines": {
542 + "node": ">=18"
543 + }
544 + },
545 + "node_modules/@esbuild/linux-mips64el": {
546 + "version": "0.25.12",
547 + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz",
548 + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==",
549 + "cpu": [
550 + "mips64el"
551 + ],
552 + "dev": true,
553 + "license": "MIT",
554 + "optional": true,
555 + "os": [
556 + "linux"
557 + ],
558 + "engines": {
559 + "node": ">=18"
560 + }
561 + },
562 + "node_modules/@esbuild/linux-ppc64": {
563 + "version": "0.25.12",
564 + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz",
565 + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==",
566 + "cpu": [
567 + "ppc64"
568 + ],
569 + "dev": true,
570 + "license": "MIT",
571 + "optional": true,
572 + "os": [
573 + "linux"
574 + ],
575 + "engines": {
576 + "node": ">=18"
577 + }
578 + },
579 + "node_modules/@esbuild/linux-riscv64": {
580 + "version": "0.25.12",
581 + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz",
582 + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==",
583 + "cpu": [
584 + "riscv64"
585 + ],
586 + "dev": true,
587 + "license": "MIT",
588 + "optional": true,
589 + "os": [
590 + "linux"
591 + ],
592 + "engines": {
593 + "node": ">=18"
594 + }
595 + },
596 + "node_modules/@esbuild/linux-s390x": {
597 + "version": "0.25.12",
598 + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz",
599 + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==",
600 + "cpu": [
601 + "s390x"
602 + ],
603 + "dev": true,
604 + "license": "MIT",
605 + "optional": true,
606 + "os": [
607 + "linux"
608 + ],
609 + "engines": {
610 + "node": ">=18"
611 + }
612 + },
613 + "node_modules/@esbuild/linux-x64": {
614 + "version": "0.25.12",
615 + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz",
616 + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==",
617 + "cpu": [
618 + "x64"
619 + ],
620 + "dev": true,
621 + "license": "MIT",
622 + "optional": true,
623 + "os": [
624 + "linux"
625 + ],
626 + "engines": {
627 + "node": ">=18"
628 + }
629 + },
630 + "node_modules/@esbuild/netbsd-arm64": {
631 + "version": "0.25.12",
632 + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz",
633 + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==",
634 + "cpu": [
635 + "arm64"
636 + ],
637 + "dev": true,
638 + "license": "MIT",
639 + "optional": true,
640 + "os": [
641 + "netbsd"
642 + ],
643 + "engines": {
644 + "node": ">=18"
645 + }
646 + },
647 + "node_modules/@esbuild/netbsd-x64": {
648 + "version": "0.25.12",
649 + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz",
650 + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==",
651 + "cpu": [
652 + "x64"
653 + ],
654 + "dev": true,
655 + "license": "MIT",
656 + "optional": true,
657 + "os": [
658 + "netbsd"
659 + ],
660 + "engines": {
661 + "node": ">=18"
662 + }
663 + },
664 + "node_modules/@esbuild/openbsd-arm64": {
665 + "version": "0.25.12",
666 + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz",
667 + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==",
668 + "cpu": [
669 + "arm64"
670 + ],
671 + "dev": true,
672 + "license": "MIT",
673 + "optional": true,
674 + "os": [
675 + "openbsd"
676 + ],
677 + "engines": {
678 + "node": ">=18"
679 + }
680 + },
681 + "node_modules/@esbuild/openbsd-x64": {
682 + "version": "0.25.12",
683 + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz",
684 + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==",
685 + "cpu": [
686 + "x64"
687 + ],
688 + "dev": true,
689 + "license": "MIT",
690 + "optional": true,
691 + "os": [
692 + "openbsd"
693 + ],
694 + "engines": {
695 + "node": ">=18"
696 + }
697 + },
698 + "node_modules/@esbuild/openharmony-arm64": {
699 + "version": "0.25.12",
700 + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz",
701 + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==",
702 + "cpu": [
703 + "arm64"
704 + ],
705 + "dev": true,
706 + "license": "MIT",
707 + "optional": true,
708 + "os": [
709 + "openharmony"
710 + ],
711 + "engines": {
712 + "node": ">=18"
713 + }
714 + },
715 + "node_modules/@esbuild/sunos-x64": {
716 + "version": "0.25.12",
717 + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz",
718 + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==",
719 + "cpu": [
720 + "x64"
721 + ],
722 + "dev": true,
723 + "license": "MIT",
724 + "optional": true,
725 + "os": [
726 + "sunos"
727 + ],
728 + "engines": {
729 + "node": ">=18"
730 + }
731 + },
732 + "node_modules/@esbuild/win32-arm64": {
733 + "version": "0.25.12",
734 + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz",
735 + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==",
736 + "cpu": [
737 + "arm64"
738 + ],
739 + "dev": true,
740 + "license": "MIT",
741 + "optional": true,
742 + "os": [
743 + "win32"
744 + ],
745 + "engines": {
746 + "node": ">=18"
747 + }
748 + },
749 + "node_modules/@esbuild/win32-ia32": {
750 + "version": "0.25.12",
751 + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz",
752 + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==",
753 + "cpu": [
754 + "ia32"
755 + ],
756 + "dev": true,
757 + "license": "MIT",
758 + "optional": true,
759 + "os": [
760 + "win32"
761 + ],
762 + "engines": {
763 + "node": ">=18"
764 + }
765 + },
766 + "node_modules/@esbuild/win32-x64": {
767 + "version": "0.25.12",
768 + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz",
769 + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==",
770 + "cpu": [
771 + "x64"
772 + ],
773 + "dev": true,
774 + "license": "MIT",
775 + "optional": true,
776 + "os": [
777 + "win32"
778 + ],
779 + "engines": {
780 + "node": ">=18"
781 + }
782 + },
783 + "node_modules/@eslint-community/eslint-utils": {
784 + "version": "4.9.0",
785 + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz",
786 + "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==",
787 + "dev": true,
788 + "license": "MIT",
789 + "dependencies": {
790 + "eslint-visitor-keys": "^3.4.3"
791 + },
792 + "engines": {
793 + "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
794 + },
795 + "funding": {
796 + "url": "https://opencollective.com/eslint"
797 + },
798 + "peerDependencies": {
799 + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
800 + }
801 + },
802 + "node_modules/@eslint-community/regexpp": {
803 + "version": "4.12.2",
804 + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz",
805 + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==",
806 + "dev": true,
807 + "license": "MIT",
808 + "engines": {
809 + "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
810 + }
811 + },
812 + "node_modules/@eslint/config-array": {
813 + "version": "0.21.1",
814 + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz",
815 + "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==",
816 + "dev": true,
817 + "license": "Apache-2.0",
818 + "dependencies": {
819 + "@eslint/object-schema": "^2.1.7",
820 + "debug": "^4.3.1",
821 + "minimatch": "^3.1.2"
822 + },
823 + "engines": {
824 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
825 + }
826 + },
827 + "node_modules/@eslint/config-array/node_modules/brace-expansion": {
828 + "version": "1.1.12",
829 + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
830 + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
831 + "dev": true,
832 + "license": "MIT",
833 + "dependencies": {
834 + "balanced-match": "^1.0.0",
835 + "concat-map": "0.0.1"
836 + }
837 + },
838 + "node_modules/@eslint/config-array/node_modules/minimatch": {
839 + "version": "3.1.2",
840 + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
841 + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
842 + "dev": true,
843 + "license": "ISC",
844 + "dependencies": {
845 + "brace-expansion": "^1.1.7"
846 + },
847 + "engines": {
848 + "node": "*"
849 + }
850 + },
851 + "node_modules/@eslint/config-helpers": {
852 + "version": "0.4.2",
853 + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz",
854 + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==",
855 + "dev": true,
856 + "license": "Apache-2.0",
857 + "dependencies": {
858 + "@eslint/core": "^0.17.0"
859 + },
860 + "engines": {
861 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
862 + }
863 + },
864 + "node_modules/@eslint/core": {
865 + "version": "0.17.0",
866 + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz",
867 + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==",
868 + "dev": true,
869 + "license": "Apache-2.0",
870 + "dependencies": {
871 + "@types/json-schema": "^7.0.15"
872 + },
873 + "engines": {
874 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
875 + }
876 + },
877 + "node_modules/@eslint/eslintrc": {
878 + "version": "3.3.1",
879 + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz",
880 + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==",
881 + "dev": true,
882 + "license": "MIT",
883 + "dependencies": {
884 + "ajv": "^6.12.4",
885 + "debug": "^4.3.2",
886 + "espree": "^10.0.1",
887 + "globals": "^14.0.0",
888 + "ignore": "^5.2.0",
889 + "import-fresh": "^3.2.1",
890 + "js-yaml": "^4.1.0",
891 + "minimatch": "^3.1.2",
892 + "strip-json-comments": "^3.1.1"
893 + },
894 + "engines": {
895 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
896 + },
897 + "funding": {
898 + "url": "https://opencollective.com/eslint"
899 + }
900 + },
901 + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": {
902 + "version": "1.1.12",
903 + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
904 + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
905 + "dev": true,
906 + "license": "MIT",
907 + "dependencies": {
908 + "balanced-match": "^1.0.0",
909 + "concat-map": "0.0.1"
910 + }
911 + },
912 + "node_modules/@eslint/eslintrc/node_modules/ignore": {
913 + "version": "5.3.2",
914 + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
915 + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
916 + "dev": true,
917 + "license": "MIT",
918 + "engines": {
919 + "node": ">= 4"
920 + }
921 + },
922 + "node_modules/@eslint/eslintrc/node_modules/minimatch": {
923 + "version": "3.1.2",
924 + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
925 + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
926 + "dev": true,
927 + "license": "ISC",
928 + "dependencies": {
929 + "brace-expansion": "^1.1.7"
930 + },
931 + "engines": {
932 + "node": "*"
933 + }
934 + },
935 + "node_modules/@eslint/js": {
936 + "version": "9.39.1",
937 + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.1.tgz",
938 + "integrity": "sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==",
939 + "dev": true,
940 + "license": "MIT",
941 + "engines": {
942 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
943 + },
944 + "funding": {
945 + "url": "https://eslint.org/donate"
946 + }
947 + },
948 + "node_modules/@eslint/object-schema": {
949 + "version": "2.1.7",
950 + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz",
951 + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==",
952 + "dev": true,
953 + "license": "Apache-2.0",
954 + "engines": {
955 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
956 + }
957 + },
958 + "node_modules/@eslint/plugin-kit": {
959 + "version": "0.4.1",
960 + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz",
961 + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==",
962 + "dev": true,
963 + "license": "Apache-2.0",
964 + "dependencies": {
965 + "@eslint/core": "^0.17.0",
966 + "levn": "^0.4.1"
967 + },
968 + "engines": {
969 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
970 + }
971 + },
972 + "node_modules/@floating-ui/core": {
973 + "version": "1.7.3",
974 + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz",
975 + "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==",
976 + "license": "MIT",
977 + "dependencies": {
978 + "@floating-ui/utils": "^0.2.10"
979 + }
980 + },
981 + "node_modules/@floating-ui/dom": {
982 + "version": "1.7.4",
983 + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz",
984 + "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==",
985 + "license": "MIT",
986 + "dependencies": {
987 + "@floating-ui/core": "^1.7.3",
988 + "@floating-ui/utils": "^0.2.10"
989 + }
990 + },
991 + "node_modules/@floating-ui/react-dom": {
992 + "version": "2.1.6",
993 + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.6.tgz",
994 + "integrity": "sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==",
995 + "license": "MIT",
996 + "dependencies": {
997 + "@floating-ui/dom": "^1.7.4"
998 + },
999 + "peerDependencies": {
1000 + "react": ">=16.8.0",
1001 + "react-dom": ">=16.8.0"
1002 + }
1003 + },
1004 + "node_modules/@floating-ui/utils": {
1005 + "version": "0.2.10",
1006 + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz",
1007 + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==",
1008 + "license": "MIT"
1009 + },
1010 + "node_modules/@humanfs/core": {
1011 + "version": "0.19.1",
1012 + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
1013 + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==",
1014 + "dev": true,
1015 + "license": "Apache-2.0",
1016 + "engines": {
1017 + "node": ">=18.18.0"
1018 + }
1019 + },
1020 + "node_modules/@humanfs/node": {
1021 + "version": "0.16.7",
1022 + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz",
1023 + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==",
1024 + "dev": true,
1025 + "license": "Apache-2.0",
1026 + "dependencies": {
1027 + "@humanfs/core": "^0.19.1",
1028 + "@humanwhocodes/retry": "^0.4.0"
1029 + },
1030 + "engines": {
1031 + "node": ">=18.18.0"
1032 + }
1033 + },
1034 + "node_modules/@humanwhocodes/module-importer": {
1035 + "version": "1.0.1",
1036 + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
1037 + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
1038 + "dev": true,
1039 + "license": "Apache-2.0",
1040 + "engines": {
1041 + "node": ">=12.22"
1042 + },
1043 + "funding": {
1044 + "type": "github",
1045 + "url": "https://github.com/sponsors/nzakas"
1046 + }
1047 + },
1048 + "node_modules/@humanwhocodes/retry": {
1049 + "version": "0.4.3",
1050 + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz",
1051 + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==",
1052 + "dev": true,
1053 + "license": "Apache-2.0",
1054 + "engines": {
1055 + "node": ">=18.18"
1056 + },
1057 + "funding": {
1058 + "type": "github",
1059 + "url": "https://github.com/sponsors/nzakas"
1060 + }
1061 + },
1062 + "node_modules/@jridgewell/gen-mapping": {
1063 + "version": "0.3.13",
1064 + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
1065 + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
1066 + "dev": true,
1067 + "license": "MIT",
1068 + "dependencies": {
1069 + "@jridgewell/sourcemap-codec": "^1.5.0",
1070 + "@jridgewell/trace-mapping": "^0.3.24"
1071 + }
1072 + },
1073 + "node_modules/@jridgewell/remapping": {
1074 + "version": "2.3.5",
1075 + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
1076 + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
1077 + "dev": true,
1078 + "license": "MIT",
1079 + "dependencies": {
1080 + "@jridgewell/gen-mapping": "^0.3.5",
1081 + "@jridgewell/trace-mapping": "^0.3.24"
1082 + }
1083 + },
1084 + "node_modules/@jridgewell/resolve-uri": {
1085 + "version": "3.1.2",
1086 + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
1087 + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
1088 + "dev": true,
1089 + "license": "MIT",
1090 + "engines": {
1091 + "node": ">=6.0.0"
1092 + }
1093 + },
1094 + "node_modules/@jridgewell/sourcemap-codec": {
1095 + "version": "1.5.5",
1096 + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
1097 + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
1098 + "dev": true,
1099 + "license": "MIT"
1100 + },
1101 + "node_modules/@jridgewell/trace-mapping": {
1102 + "version": "0.3.31",
1103 + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
1104 + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
1105 + "dev": true,
1106 + "license": "MIT",
1107 + "dependencies": {
1108 + "@jridgewell/resolve-uri": "^3.1.0",
1109 + "@jridgewell/sourcemap-codec": "^1.4.14"
1110 + }
1111 + },
1112 + "node_modules/@nodelib/fs.scandir": {
1113 + "version": "2.1.5",
1114 + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
1115 + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
1116 + "dev": true,
1117 + "license": "MIT",
1118 + "dependencies": {
1119 + "@nodelib/fs.stat": "2.0.5",
1120 + "run-parallel": "^1.1.9"
1121 + },
1122 + "engines": {
1123 + "node": ">= 8"
1124 + }
1125 + },
1126 + "node_modules/@nodelib/fs.stat": {
1127 + "version": "2.0.5",
1128 + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
1129 + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
1130 + "dev": true,
1131 + "license": "MIT",
1132 + "engines": {
1133 + "node": ">= 8"
1134 + }
1135 + },
1136 + "node_modules/@nodelib/fs.walk": {
1137 + "version": "1.2.8",
1138 + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
1139 + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
1140 + "dev": true,
1141 + "license": "MIT",
1142 + "dependencies": {
1143 + "@nodelib/fs.scandir": "2.1.5",
1144 + "fastq": "^1.6.0"
1145 + },
1146 + "engines": {
1147 + "node": ">= 8"
1148 + }
1149 + },
1150 + "node_modules/@radix-ui/number": {
1151 + "version": "1.1.1",
1152 + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz",
1153 + "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==",
1154 + "license": "MIT"
1155 + },
1156 + "node_modules/@radix-ui/primitive": {
1157 + "version": "1.1.3",
1158 + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz",
1159 + "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==",
1160 + "license": "MIT"
1161 + },
1162 + "node_modules/@radix-ui/react-arrow": {
1163 + "version": "1.1.7",
1164 + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz",
1165 + "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==",
1166 + "license": "MIT",
1167 + "dependencies": {
1168 + "@radix-ui/react-primitive": "2.1.3"
1169 + },
1170 + "peerDependencies": {
1171 + "@types/react": "*",
1172 + "@types/react-dom": "*",
1173 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
1174 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1175 + },
1176 + "peerDependenciesMeta": {
1177 + "@types/react": {
1178 + "optional": true
1179 + },
1180 + "@types/react-dom": {
1181 + "optional": true
1182 + }
1183 + }
1184 + },
1185 + "node_modules/@radix-ui/react-collection": {
1186 + "version": "1.1.7",
1187 + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz",
1188 + "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==",
1189 + "license": "MIT",
1190 + "dependencies": {
1191 + "@radix-ui/react-compose-refs": "1.1.2",
1192 + "@radix-ui/react-context": "1.1.2",
1193 + "@radix-ui/react-primitive": "2.1.3",
1194 + "@radix-ui/react-slot": "1.2.3"
1195 + },
1196 + "peerDependencies": {
1197 + "@types/react": "*",
1198 + "@types/react-dom": "*",
1199 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
1200 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1201 + },
1202 + "peerDependenciesMeta": {
1203 + "@types/react": {
1204 + "optional": true
1205 + },
1206 + "@types/react-dom": {
1207 + "optional": true
1208 + }
1209 + }
1210 + },
1211 + "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-slot": {
1212 + "version": "1.2.3",
1213 + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
1214 + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==",
1215 + "license": "MIT",
1216 + "dependencies": {
1217 + "@radix-ui/react-compose-refs": "1.1.2"
1218 + },
1219 + "peerDependencies": {
1220 + "@types/react": "*",
1221 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1222 + },
1223 + "peerDependenciesMeta": {
1224 + "@types/react": {
1225 + "optional": true
1226 + }
1227 + }
1228 + },
1229 + "node_modules/@radix-ui/react-compose-refs": {
1230 + "version": "1.1.2",
1231 + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
1232 + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==",
1233 + "license": "MIT",
1234 + "peerDependencies": {
1235 + "@types/react": "*",
1236 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1237 + },
1238 + "peerDependenciesMeta": {
1239 + "@types/react": {
1240 + "optional": true
1241 + }
1242 + }
1243 + },
1244 + "node_modules/@radix-ui/react-context": {
1245 + "version": "1.1.2",
1246 + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz",
1247 + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==",
1248 + "license": "MIT",
1249 + "peerDependencies": {
1250 + "@types/react": "*",
1251 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1252 + },
1253 + "peerDependenciesMeta": {
1254 + "@types/react": {
1255 + "optional": true
1256 + }
1257 + }
1258 + },
1259 + "node_modules/@radix-ui/react-dialog": {
1260 + "version": "1.1.15",
1261 + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz",
1262 + "integrity": "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==",
1263 + "license": "MIT",
1264 + "dependencies": {
1265 + "@radix-ui/primitive": "1.1.3",
1266 + "@radix-ui/react-compose-refs": "1.1.2",
1267 + "@radix-ui/react-context": "1.1.2",
1268 + "@radix-ui/react-dismissable-layer": "1.1.11",
1269 + "@radix-ui/react-focus-guards": "1.1.3",
1270 + "@radix-ui/react-focus-scope": "1.1.7",
1271 + "@radix-ui/react-id": "1.1.1",
1272 + "@radix-ui/react-portal": "1.1.9",
1273 + "@radix-ui/react-presence": "1.1.5",
1274 + "@radix-ui/react-primitive": "2.1.3",
1275 + "@radix-ui/react-slot": "1.2.3",
1276 + "@radix-ui/react-use-controllable-state": "1.2.2",
1277 + "aria-hidden": "^1.2.4",
1278 + "react-remove-scroll": "^2.6.3"
1279 + },
1280 + "peerDependencies": {
1281 + "@types/react": "*",
1282 + "@types/react-dom": "*",
1283 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
1284 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1285 + },
1286 + "peerDependenciesMeta": {
1287 + "@types/react": {
1288 + "optional": true
1289 + },
1290 + "@types/react-dom": {
1291 + "optional": true
1292 + }
1293 + }
1294 + },
1295 + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-slot": {
1296 + "version": "1.2.3",
1297 + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
1298 + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==",
1299 + "license": "MIT",
1300 + "dependencies": {
1301 + "@radix-ui/react-compose-refs": "1.1.2"
1302 + },
1303 + "peerDependencies": {
1304 + "@types/react": "*",
1305 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1306 + },
1307 + "peerDependenciesMeta": {
1308 + "@types/react": {
1309 + "optional": true
1310 + }
1311 + }
1312 + },
1313 + "node_modules/@radix-ui/react-direction": {
1314 + "version": "1.1.1",
1315 + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz",
1316 + "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==",
1317 + "license": "MIT",
1318 + "peerDependencies": {
1319 + "@types/react": "*",
1320 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1321 + },
1322 + "peerDependenciesMeta": {
1323 + "@types/react": {
1324 + "optional": true
1325 + }
1326 + }
1327 + },
1328 + "node_modules/@radix-ui/react-dismissable-layer": {
1329 + "version": "1.1.11",
1330 + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz",
1331 + "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==",
1332 + "license": "MIT",
1333 + "dependencies": {
1334 + "@radix-ui/primitive": "1.1.3",
1335 + "@radix-ui/react-compose-refs": "1.1.2",
1336 + "@radix-ui/react-primitive": "2.1.3",
1337 + "@radix-ui/react-use-callback-ref": "1.1.1",
1338 + "@radix-ui/react-use-escape-keydown": "1.1.1"
1339 + },
1340 + "peerDependencies": {
1341 + "@types/react": "*",
1342 + "@types/react-dom": "*",
1343 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
1344 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1345 + },
1346 + "peerDependenciesMeta": {
1347 + "@types/react": {
1348 + "optional": true
1349 + },
1350 + "@types/react-dom": {
1351 + "optional": true
1352 + }
1353 + }
1354 + },
1355 + "node_modules/@radix-ui/react-focus-guards": {
1356 + "version": "1.1.3",
1357 + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz",
1358 + "integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==",
1359 + "license": "MIT",
1360 + "peerDependencies": {
1361 + "@types/react": "*",
1362 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1363 + },
1364 + "peerDependenciesMeta": {
1365 + "@types/react": {
1366 + "optional": true
1367 + }
1368 + }
1369 + },
1370 + "node_modules/@radix-ui/react-focus-scope": {
1371 + "version": "1.1.7",
1372 + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz",
1373 + "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==",
1374 + "license": "MIT",
1375 + "dependencies": {
1376 + "@radix-ui/react-compose-refs": "1.1.2",
1377 + "@radix-ui/react-primitive": "2.1.3",
1378 + "@radix-ui/react-use-callback-ref": "1.1.1"
1379 + },
1380 + "peerDependencies": {
1381 + "@types/react": "*",
1382 + "@types/react-dom": "*",
1383 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
1384 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1385 + },
1386 + "peerDependenciesMeta": {
1387 + "@types/react": {
1388 + "optional": true
1389 + },
1390 + "@types/react-dom": {
1391 + "optional": true
1392 + }
1393 + }
1394 + },
1395 + "node_modules/@radix-ui/react-id": {
1396 + "version": "1.1.1",
1397 + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz",
1398 + "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==",
1399 + "license": "MIT",
1400 + "dependencies": {
1401 + "@radix-ui/react-use-layout-effect": "1.1.1"
1402 + },
1403 + "peerDependencies": {
1404 + "@types/react": "*",
1405 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1406 + },
1407 + "peerDependenciesMeta": {
1408 + "@types/react": {
1409 + "optional": true
1410 + }
1411 + }
1412 + },
1413 + "node_modules/@radix-ui/react-popover": {
1414 + "version": "1.1.15",
1415 + "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.15.tgz",
1416 + "integrity": "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==",
1417 + "license": "MIT",
1418 + "dependencies": {
1419 + "@radix-ui/primitive": "1.1.3",
1420 + "@radix-ui/react-compose-refs": "1.1.2",
1421 + "@radix-ui/react-context": "1.1.2",
1422 + "@radix-ui/react-dismissable-layer": "1.1.11",
1423 + "@radix-ui/react-focus-guards": "1.1.3",
1424 + "@radix-ui/react-focus-scope": "1.1.7",
1425 + "@radix-ui/react-id": "1.1.1",
1426 + "@radix-ui/react-popper": "1.2.8",
1427 + "@radix-ui/react-portal": "1.1.9",
1428 + "@radix-ui/react-presence": "1.1.5",
1429 + "@radix-ui/react-primitive": "2.1.3",
1430 + "@radix-ui/react-slot": "1.2.3",
1431 + "@radix-ui/react-use-controllable-state": "1.2.2",
1432 + "aria-hidden": "^1.2.4",
1433 + "react-remove-scroll": "^2.6.3"
1434 + },
1435 + "peerDependencies": {
1436 + "@types/react": "*",
1437 + "@types/react-dom": "*",
1438 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
1439 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1440 + },
1441 + "peerDependenciesMeta": {
1442 + "@types/react": {
1443 + "optional": true
1444 + },
1445 + "@types/react-dom": {
1446 + "optional": true
1447 + }
1448 + }
1449 + },
1450 + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-slot": {
1451 + "version": "1.2.3",
1452 + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
1453 + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==",
1454 + "license": "MIT",
1455 + "dependencies": {
1456 + "@radix-ui/react-compose-refs": "1.1.2"
1457 + },
1458 + "peerDependencies": {
1459 + "@types/react": "*",
1460 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1461 + },
1462 + "peerDependenciesMeta": {
1463 + "@types/react": {
1464 + "optional": true
1465 + }
1466 + }
1467 + },
1468 + "node_modules/@radix-ui/react-popper": {
1469 + "version": "1.2.8",
1470 + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz",
1471 + "integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==",
1472 + "license": "MIT",
1473 + "dependencies": {
1474 + "@floating-ui/react-dom": "^2.0.0",
1475 + "@radix-ui/react-arrow": "1.1.7",
1476 + "@radix-ui/react-compose-refs": "1.1.2",
1477 + "@radix-ui/react-context": "1.1.2",
1478 + "@radix-ui/react-primitive": "2.1.3",
1479 + "@radix-ui/react-use-callback-ref": "1.1.1",
1480 + "@radix-ui/react-use-layout-effect": "1.1.1",
1481 + "@radix-ui/react-use-rect": "1.1.1",
1482 + "@radix-ui/react-use-size": "1.1.1",
1483 + "@radix-ui/rect": "1.1.1"
1484 + },
1485 + "peerDependencies": {
1486 + "@types/react": "*",
1487 + "@types/react-dom": "*",
1488 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
1489 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1490 + },
1491 + "peerDependenciesMeta": {
1492 + "@types/react": {
1493 + "optional": true
1494 + },
1495 + "@types/react-dom": {
1496 + "optional": true
1497 + }
1498 + }
1499 + },
1500 + "node_modules/@radix-ui/react-portal": {
1501 + "version": "1.1.9",
1502 + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz",
1503 + "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==",
1504 + "license": "MIT",
1505 + "dependencies": {
1506 + "@radix-ui/react-primitive": "2.1.3",
1507 + "@radix-ui/react-use-layout-effect": "1.1.1"
1508 + },
1509 + "peerDependencies": {
1510 + "@types/react": "*",
1511 + "@types/react-dom": "*",
1512 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
1513 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1514 + },
1515 + "peerDependenciesMeta": {
1516 + "@types/react": {
1517 + "optional": true
1518 + },
1519 + "@types/react-dom": {
1520 + "optional": true
1521 + }
1522 + }
1523 + },
1524 + "node_modules/@radix-ui/react-presence": {
1525 + "version": "1.1.5",
1526 + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz",
1527 + "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==",
1528 + "license": "MIT",
1529 + "dependencies": {
1530 + "@radix-ui/react-compose-refs": "1.1.2",
1531 + "@radix-ui/react-use-layout-effect": "1.1.1"
1532 + },
1533 + "peerDependencies": {
1534 + "@types/react": "*",
1535 + "@types/react-dom": "*",
1536 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
1537 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1538 + },
1539 + "peerDependenciesMeta": {
1540 + "@types/react": {
1541 + "optional": true
1542 + },
1543 + "@types/react-dom": {
1544 + "optional": true
1545 + }
1546 + }
1547 + },
1548 + "node_modules/@radix-ui/react-primitive": {
1549 + "version": "2.1.3",
1550 + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz",
1551 + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==",
1552 + "license": "MIT",
1553 + "dependencies": {
1554 + "@radix-ui/react-slot": "1.2.3"
1555 + },
1556 + "peerDependencies": {
1557 + "@types/react": "*",
1558 + "@types/react-dom": "*",
1559 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
1560 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1561 + },
1562 + "peerDependenciesMeta": {
1563 + "@types/react": {
1564 + "optional": true
1565 + },
1566 + "@types/react-dom": {
1567 + "optional": true
1568 + }
1569 + }
1570 + },
1571 + "node_modules/@radix-ui/react-primitive/node_modules/@radix-ui/react-slot": {
1572 + "version": "1.2.3",
1573 + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
1574 + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==",
1575 + "license": "MIT",
1576 + "dependencies": {
1577 + "@radix-ui/react-compose-refs": "1.1.2"
1578 + },
1579 + "peerDependencies": {
1580 + "@types/react": "*",
1581 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1582 + },
1583 + "peerDependenciesMeta": {
1584 + "@types/react": {
1585 + "optional": true
1586 + }
1587 + }
1588 + },
1589 + "node_modules/@radix-ui/react-select": {
1590 + "version": "2.2.6",
1591 + "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.6.tgz",
1592 + "integrity": "sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==",
1593 + "license": "MIT",
1594 + "dependencies": {
1595 + "@radix-ui/number": "1.1.1",
1596 + "@radix-ui/primitive": "1.1.3",
1597 + "@radix-ui/react-collection": "1.1.7",
1598 + "@radix-ui/react-compose-refs": "1.1.2",
1599 + "@radix-ui/react-context": "1.1.2",
1600 + "@radix-ui/react-direction": "1.1.1",
1601 + "@radix-ui/react-dismissable-layer": "1.1.11",
1602 + "@radix-ui/react-focus-guards": "1.1.3",
1603 + "@radix-ui/react-focus-scope": "1.1.7",
1604 + "@radix-ui/react-id": "1.1.1",
1605 + "@radix-ui/react-popper": "1.2.8",
1606 + "@radix-ui/react-portal": "1.1.9",
1607 + "@radix-ui/react-primitive": "2.1.3",
1608 + "@radix-ui/react-slot": "1.2.3",
1609 + "@radix-ui/react-use-callback-ref": "1.1.1",
1610 + "@radix-ui/react-use-controllable-state": "1.2.2",
1611 + "@radix-ui/react-use-layout-effect": "1.1.1",
1612 + "@radix-ui/react-use-previous": "1.1.1",
1613 + "@radix-ui/react-visually-hidden": "1.2.3",
1614 + "aria-hidden": "^1.2.4",
1615 + "react-remove-scroll": "^2.6.3"
1616 + },
1617 + "peerDependencies": {
1618 + "@types/react": "*",
1619 + "@types/react-dom": "*",
1620 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
1621 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1622 + },
1623 + "peerDependenciesMeta": {
1624 + "@types/react": {
1625 + "optional": true
1626 + },
1627 + "@types/react-dom": {
1628 + "optional": true
1629 + }
1630 + }
1631 + },
1632 + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-slot": {
1633 + "version": "1.2.3",
1634 + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
1635 + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==",
1636 + "license": "MIT",
1637 + "dependencies": {
1638 + "@radix-ui/react-compose-refs": "1.1.2"
1639 + },
1640 + "peerDependencies": {
1641 + "@types/react": "*",
1642 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1643 + },
1644 + "peerDependenciesMeta": {
1645 + "@types/react": {
1646 + "optional": true
1647 + }
1648 + }
1649 + },
1650 + "node_modules/@radix-ui/react-slot": {
1651 + "version": "1.2.4",
1652 + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.4.tgz",
1653 + "integrity": "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==",
1654 + "license": "MIT",
1655 + "dependencies": {
1656 + "@radix-ui/react-compose-refs": "1.1.2"
1657 + },
1658 + "peerDependencies": {
1659 + "@types/react": "*",
1660 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1661 + },
1662 + "peerDependenciesMeta": {
1663 + "@types/react": {
1664 + "optional": true
1665 + }
1666 + }
1667 + },
1668 + "node_modules/@radix-ui/react-use-callback-ref": {
1669 + "version": "1.1.1",
1670 + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz",
1671 + "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==",
1672 + "license": "MIT",
1673 + "peerDependencies": {
1674 + "@types/react": "*",
1675 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1676 + },
1677 + "peerDependenciesMeta": {
1678 + "@types/react": {
1679 + "optional": true
1680 + }
1681 + }
1682 + },
1683 + "node_modules/@radix-ui/react-use-controllable-state": {
1684 + "version": "1.2.2",
1685 + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz",
1686 + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==",
1687 + "license": "MIT",
1688 + "dependencies": {
1689 + "@radix-ui/react-use-effect-event": "0.0.2",
1690 + "@radix-ui/react-use-layout-effect": "1.1.1"
1691 + },
1692 + "peerDependencies": {
1693 + "@types/react": "*",
1694 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1695 + },
1696 + "peerDependenciesMeta": {
1697 + "@types/react": {
1698 + "optional": true
1699 + }
1700 + }
1701 + },
1702 + "node_modules/@radix-ui/react-use-effect-event": {
1703 + "version": "0.0.2",
1704 + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz",
1705 + "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==",
1706 + "license": "MIT",
1707 + "dependencies": {
1708 + "@radix-ui/react-use-layout-effect": "1.1.1"
1709 + },
1710 + "peerDependencies": {
1711 + "@types/react": "*",
1712 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1713 + },
1714 + "peerDependenciesMeta": {
1715 + "@types/react": {
1716 + "optional": true
1717 + }
1718 + }
1719 + },
1720 + "node_modules/@radix-ui/react-use-escape-keydown": {
1721 + "version": "1.1.1",
1722 + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz",
1723 + "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==",
1724 + "license": "MIT",
1725 + "dependencies": {
1726 + "@radix-ui/react-use-callback-ref": "1.1.1"
1727 + },
1728 + "peerDependencies": {
1729 + "@types/react": "*",
1730 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1731 + },
1732 + "peerDependenciesMeta": {
1733 + "@types/react": {
1734 + "optional": true
1735 + }
1736 + }
1737 + },
1738 + "node_modules/@radix-ui/react-use-layout-effect": {
1739 + "version": "1.1.1",
1740 + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz",
1741 + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==",
1742 + "license": "MIT",
1743 + "peerDependencies": {
1744 + "@types/react": "*",
1745 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1746 + },
1747 + "peerDependenciesMeta": {
1748 + "@types/react": {
1749 + "optional": true
1750 + }
1751 + }
1752 + },
1753 + "node_modules/@radix-ui/react-use-previous": {
1754 + "version": "1.1.1",
1755 + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz",
1756 + "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==",
1757 + "license": "MIT",
1758 + "peerDependencies": {
1759 + "@types/react": "*",
1760 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1761 + },
1762 + "peerDependenciesMeta": {
1763 + "@types/react": {
1764 + "optional": true
1765 + }
1766 + }
1767 + },
1768 + "node_modules/@radix-ui/react-use-rect": {
1769 + "version": "1.1.1",
1770 + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz",
1771 + "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==",
1772 + "license": "MIT",
1773 + "dependencies": {
1774 + "@radix-ui/rect": "1.1.1"
1775 + },
1776 + "peerDependencies": {
1777 + "@types/react": "*",
1778 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1779 + },
1780 + "peerDependenciesMeta": {
1781 + "@types/react": {
1782 + "optional": true
1783 + }
1784 + }
1785 + },
1786 + "node_modules/@radix-ui/react-use-size": {
1787 + "version": "1.1.1",
1788 + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz",
1789 + "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==",
1790 + "license": "MIT",
1791 + "dependencies": {
1792 + "@radix-ui/react-use-layout-effect": "1.1.1"
1793 + },
1794 + "peerDependencies": {
1795 + "@types/react": "*",
1796 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1797 + },
1798 + "peerDependenciesMeta": {
1799 + "@types/react": {
1800 + "optional": true
1801 + }
1802 + }
1803 + },
1804 + "node_modules/@radix-ui/react-visually-hidden": {
1805 + "version": "1.2.3",
1806 + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz",
1807 + "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==",
1808 + "license": "MIT",
1809 + "dependencies": {
1810 + "@radix-ui/react-primitive": "2.1.3"
1811 + },
1812 + "peerDependencies": {
1813 + "@types/react": "*",
1814 + "@types/react-dom": "*",
1815 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
1816 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
1817 + },
1818 + "peerDependenciesMeta": {
1819 + "@types/react": {
1820 + "optional": true
1821 + },
1822 + "@types/react-dom": {
1823 + "optional": true
1824 + }
1825 + }
1826 + },
1827 + "node_modules/@radix-ui/rect": {
1828 + "version": "1.1.1",
1829 + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz",
1830 + "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==",
1831 + "license": "MIT"
1832 + },
1833 + "node_modules/@rolldown/pluginutils": {
1834 + "version": "1.0.0-beta.47",
1835 + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.47.tgz",
1836 + "integrity": "sha512-8QagwMH3kNCuzD8EWL8R2YPW5e4OrHNSAHRFDdmFqEwEaD/KcNKjVoumo+gP2vW5eKB2UPbM6vTYiGZX0ixLnw==",
1837 + "dev": true,
1838 + "license": "MIT"
1839 + },
1840 + "node_modules/@rollup/rollup-android-arm-eabi": {
1841 + "version": "4.53.2",
1842 + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.2.tgz",
1843 + "integrity": "sha512-yDPzwsgiFO26RJA4nZo8I+xqzh7sJTZIWQOxn+/XOdPE31lAvLIYCKqjV+lNH/vxE2L2iH3plKxDCRK6i+CwhA==",
1844 + "cpu": [
1845 + "arm"
1846 + ],
1847 + "dev": true,
1848 + "license": "MIT",
1849 + "optional": true,
1850 + "os": [
1851 + "android"
1852 + ]
1853 + },
1854 + "node_modules/@rollup/rollup-android-arm64": {
1855 + "version": "4.53.2",
1856 + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.53.2.tgz",
1857 + "integrity": "sha512-k8FontTxIE7b0/OGKeSN5B6j25EuppBcWM33Z19JoVT7UTXFSo3D9CdU39wGTeb29NO3XxpMNauh09B+Ibw+9g==",
1858 + "cpu": [
1859 + "arm64"
1860 + ],
1861 + "dev": true,
1862 + "license": "MIT",
1863 + "optional": true,
1864 + "os": [
1865 + "android"
1866 + ]
1867 + },
1868 + "node_modules/@rollup/rollup-darwin-arm64": {
1869 + "version": "4.53.2",
1870 + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.2.tgz",
1871 + "integrity": "sha512-A6s4gJpomNBtJ2yioj8bflM2oogDwzUiMl2yNJ2v9E7++sHrSrsQ29fOfn5DM/iCzpWcebNYEdXpaK4tr2RhfQ==",
1872 + "cpu": [
1873 + "arm64"
1874 + ],
1875 + "dev": true,
1876 + "license": "MIT",
1877 + "optional": true,
1878 + "os": [
1879 + "darwin"
1880 + ]
1881 + },
1882 + "node_modules/@rollup/rollup-darwin-x64": {
1883 + "version": "4.53.2",
1884 + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.53.2.tgz",
1885 + "integrity": "sha512-e6XqVmXlHrBlG56obu9gDRPW3O3hLxpwHpLsBJvuI8qqnsrtSZ9ERoWUXtPOkY8c78WghyPHZdmPhHLWNdAGEw==",
1886 + "cpu": [
1887 + "x64"
1888 + ],
1889 + "dev": true,
1890 + "license": "MIT",
1891 + "optional": true,
1892 + "os": [
1893 + "darwin"
1894 + ]
1895 + },
1896 + "node_modules/@rollup/rollup-freebsd-arm64": {
1897 + "version": "4.53.2",
1898 + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.53.2.tgz",
1899 + "integrity": "sha512-v0E9lJW8VsrwPux5Qe5CwmH/CF/2mQs6xU1MF3nmUxmZUCHazCjLgYvToOk+YuuUqLQBio1qkkREhxhc656ViA==",
1900 + "cpu": [
1901 + "arm64"
1902 + ],
1903 + "dev": true,
1904 + "license": "MIT",
1905 + "optional": true,
1906 + "os": [
1907 + "freebsd"
1908 + ]
1909 + },
1910 + "node_modules/@rollup/rollup-freebsd-x64": {
1911 + "version": "4.53.2",
1912 + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.53.2.tgz",
1913 + "integrity": "sha512-ClAmAPx3ZCHtp6ysl4XEhWU69GUB1D+s7G9YjHGhIGCSrsg00nEGRRZHmINYxkdoJehde8VIsDC5t9C0gb6yqA==",
1914 + "cpu": [
1915 + "x64"
1916 + ],
1917 + "dev": true,
1918 + "license": "MIT",
1919 + "optional": true,
1920 + "os": [
1921 + "freebsd"
1922 + ]
1923 + },
1924 + "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
1925 + "version": "4.53.2",
1926 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.53.2.tgz",
1927 + "integrity": "sha512-EPlb95nUsz6Dd9Qy13fI5kUPXNSljaG9FiJ4YUGU1O/Q77i5DYFW5KR8g1OzTcdZUqQQ1KdDqsTohdFVwCwjqg==",
1928 + "cpu": [
1929 + "arm"
1930 + ],
1931 + "dev": true,
1932 + "license": "MIT",
1933 + "optional": true,
1934 + "os": [
1935 + "linux"
1936 + ]
1937 + },
1938 + "node_modules/@rollup/rollup-linux-arm-musleabihf": {
1939 + "version": "4.53.2",
1940 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.53.2.tgz",
1941 + "integrity": "sha512-BOmnVW+khAUX+YZvNfa0tGTEMVVEerOxN0pDk2E6N6DsEIa2Ctj48FOMfNDdrwinocKaC7YXUZ1pHlKpnkja/Q==",
1942 + "cpu": [
1943 + "arm"
1944 + ],
1945 + "dev": true,
1946 + "license": "MIT",
1947 + "optional": true,
1948 + "os": [
1949 + "linux"
1950 + ]
1951 + },
1952 + "node_modules/@rollup/rollup-linux-arm64-gnu": {
1953 + "version": "4.53.2",
1954 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.53.2.tgz",
1955 + "integrity": "sha512-Xt2byDZ+6OVNuREgBXr4+CZDJtrVso5woFtpKdGPhpTPHcNG7D8YXeQzpNbFRxzTVqJf7kvPMCub/pcGUWgBjA==",
1956 + "cpu": [
1957 + "arm64"
1958 + ],
1959 + "dev": true,
1960 + "license": "MIT",
1961 + "optional": true,
1962 + "os": [
1963 + "linux"
1964 + ]
1965 + },
1966 + "node_modules/@rollup/rollup-linux-arm64-musl": {
1967 + "version": "4.53.2",
1968 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.53.2.tgz",
1969 + "integrity": "sha512-+LdZSldy/I9N8+klim/Y1HsKbJ3BbInHav5qE9Iy77dtHC/pibw1SR/fXlWyAk0ThnpRKoODwnAuSjqxFRDHUQ==",
1970 + "cpu": [
1971 + "arm64"
1972 + ],
1973 + "dev": true,
1974 + "license": "MIT",
1975 + "optional": true,
1976 + "os": [
1977 + "linux"
1978 + ]
1979 + },
1980 + "node_modules/@rollup/rollup-linux-loong64-gnu": {
1981 + "version": "4.53.2",
1982 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.53.2.tgz",
1983 + "integrity": "sha512-8ms8sjmyc1jWJS6WdNSA23rEfdjWB30LH8Wqj0Cqvv7qSHnvw6kgMMXRdop6hkmGPlyYBdRPkjJnj3KCUHV/uQ==",
1984 + "cpu": [
1985 + "loong64"
1986 + ],
1987 + "dev": true,
1988 + "license": "MIT",
1989 + "optional": true,
1990 + "os": [
1991 + "linux"
1992 + ]
1993 + },
1994 + "node_modules/@rollup/rollup-linux-ppc64-gnu": {
1995 + "version": "4.53.2",
1996 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.53.2.tgz",
1997 + "integrity": "sha512-3HRQLUQbpBDMmzoxPJYd3W6vrVHOo2cVW8RUo87Xz0JPJcBLBr5kZ1pGcQAhdZgX9VV7NbGNipah1omKKe23/g==",
1998 + "cpu": [
1999 + "ppc64"
2000 + ],
2001 + "dev": true,
2002 + "license": "MIT",
2003 + "optional": true,
2004 + "os": [
2005 + "linux"
2006 + ]
2007 + },
2008 + "node_modules/@rollup/rollup-linux-riscv64-gnu": {
2009 + "version": "4.53.2",
2010 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.53.2.tgz",
2011 + "integrity": "sha512-fMjKi+ojnmIvhk34gZP94vjogXNNUKMEYs+EDaB/5TG/wUkoeua7p7VCHnE6T2Tx+iaghAqQX8teQzcvrYpaQA==",
2012 + "cpu": [
2013 + "riscv64"
2014 + ],
2015 + "dev": true,
2016 + "license": "MIT",
2017 + "optional": true,
2018 + "os": [
2019 + "linux"
2020 + ]
2021 + },
2022 + "node_modules/@rollup/rollup-linux-riscv64-musl": {
2023 + "version": "4.53.2",
2024 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.53.2.tgz",
2025 + "integrity": "sha512-XuGFGU+VwUUV5kLvoAdi0Wz5Xbh2SrjIxCtZj6Wq8MDp4bflb/+ThZsVxokM7n0pcbkEr2h5/pzqzDYI7cCgLQ==",
2026 + "cpu": [
2027 + "riscv64"
2028 + ],
2029 + "dev": true,
2030 + "license": "MIT",
2031 + "optional": true,
2032 + "os": [
2033 + "linux"
2034 + ]
2035 + },
2036 + "node_modules/@rollup/rollup-linux-s390x-gnu": {
2037 + "version": "4.53.2",
2038 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.53.2.tgz",
2039 + "integrity": "sha512-w6yjZF0P+NGzWR3AXWX9zc0DNEGdtvykB03uhonSHMRa+oWA6novflo2WaJr6JZakG2ucsyb+rvhrKac6NIy+w==",
2040 + "cpu": [
2041 + "s390x"
2042 + ],
2043 + "dev": true,
2044 + "license": "MIT",
2045 + "optional": true,
2046 + "os": [
2047 + "linux"
2048 + ]
2049 + },
2050 + "node_modules/@rollup/rollup-linux-x64-gnu": {
2051 + "version": "4.53.2",
2052 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.53.2.tgz",
2053 + "integrity": "sha512-yo8d6tdfdeBArzC7T/PnHd7OypfI9cbuZzPnzLJIyKYFhAQ8SvlkKtKBMbXDxe1h03Rcr7u++nFS7tqXz87Gtw==",
2054 + "cpu": [
2055 + "x64"
2056 + ],
2057 + "dev": true,
2058 + "license": "MIT",
2059 + "optional": true,
2060 + "os": [
2061 + "linux"
2062 + ]
2063 + },
2064 + "node_modules/@rollup/rollup-linux-x64-musl": {
2065 + "version": "4.53.2",
2066 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.53.2.tgz",
2067 + "integrity": "sha512-ah59c1YkCxKExPP8O9PwOvs+XRLKwh/mV+3YdKqQ5AMQ0r4M4ZDuOrpWkUaqO7fzAHdINzV9tEVu8vNw48z0lA==",
2068 + "cpu": [
2069 + "x64"
2070 + ],
2071 + "dev": true,
2072 + "license": "MIT",
2073 + "optional": true,
2074 + "os": [
2075 + "linux"
2076 + ]
2077 + },
2078 + "node_modules/@rollup/rollup-openharmony-arm64": {
2079 + "version": "4.53.2",
2080 + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.53.2.tgz",
2081 + "integrity": "sha512-4VEd19Wmhr+Zy7hbUsFZ6YXEiP48hE//KPLCSVNY5RMGX2/7HZ+QkN55a3atM1C/BZCGIgqN+xrVgtdak2S9+A==",
2082 + "cpu": [
2083 + "arm64"
2084 + ],
2085 + "dev": true,
2086 + "license": "MIT",
2087 + "optional": true,
2088 + "os": [
2089 + "openharmony"
2090 + ]
2091 + },
2092 + "node_modules/@rollup/rollup-win32-arm64-msvc": {
2093 + "version": "4.53.2",
2094 + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.53.2.tgz",
2095 + "integrity": "sha512-IlbHFYc/pQCgew/d5fslcy1KEaYVCJ44G8pajugd8VoOEI8ODhtb/j8XMhLpwHCMB3yk2J07ctup10gpw2nyMA==",
2096 + "cpu": [
2097 + "arm64"
2098 + ],
2099 + "dev": true,
2100 + "license": "MIT",
2101 + "optional": true,
2102 + "os": [
2103 + "win32"
2104 + ]
2105 + },
2106 + "node_modules/@rollup/rollup-win32-ia32-msvc": {
2107 + "version": "4.53.2",
2108 + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.53.2.tgz",
2109 + "integrity": "sha512-lNlPEGgdUfSzdCWU176ku/dQRnA7W+Gp8d+cWv73jYrb8uT7HTVVxq62DUYxjbaByuf1Yk0RIIAbDzp+CnOTFg==",
2110 + "cpu": [
2111 + "ia32"
2112 + ],
2113 + "dev": true,
2114 + "license": "MIT",
2115 + "optional": true,
2116 + "os": [
2117 + "win32"
2118 + ]
2119 + },
2120 + "node_modules/@rollup/rollup-win32-x64-gnu": {
2121 + "version": "4.53.2",
2122 + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.53.2.tgz",
2123 + "integrity": "sha512-S6YojNVrHybQis2lYov1sd+uj7K0Q05NxHcGktuMMdIQ2VixGwAfbJ23NnlvvVV1bdpR2m5MsNBViHJKcA4ADw==",
2124 + "cpu": [
2125 + "x64"
2126 + ],
2127 + "dev": true,
2128 + "license": "MIT",
2129 + "optional": true,
2130 + "os": [
2131 + "win32"
2132 + ]
2133 + },
2134 + "node_modules/@rollup/rollup-win32-x64-msvc": {
2135 + "version": "4.53.2",
2136 + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.53.2.tgz",
2137 + "integrity": "sha512-k+/Rkcyx//P6fetPoLMb8pBeqJBNGx81uuf7iljX9++yNBVRDQgD04L+SVXmXmh5ZP4/WOp4mWF0kmi06PW2tA==",
2138 + "cpu": [
2139 + "x64"
2140 + ],
2141 + "dev": true,
2142 + "license": "MIT",
2143 + "optional": true,
2144 + "os": [
2145 + "win32"
2146 + ]
2147 + },
2148 + "node_modules/@tailwindcss/node": {
2149 + "version": "4.1.17",
2150 + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.17.tgz",
2151 + "integrity": "sha512-csIkHIgLb3JisEFQ0vxr2Y57GUNYh447C8xzwj89U/8fdW8LhProdxvnVH6U8M2Y73QKiTIH+LWbK3V2BBZsAg==",
2152 + "dev": true,
2153 + "license": "MIT",
2154 + "dependencies": {
2155 + "@jridgewell/remapping": "^2.3.4",
2156 + "enhanced-resolve": "^5.18.3",
2157 + "jiti": "^2.6.1",
2158 + "lightningcss": "1.30.2",
2159 + "magic-string": "^0.30.21",
2160 + "source-map-js": "^1.2.1",
2161 + "tailwindcss": "4.1.17"
2162 + }
2163 + },
2164 + "node_modules/@tailwindcss/oxide": {
2165 + "version": "4.1.17",
2166 + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.17.tgz",
2167 + "integrity": "sha512-F0F7d01fmkQhsTjXezGBLdrl1KresJTcI3DB8EkScCldyKp3Msz4hub4uyYaVnk88BAS1g5DQjjF6F5qczheLA==",
2168 + "dev": true,
2169 + "license": "MIT",
2170 + "engines": {
2171 + "node": ">= 10"
2172 + },
2173 + "optionalDependencies": {
2174 + "@tailwindcss/oxide-android-arm64": "4.1.17",
2175 + "@tailwindcss/oxide-darwin-arm64": "4.1.17",
2176 + "@tailwindcss/oxide-darwin-x64": "4.1.17",
2177 + "@tailwindcss/oxide-freebsd-x64": "4.1.17",
2178 + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.17",
2179 + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.17",
2180 + "@tailwindcss/oxide-linux-arm64-musl": "4.1.17",
2181 + "@tailwindcss/oxide-linux-x64-gnu": "4.1.17",
2182 + "@tailwindcss/oxide-linux-x64-musl": "4.1.17",
2183 + "@tailwindcss/oxide-wasm32-wasi": "4.1.17",
2184 + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.17",
2185 + "@tailwindcss/oxide-win32-x64-msvc": "4.1.17"
2186 + }
2187 + },
2188 + "node_modules/@tailwindcss/oxide-android-arm64": {
2189 + "version": "4.1.17",
2190 + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.17.tgz",
2191 + "integrity": "sha512-BMqpkJHgOZ5z78qqiGE6ZIRExyaHyuxjgrJ6eBO5+hfrfGkuya0lYfw8fRHG77gdTjWkNWEEm+qeG2cDMxArLQ==",
2192 + "cpu": [
2193 + "arm64"
2194 + ],
2195 + "dev": true,
2196 + "license": "MIT",
2197 + "optional": true,
2198 + "os": [
2199 + "android"
2200 + ],
2201 + "engines": {
2202 + "node": ">= 10"
2203 + }
2204 + },
2205 + "node_modules/@tailwindcss/oxide-darwin-arm64": {
2206 + "version": "4.1.17",
2207 + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.17.tgz",
2208 + "integrity": "sha512-EquyumkQweUBNk1zGEU/wfZo2qkp/nQKRZM8bUYO0J+Lums5+wl2CcG1f9BgAjn/u9pJzdYddHWBiFXJTcxmOg==",
2209 + "cpu": [
2210 + "arm64"
2211 + ],
2212 + "dev": true,
2213 + "license": "MIT",
2214 + "optional": true,
2215 + "os": [
2216 + "darwin"
2217 + ],
2218 + "engines": {
2219 + "node": ">= 10"
2220 + }
2221 + },
2222 + "node_modules/@tailwindcss/oxide-darwin-x64": {
2223 + "version": "4.1.17",
2224 + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.17.tgz",
2225 + "integrity": "sha512-gdhEPLzke2Pog8s12oADwYu0IAw04Y2tlmgVzIN0+046ytcgx8uZmCzEg4VcQh+AHKiS7xaL8kGo/QTiNEGRog==",
2226 + "cpu": [
2227 + "x64"
2228 + ],
2229 + "dev": true,
2230 + "license": "MIT",
2231 + "optional": true,
2232 + "os": [
2233 + "darwin"
2234 + ],
2235 + "engines": {
2236 + "node": ">= 10"
2237 + }
2238 + },
2239 + "node_modules/@tailwindcss/oxide-freebsd-x64": {
2240 + "version": "4.1.17",
2241 + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.17.tgz",
2242 + "integrity": "sha512-hxGS81KskMxML9DXsaXT1H0DyA+ZBIbyG/sSAjWNe2EDl7TkPOBI42GBV3u38itzGUOmFfCzk1iAjDXds8Oh0g==",
2243 + "cpu": [
2244 + "x64"
2245 + ],
2246 + "dev": true,
2247 + "license": "MIT",
2248 + "optional": true,
2249 + "os": [
2250 + "freebsd"
2251 + ],
2252 + "engines": {
2253 + "node": ">= 10"
2254 + }
2255 + },
2256 + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
2257 + "version": "4.1.17",
2258 + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.17.tgz",
2259 + "integrity": "sha512-k7jWk5E3ldAdw0cNglhjSgv501u7yrMf8oeZ0cElhxU6Y2o7f8yqelOp3fhf7evjIS6ujTI3U8pKUXV2I4iXHQ==",
2260 + "cpu": [
2261 + "arm"
2262 + ],
2263 + "dev": true,
2264 + "license": "MIT",
2265 + "optional": true,
2266 + "os": [
2267 + "linux"
2268 + ],
2269 + "engines": {
2270 + "node": ">= 10"
2271 + }
2272 + },
2273 + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
2274 + "version": "4.1.17",
2275 + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.17.tgz",
2276 + "integrity": "sha512-HVDOm/mxK6+TbARwdW17WrgDYEGzmoYayrCgmLEw7FxTPLcp/glBisuyWkFz/jb7ZfiAXAXUACfyItn+nTgsdQ==",
2277 + "cpu": [
2278 + "arm64"
2279 + ],
2280 + "dev": true,
2281 + "license": "MIT",
2282 + "optional": true,
2283 + "os": [
2284 + "linux"
2285 + ],
2286 + "engines": {
2287 + "node": ">= 10"
2288 + }
2289 + },
2290 + "node_modules/@tailwindcss/oxide-linux-arm64-musl": {
2291 + "version": "4.1.17",
2292 + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.17.tgz",
2293 + "integrity": "sha512-HvZLfGr42i5anKtIeQzxdkw/wPqIbpeZqe7vd3V9vI3RQxe3xU1fLjss0TjyhxWcBaipk7NYwSrwTwK1hJARMg==",
2294 + "cpu": [
2295 + "arm64"
2296 + ],
2297 + "dev": true,
2298 + "license": "MIT",
2299 + "optional": true,
2300 + "os": [
2301 + "linux"
2302 + ],
2303 + "engines": {
2304 + "node": ">= 10"
2305 + }
2306 + },
2307 + "node_modules/@tailwindcss/oxide-linux-x64-gnu": {
2308 + "version": "4.1.17",
2309 + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.17.tgz",
2310 + "integrity": "sha512-M3XZuORCGB7VPOEDH+nzpJ21XPvK5PyjlkSFkFziNHGLc5d6g3di2McAAblmaSUNl8IOmzYwLx9NsE7bplNkwQ==",
2311 + "cpu": [
2312 + "x64"
2313 + ],
2314 + "dev": true,
2315 + "license": "MIT",
2316 + "optional": true,
2317 + "os": [
2318 + "linux"
2319 + ],
2320 + "engines": {
2321 + "node": ">= 10"
2322 + }
2323 + },
2324 + "node_modules/@tailwindcss/oxide-linux-x64-musl": {
2325 + "version": "4.1.17",
2326 + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.17.tgz",
2327 + "integrity": "sha512-k7f+pf9eXLEey4pBlw+8dgfJHY4PZ5qOUFDyNf7SI6lHjQ9Zt7+NcscjpwdCEbYi6FI5c2KDTDWyf2iHcCSyyQ==",
2328 + "cpu": [
2329 + "x64"
2330 + ],
2331 + "dev": true,
2332 + "license": "MIT",
2333 + "optional": true,
2334 + "os": [
2335 + "linux"
2336 + ],
2337 + "engines": {
2338 + "node": ">= 10"
2339 + }
2340 + },
2341 + "node_modules/@tailwindcss/oxide-wasm32-wasi": {
2342 + "version": "4.1.17",
2343 + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.17.tgz",
2344 + "integrity": "sha512-cEytGqSSoy7zK4JRWiTCx43FsKP/zGr0CsuMawhH67ONlH+T79VteQeJQRO/X7L0juEUA8ZyuYikcRBf0vsxhg==",
2345 + "bundleDependencies": [
2346 + "@napi-rs/wasm-runtime",
2347 + "@emnapi/core",
2348 + "@emnapi/runtime",
2349 + "@tybys/wasm-util",
2350 + "@emnapi/wasi-threads",
2351 + "tslib"
2352 + ],
2353 + "cpu": [
2354 + "wasm32"
2355 + ],
2356 + "dev": true,
2357 + "license": "MIT",
2358 + "optional": true,
2359 + "dependencies": {
2360 + "@emnapi/core": "^1.6.0",
2361 + "@emnapi/runtime": "^1.6.0",
2362 + "@emnapi/wasi-threads": "^1.1.0",
2363 + "@napi-rs/wasm-runtime": "^1.0.7",
2364 + "@tybys/wasm-util": "^0.10.1",
2365 + "tslib": "^2.4.0"
2366 + },
2367 + "engines": {
2368 + "node": ">=14.0.0"
2369 + }
2370 + },
2371 + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
2372 + "version": "4.1.17",
2373 + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.17.tgz",
2374 + "integrity": "sha512-JU5AHr7gKbZlOGvMdb4722/0aYbU+tN6lv1kONx0JK2cGsh7g148zVWLM0IKR3NeKLv+L90chBVYcJ8uJWbC9A==",
2375 + "cpu": [
2376 + "arm64"
2377 + ],
2378 + "dev": true,
2379 + "license": "MIT",
2380 + "optional": true,
2381 + "os": [
2382 + "win32"
2383 + ],
2384 + "engines": {
2385 + "node": ">= 10"
2386 + }
2387 + },
2388 + "node_modules/@tailwindcss/oxide-win32-x64-msvc": {
2389 + "version": "4.1.17",
2390 + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.17.tgz",
2391 + "integrity": "sha512-SKWM4waLuqx0IH+FMDUw6R66Hu4OuTALFgnleKbqhgGU30DY20NORZMZUKgLRjQXNN2TLzKvh48QXTig4h4bGw==",
2392 + "cpu": [
2393 + "x64"
2394 + ],
2395 + "dev": true,
2396 + "license": "MIT",
2397 + "optional": true,
2398 + "os": [
2399 + "win32"
2400 + ],
2401 + "engines": {
2402 + "node": ">= 10"
2403 + }
2404 + },
2405 + "node_modules/@tailwindcss/vite": {
2406 + "version": "4.1.17",
2407 + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.17.tgz",
2408 + "integrity": "sha512-4+9w8ZHOiGnpcGI6z1TVVfWaX/koK7fKeSYF3qlYg2xpBtbteP2ddBxiarL+HVgfSJGeK5RIxRQmKm4rTJJAwA==",
2409 + "dev": true,
2410 + "license": "MIT",
2411 + "dependencies": {
2412 + "@tailwindcss/node": "4.1.17",
2413 + "@tailwindcss/oxide": "4.1.17",
2414 + "tailwindcss": "4.1.17"
2415 + },
2416 + "peerDependencies": {
2417 + "vite": "^5.2.0 || ^6 || ^7"
2418 + }
2419 + },
2420 + "node_modules/@types/babel__core": {
2421 + "version": "7.20.5",
2422 + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
2423 + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
2424 + "dev": true,
2425 + "license": "MIT",
2426 + "dependencies": {
2427 + "@babel/parser": "^7.20.7",
2428 + "@babel/types": "^7.20.7",
2429 + "@types/babel__generator": "*",
2430 + "@types/babel__template": "*",
2431 + "@types/babel__traverse": "*"
2432 + }
2433 + },
2434 + "node_modules/@types/babel__generator": {
2435 + "version": "7.27.0",
2436 + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz",
2437 + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==",
2438 + "dev": true,
2439 + "license": "MIT",
2440 + "dependencies": {
2441 + "@babel/types": "^7.0.0"
2442 + }
2443 + },
2444 + "node_modules/@types/babel__template": {
2445 + "version": "7.4.4",
2446 + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
2447 + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
2448 + "dev": true,
2449 + "license": "MIT",
2450 + "dependencies": {
2451 + "@babel/parser": "^7.1.0",
2452 + "@babel/types": "^7.0.0"
2453 + }
2454 + },
2455 + "node_modules/@types/babel__traverse": {
2456 + "version": "7.28.0",
2457 + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz",
2458 + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==",
2459 + "dev": true,
2460 + "license": "MIT",
2461 + "dependencies": {
2462 + "@babel/types": "^7.28.2"
2463 + }
2464 + },
2465 + "node_modules/@types/estree": {
2466 + "version": "1.0.8",
2467 + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
2468 + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
2469 + "dev": true,
2470 + "license": "MIT"
2471 + },
2472 + "node_modules/@types/json-schema": {
2473 + "version": "7.0.15",
2474 + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
2475 + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
2476 + "dev": true,
2477 + "license": "MIT"
2478 + },
2479 + "node_modules/@types/node": {
2480 + "version": "24.10.1",
2481 + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz",
2482 + "integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==",
2483 + "dev": true,
2484 + "license": "MIT",
2485 + "dependencies": {
2486 + "undici-types": "~7.16.0"
2487 + }
2488 + },
2489 + "node_modules/@types/react": {
2490 + "version": "19.2.5",
2491 + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.5.tgz",
2492 + "integrity": "sha512-keKxkZMqnDicuvFoJbzrhbtdLSPhj/rZThDlKWCDbgXmUg0rEUFtRssDXKYmtXluZlIqiC5VqkCgRwzuyLHKHw==",
2493 + "devOptional": true,
2494 + "license": "MIT",
2495 + "dependencies": {
2496 + "csstype": "^3.0.2"
2497 + }
2498 + },
2499 + "node_modules/@types/react-dom": {
2500 + "version": "19.2.3",
2501 + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz",
2502 + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
2503 + "devOptional": true,
2504 + "license": "MIT",
2505 + "peerDependencies": {
2506 + "@types/react": "^19.2.0"
2507 + }
2508 + },
2509 + "node_modules/@typescript-eslint/eslint-plugin": {
2510 + "version": "8.46.4",
2511 + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.4.tgz",
2512 + "integrity": "sha512-R48VhmTJqplNyDxCyqqVkFSZIx1qX6PzwqgcXn1olLrzxcSBDlOsbtcnQuQhNtnNiJ4Xe5gREI1foajYaYU2Vg==",
2513 + "dev": true,
2514 + "license": "MIT",
2515 + "dependencies": {
2516 + "@eslint-community/regexpp": "^4.10.0",
2517 + "@typescript-eslint/scope-manager": "8.46.4",
2518 + "@typescript-eslint/type-utils": "8.46.4",
2519 + "@typescript-eslint/utils": "8.46.4",
2520 + "@typescript-eslint/visitor-keys": "8.46.4",
2521 + "graphemer": "^1.4.0",
2522 + "ignore": "^7.0.0",
2523 + "natural-compare": "^1.4.0",
2524 + "ts-api-utils": "^2.1.0"
2525 + },
2526 + "engines": {
2527 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
2528 + },
2529 + "funding": {
2530 + "type": "opencollective",
2531 + "url": "https://opencollective.com/typescript-eslint"
2532 + },
2533 + "peerDependencies": {
2534 + "@typescript-eslint/parser": "^8.46.4",
2535 + "eslint": "^8.57.0 || ^9.0.0",
2536 + "typescript": ">=4.8.4 <6.0.0"
2537 + }
2538 + },
2539 + "node_modules/@typescript-eslint/parser": {
2540 + "version": "8.46.4",
2541 + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.46.4.tgz",
2542 + "integrity": "sha512-tK3GPFWbirvNgsNKto+UmB/cRtn6TZfyw0D6IKrW55n6Vbs7KJoZtI//kpTKzE/DUmmnAFD8/Ca46s7Obs92/w==",
2543 + "dev": true,
2544 + "license": "MIT",
2545 + "dependencies": {
2546 + "@typescript-eslint/scope-manager": "8.46.4",
2547 + "@typescript-eslint/types": "8.46.4",
2548 + "@typescript-eslint/typescript-estree": "8.46.4",
2549 + "@typescript-eslint/visitor-keys": "8.46.4",
2550 + "debug": "^4.3.4"
2551 + },
2552 + "engines": {
2553 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
2554 + },
2555 + "funding": {
2556 + "type": "opencollective",
2557 + "url": "https://opencollective.com/typescript-eslint"
2558 + },
2559 + "peerDependencies": {
2560 + "eslint": "^8.57.0 || ^9.0.0",
2561 + "typescript": ">=4.8.4 <6.0.0"
2562 + }
2563 + },
2564 + "node_modules/@typescript-eslint/project-service": {
2565 + "version": "8.46.4",
2566 + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.46.4.tgz",
2567 + "integrity": "sha512-nPiRSKuvtTN+no/2N1kt2tUh/HoFzeEgOm9fQ6XQk4/ApGqjx0zFIIaLJ6wooR1HIoozvj2j6vTi/1fgAz7UYQ==",
2568 + "dev": true,
2569 + "license": "MIT",
2570 + "dependencies": {
2571 + "@typescript-eslint/tsconfig-utils": "^8.46.4",
2572 + "@typescript-eslint/types": "^8.46.4",
2573 + "debug": "^4.3.4"
2574 + },
2575 + "engines": {
2576 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
2577 + },
2578 + "funding": {
2579 + "type": "opencollective",
2580 + "url": "https://opencollective.com/typescript-eslint"
2581 + },
2582 + "peerDependencies": {
2583 + "typescript": ">=4.8.4 <6.0.0"
2584 + }
2585 + },
2586 + "node_modules/@typescript-eslint/scope-manager": {
2587 + "version": "8.46.4",
2588 + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.46.4.tgz",
2589 + "integrity": "sha512-tMDbLGXb1wC+McN1M6QeDx7P7c0UWO5z9CXqp7J8E+xGcJuUuevWKxuG8j41FoweS3+L41SkyKKkia16jpX7CA==",
2590 + "dev": true,
2591 + "license": "MIT",
2592 + "dependencies": {
2593 + "@typescript-eslint/types": "8.46.4",
2594 + "@typescript-eslint/visitor-keys": "8.46.4"
2595 + },
2596 + "engines": {
2597 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
2598 + },
2599 + "funding": {
2600 + "type": "opencollective",
2601 + "url": "https://opencollective.com/typescript-eslint"
2602 + }
2603 + },
2604 + "node_modules/@typescript-eslint/tsconfig-utils": {
2605 + "version": "8.46.4",
2606 + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.46.4.tgz",
2607 + "integrity": "sha512-+/XqaZPIAk6Cjg7NWgSGe27X4zMGqrFqZ8atJsX3CWxH/jACqWnrWI68h7nHQld0y+k9eTTjb9r+KU4twLoo9A==",
2608 + "dev": true,
2609 + "license": "MIT",
2610 + "engines": {
2611 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
2612 + },
2613 + "funding": {
2614 + "type": "opencollective",
2615 + "url": "https://opencollective.com/typescript-eslint"
2616 + },
2617 + "peerDependencies": {
2618 + "typescript": ">=4.8.4 <6.0.0"
2619 + }
2620 + },
2621 + "node_modules/@typescript-eslint/type-utils": {
2622 + "version": "8.46.4",
2623 + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.46.4.tgz",
2624 + "integrity": "sha512-V4QC8h3fdT5Wro6vANk6eojqfbv5bpwHuMsBcJUJkqs2z5XnYhJzyz9Y02eUmF9u3PgXEUiOt4w4KHR3P+z0PQ==",
2625 + "dev": true,
2626 + "license": "MIT",
2627 + "dependencies": {
2628 + "@typescript-eslint/types": "8.46.4",
2629 + "@typescript-eslint/typescript-estree": "8.46.4",
2630 + "@typescript-eslint/utils": "8.46.4",
2631 + "debug": "^4.3.4",
2632 + "ts-api-utils": "^2.1.0"
2633 + },
2634 + "engines": {
2635 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
2636 + },
2637 + "funding": {
2638 + "type": "opencollective",
2639 + "url": "https://opencollective.com/typescript-eslint"
2640 + },
2641 + "peerDependencies": {
2642 + "eslint": "^8.57.0 || ^9.0.0",
2643 + "typescript": ">=4.8.4 <6.0.0"
2644 + }
2645 + },
2646 + "node_modules/@typescript-eslint/types": {
2647 + "version": "8.46.4",
2648 + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.46.4.tgz",
2649 + "integrity": "sha512-USjyxm3gQEePdUwJBFjjGNG18xY9A2grDVGuk7/9AkjIF1L+ZrVnwR5VAU5JXtUnBL/Nwt3H31KlRDaksnM7/w==",
2650 + "dev": true,
2651 + "license": "MIT",
2652 + "engines": {
2653 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
2654 + },
2655 + "funding": {
2656 + "type": "opencollective",
2657 + "url": "https://opencollective.com/typescript-eslint"
2658 + }
2659 + },
2660 + "node_modules/@typescript-eslint/typescript-estree": {
2661 + "version": "8.46.4",
2662 + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.46.4.tgz",
2663 + "integrity": "sha512-7oV2qEOr1d4NWNmpXLR35LvCfOkTNymY9oyW+lUHkmCno7aOmIf/hMaydnJBUTBMRCOGZh8YjkFOc8dadEoNGA==",
2664 + "dev": true,
2665 + "license": "MIT",
2666 + "dependencies": {
2667 + "@typescript-eslint/project-service": "8.46.4",
2668 + "@typescript-eslint/tsconfig-utils": "8.46.4",
2669 + "@typescript-eslint/types": "8.46.4",
2670 + "@typescript-eslint/visitor-keys": "8.46.4",
2671 + "debug": "^4.3.4",
2672 + "fast-glob": "^3.3.2",
2673 + "is-glob": "^4.0.3",
2674 + "minimatch": "^9.0.4",
2675 + "semver": "^7.6.0",
2676 + "ts-api-utils": "^2.1.0"
2677 + },
2678 + "engines": {
2679 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
2680 + },
2681 + "funding": {
2682 + "type": "opencollective",
2683 + "url": "https://opencollective.com/typescript-eslint"
2684 + },
2685 + "peerDependencies": {
2686 + "typescript": ">=4.8.4 <6.0.0"
2687 + }
2688 + },
2689 + "node_modules/@typescript-eslint/utils": {
2690 + "version": "8.46.4",
2691 + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.46.4.tgz",
2692 + "integrity": "sha512-AbSv11fklGXV6T28dp2Me04Uw90R2iJ30g2bgLz529Koehrmkbs1r7paFqr1vPCZi7hHwYxYtxfyQMRC8QaVSg==",
2693 + "dev": true,
2694 + "license": "MIT",
2695 + "dependencies": {
2696 + "@eslint-community/eslint-utils": "^4.7.0",
2697 + "@typescript-eslint/scope-manager": "8.46.4",
2698 + "@typescript-eslint/types": "8.46.4",
2699 + "@typescript-eslint/typescript-estree": "8.46.4"
2700 + },
2701 + "engines": {
2702 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
2703 + },
2704 + "funding": {
2705 + "type": "opencollective",
2706 + "url": "https://opencollective.com/typescript-eslint"
2707 + },
2708 + "peerDependencies": {
2709 + "eslint": "^8.57.0 || ^9.0.0",
2710 + "typescript": ">=4.8.4 <6.0.0"
2711 + }
2712 + },
2713 + "node_modules/@typescript-eslint/visitor-keys": {
2714 + "version": "8.46.4",
2715 + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.46.4.tgz",
2716 + "integrity": "sha512-/++5CYLQqsO9HFGLI7APrxBJYo+5OCMpViuhV8q5/Qa3o5mMrF//eQHks+PXcsAVaLdn817fMuS7zqoXNNZGaw==",
2717 + "dev": true,
2718 + "license": "MIT",
2719 + "dependencies": {
2720 + "@typescript-eslint/types": "8.46.4",
2721 + "eslint-visitor-keys": "^4.2.1"
2722 + },
2723 + "engines": {
2724 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
2725 + },
2726 + "funding": {
2727 + "type": "opencollective",
2728 + "url": "https://opencollective.com/typescript-eslint"
2729 + }
2730 + },
2731 + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": {
2732 + "version": "4.2.1",
2733 + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
2734 + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
2735 + "dev": true,
2736 + "license": "Apache-2.0",
2737 + "engines": {
2738 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
2739 + },
2740 + "funding": {
2741 + "url": "https://opencollective.com/eslint"
2742 + }
2743 + },
2744 + "node_modules/@vitejs/plugin-react": {
2745 + "version": "5.1.1",
2746 + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.1.1.tgz",
2747 + "integrity": "sha512-WQfkSw0QbQ5aJ2CHYw23ZGkqnRwqKHD/KYsMeTkZzPT4Jcf0DcBxBtwMJxnu6E7oxw5+JC6ZAiePgh28uJ1HBA==",
2748 + "dev": true,
2749 + "license": "MIT",
2750 + "dependencies": {
2751 + "@babel/core": "^7.28.5",
2752 + "@babel/plugin-transform-react-jsx-self": "^7.27.1",
2753 + "@babel/plugin-transform-react-jsx-source": "^7.27.1",
2754 + "@rolldown/pluginutils": "1.0.0-beta.47",
2755 + "@types/babel__core": "^7.20.5",
2756 + "react-refresh": "^0.18.0"
2757 + },
2758 + "engines": {
2759 + "node": "^20.19.0 || >=22.12.0"
2760 + },
2761 + "peerDependencies": {
2762 + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
2763 + }
2764 + },
2765 + "node_modules/acorn": {
2766 + "version": "8.15.0",
2767 + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
2768 + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
2769 + "dev": true,
2770 + "license": "MIT",
2771 + "bin": {
2772 + "acorn": "bin/acorn"
2773 + },
2774 + "engines": {
2775 + "node": ">=0.4.0"
2776 + }
2777 + },
2778 + "node_modules/acorn-jsx": {
2779 + "version": "5.3.2",
2780 + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
2781 + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
2782 + "dev": true,
2783 + "license": "MIT",
2784 + "peerDependencies": {
2785 + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
2786 + }
2787 + },
2788 + "node_modules/ajv": {
2789 + "version": "6.12.6",
2790 + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
2791 + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
2792 + "dev": true,
2793 + "license": "MIT",
2794 + "dependencies": {
2795 + "fast-deep-equal": "^3.1.1",
2796 + "fast-json-stable-stringify": "^2.0.0",
2797 + "json-schema-traverse": "^0.4.1",
2798 + "uri-js": "^4.2.2"
2799 + },
2800 + "funding": {
2801 + "type": "github",
2802 + "url": "https://github.com/sponsors/epoberezkin"
2803 + }
2804 + },
2805 + "node_modules/ansi-styles": {
2806 + "version": "4.3.0",
2807 + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
2808 + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
2809 + "dev": true,
2810 + "license": "MIT",
2811 + "dependencies": {
2812 + "color-convert": "^2.0.1"
2813 + },
2814 + "engines": {
2815 + "node": ">=8"
2816 + },
2817 + "funding": {
2818 + "url": "https://github.com/chalk/ansi-styles?sponsor=1"
2819 + }
2820 + },
2821 + "node_modules/argparse": {
2822 + "version": "2.0.1",
2823 + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
2824 + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
2825 + "dev": true,
2826 + "license": "Python-2.0"
2827 + },
2828 + "node_modules/aria-hidden": {
2829 + "version": "1.2.6",
2830 + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz",
2831 + "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==",
2832 + "license": "MIT",
2833 + "dependencies": {
2834 + "tslib": "^2.0.0"
2835 + },
2836 + "engines": {
2837 + "node": ">=10"
2838 + }
2839 + },
2840 + "node_modules/balanced-match": {
2841 + "version": "1.0.2",
2842 + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
2843 + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
2844 + "dev": true,
2845 + "license": "MIT"
2846 + },
2847 + "node_modules/baseline-browser-mapping": {
2848 + "version": "2.8.28",
2849 + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.28.tgz",
2850 + "integrity": "sha512-gYjt7OIqdM0PcttNYP2aVrr2G0bMALkBaoehD4BuRGjAOtipg0b6wHg1yNL+s5zSnLZZrGHOw4IrND8CD+3oIQ==",
2851 + "dev": true,
2852 + "license": "Apache-2.0",
2853 + "bin": {
2854 + "baseline-browser-mapping": "dist/cli.js"
2855 + }
2856 + },
2857 + "node_modules/brace-expansion": {
2858 + "version": "2.0.2",
2859 + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
2860 + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
2861 + "dev": true,
2862 + "license": "MIT",
2863 + "dependencies": {
2864 + "balanced-match": "^1.0.0"
2865 + }
2866 + },
2867 + "node_modules/braces": {
2868 + "version": "3.0.3",
2869 + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
2870 + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
2871 + "dev": true,
2872 + "license": "MIT",
2873 + "dependencies": {
2874 + "fill-range": "^7.1.1"
2875 + },
2876 + "engines": {
2877 + "node": ">=8"
2878 + }
2879 + },
2880 + "node_modules/browserslist": {
2881 + "version": "4.28.0",
2882 + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.0.tgz",
2883 + "integrity": "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==",
2884 + "dev": true,
2885 + "funding": [
2886 + {
2887 + "type": "opencollective",
2888 + "url": "https://opencollective.com/browserslist"
2889 + },
2890 + {
2891 + "type": "tidelift",
2892 + "url": "https://tidelift.com/funding/github/npm/browserslist"
2893 + },
2894 + {
2895 + "type": "github",
2896 + "url": "https://github.com/sponsors/ai"
2897 + }
2898 + ],
2899 + "license": "MIT",
2900 + "dependencies": {
2901 + "baseline-browser-mapping": "^2.8.25",
2902 + "caniuse-lite": "^1.0.30001754",
2903 + "electron-to-chromium": "^1.5.249",
2904 + "node-releases": "^2.0.27",
2905 + "update-browserslist-db": "^1.1.4"
2906 + },
2907 + "bin": {
2908 + "browserslist": "cli.js"
2909 + },
2910 + "engines": {
2911 + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
2912 + }
2913 + },
2914 + "node_modules/callsites": {
2915 + "version": "3.1.0",
2916 + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
2917 + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
2918 + "dev": true,
2919 + "license": "MIT",
2920 + "engines": {
2921 + "node": ">=6"
2922 + }
2923 + },
2924 + "node_modules/caniuse-lite": {
2925 + "version": "1.0.30001754",
2926 + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001754.tgz",
2927 + "integrity": "sha512-x6OeBXueoAceOmotzx3PO4Zpt4rzpeIFsSr6AAePTZxSkXiYDUmpypEl7e2+8NCd9bD7bXjqyef8CJYPC1jfxg==",
2928 + "dev": true,
2929 + "funding": [
2930 + {
2931 + "type": "opencollective",
2932 + "url": "https://opencollective.com/browserslist"
2933 + },
2934 + {
2935 + "type": "tidelift",
2936 + "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
2937 + },
2938 + {
2939 + "type": "github",
2940 + "url": "https://github.com/sponsors/ai"
2941 + }
2942 + ],
2943 + "license": "CC-BY-4.0"
2944 + },
2945 + "node_modules/chalk": {
2946 + "version": "4.1.2",
2947 + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
2948 + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
2949 + "dev": true,
2950 + "license": "MIT",
2951 + "dependencies": {
2952 + "ansi-styles": "^4.1.0",
2953 + "supports-color": "^7.1.0"
2954 + },
2955 + "engines": {
2956 + "node": ">=10"
2957 + },
2958 + "funding": {
2959 + "url": "https://github.com/chalk/chalk?sponsor=1"
2960 + }
2961 + },
2962 + "node_modules/class-variance-authority": {
2963 + "version": "0.7.1",
2964 + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz",
2965 + "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==",
2966 + "license": "Apache-2.0",
2967 + "dependencies": {
2968 + "clsx": "^2.1.1"
2969 + },
2970 + "funding": {
2971 + "url": "https://polar.sh/cva"
2972 + }
2973 + },
2974 + "node_modules/clsx": {
2975 + "version": "2.1.1",
2976 + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
2977 + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
2978 + "license": "MIT",
2979 + "engines": {
2980 + "node": ">=6"
2981 + }
2982 + },
2983 + "node_modules/cmdk": {
2984 + "version": "1.1.1",
2985 + "resolved": "https://registry.npmjs.org/cmdk/-/cmdk-1.1.1.tgz",
2986 + "integrity": "sha512-Vsv7kFaXm+ptHDMZ7izaRsP70GgrW9NBNGswt9OZaVBLlE0SNpDq8eu/VGXyF9r7M0azK3Wy7OlYXsuyYLFzHg==",
2987 + "license": "MIT",
2988 + "dependencies": {
2989 + "@radix-ui/react-compose-refs": "^1.1.1",
2990 + "@radix-ui/react-dialog": "^1.1.6",
2991 + "@radix-ui/react-id": "^1.1.0",
2992 + "@radix-ui/react-primitive": "^2.0.2"
2993 + },
2994 + "peerDependencies": {
2995 + "react": "^18 || ^19 || ^19.0.0-rc",
2996 + "react-dom": "^18 || ^19 || ^19.0.0-rc"
2997 + }
2998 + },
2999 + "node_modules/color-convert": {
3000 + "version": "2.0.1",
3001 + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
3002 + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
3003 + "dev": true,
3004 + "license": "MIT",
3005 + "dependencies": {
3006 + "color-name": "~1.1.4"
3007 + },
3008 + "engines": {
3009 + "node": ">=7.0.0"
3010 + }
3011 + },
3012 + "node_modules/color-name": {
3013 + "version": "1.1.4",
3014 + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
3015 + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
3016 + "dev": true,
3017 + "license": "MIT"
3018 + },
3019 + "node_modules/concat-map": {
3020 + "version": "0.0.1",
3021 + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
3022 + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
3023 + "dev": true,
3024 + "license": "MIT"
3025 + },
3026 + "node_modules/convert-source-map": {
3027 + "version": "2.0.0",
3028 + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
3029 + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
3030 + "dev": true,
3031 + "license": "MIT"
3032 + },
3033 + "node_modules/cross-spawn": {
3034 + "version": "7.0.6",
3035 + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
3036 + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
3037 + "dev": true,
3038 + "license": "MIT",
3039 + "dependencies": {
3040 + "path-key": "^3.1.0",
3041 + "shebang-command": "^2.0.0",
3042 + "which": "^2.0.1"
3043 + },
3044 + "engines": {
3045 + "node": ">= 8"
3046 + }
3047 + },
3048 + "node_modules/csstype": {
3049 + "version": "3.2.1",
3050 + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.1.tgz",
3051 + "integrity": "sha512-98XGutrXoh75MlgLihlNxAGbUuFQc7l1cqcnEZlLNKc0UrVdPndgmaDmYTDDh929VS/eqTZV0rozmhu2qqT1/g==",
3052 + "devOptional": true,
3053 + "license": "MIT"
3054 + },
3055 + "node_modules/debug": {
3056 + "version": "4.4.3",
3057 + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
3058 + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
3059 + "dev": true,
3060 + "license": "MIT",
3061 + "dependencies": {
3062 + "ms": "^2.1.3"
3063 + },
3064 + "engines": {
3065 + "node": ">=6.0"
3066 + },
3067 + "peerDependenciesMeta": {
3068 + "supports-color": {
3069 + "optional": true
3070 + }
3071 + }
3072 + },
3073 + "node_modules/deep-is": {
3074 + "version": "0.1.4",
3075 + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
3076 + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
3077 + "dev": true,
3078 + "license": "MIT"
3079 + },
3080 + "node_modules/detect-libc": {
3081 + "version": "2.1.2",
3082 + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
3083 + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
3084 + "dev": true,
3085 + "license": "Apache-2.0",
3086 + "engines": {
3087 + "node": ">=8"
3088 + }
3089 + },
3090 + "node_modules/detect-node-es": {
3091 + "version": "1.1.0",
3092 + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
3093 + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==",
3094 + "license": "MIT"
3095 + },
3096 + "node_modules/electron-to-chromium": {
3097 + "version": "1.5.254",
3098 + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.254.tgz",
3099 + "integrity": "sha512-DcUsWpVhv9svsKRxnSCZ86SjD+sp32SGidNB37KpqXJncp1mfUgKbHvBomE89WJDbfVKw1mdv5+ikrvd43r+Bg==",
3100 + "dev": true,
3101 + "license": "ISC"
3102 + },
3103 + "node_modules/enhanced-resolve": {
3104 + "version": "5.18.3",
3105 + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz",
3106 + "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==",
3107 + "dev": true,
3108 + "license": "MIT",
3109 + "dependencies": {
3110 + "graceful-fs": "^4.2.4",
3111 + "tapable": "^2.2.0"
3112 + },
3113 + "engines": {
3114 + "node": ">=10.13.0"
3115 + }
3116 + },
3117 + "node_modules/esbuild": {
3118 + "version": "0.25.12",
3119 + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz",
3120 + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==",
3121 + "dev": true,
3122 + "hasInstallScript": true,
3123 + "license": "MIT",
3124 + "bin": {
3125 + "esbuild": "bin/esbuild"
3126 + },
3127 + "engines": {
3128 + "node": ">=18"
3129 + },
3130 + "optionalDependencies": {
3131 + "@esbuild/aix-ppc64": "0.25.12",
3132 + "@esbuild/android-arm": "0.25.12",
3133 + "@esbuild/android-arm64": "0.25.12",
3134 + "@esbuild/android-x64": "0.25.12",
3135 + "@esbuild/darwin-arm64": "0.25.12",
3136 + "@esbuild/darwin-x64": "0.25.12",
3137 + "@esbuild/freebsd-arm64": "0.25.12",
3138 + "@esbuild/freebsd-x64": "0.25.12",
3139 + "@esbuild/linux-arm": "0.25.12",
3140 + "@esbuild/linux-arm64": "0.25.12",
3141 + "@esbuild/linux-ia32": "0.25.12",
3142 + "@esbuild/linux-loong64": "0.25.12",
3143 + "@esbuild/linux-mips64el": "0.25.12",
3144 + "@esbuild/linux-ppc64": "0.25.12",
3145 + "@esbuild/linux-riscv64": "0.25.12",
3146 + "@esbuild/linux-s390x": "0.25.12",
3147 + "@esbuild/linux-x64": "0.25.12",
3148 + "@esbuild/netbsd-arm64": "0.25.12",
3149 + "@esbuild/netbsd-x64": "0.25.12",
3150 + "@esbuild/openbsd-arm64": "0.25.12",
3151 + "@esbuild/openbsd-x64": "0.25.12",
3152 + "@esbuild/openharmony-arm64": "0.25.12",
3153 + "@esbuild/sunos-x64": "0.25.12",
3154 + "@esbuild/win32-arm64": "0.25.12",
3155 + "@esbuild/win32-ia32": "0.25.12",
3156 + "@esbuild/win32-x64": "0.25.12"
3157 + }
3158 + },
3159 + "node_modules/escalade": {
3160 + "version": "3.2.0",
3161 + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
3162 + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
3163 + "dev": true,
3164 + "license": "MIT",
3165 + "engines": {
3166 + "node": ">=6"
3167 + }
3168 + },
3169 + "node_modules/escape-string-regexp": {
3170 + "version": "4.0.0",
3171 + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
3172 + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
3173 + "dev": true,
3174 + "license": "MIT",
3175 + "engines": {
3176 + "node": ">=10"
3177 + },
3178 + "funding": {
3179 + "url": "https://github.com/sponsors/sindresorhus"
3180 + }
3181 + },
3182 + "node_modules/eslint": {
3183 + "version": "9.39.1",
3184 + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz",
3185 + "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==",
3186 + "dev": true,
3187 + "license": "MIT",
3188 + "dependencies": {
3189 + "@eslint-community/eslint-utils": "^4.8.0",
3190 + "@eslint-community/regexpp": "^4.12.1",
3191 + "@eslint/config-array": "^0.21.1",
3192 + "@eslint/config-helpers": "^0.4.2",
3193 + "@eslint/core": "^0.17.0",
3194 + "@eslint/eslintrc": "^3.3.1",
3195 + "@eslint/js": "9.39.1",
3196 + "@eslint/plugin-kit": "^0.4.1",
3197 + "@humanfs/node": "^0.16.6",
3198 + "@humanwhocodes/module-importer": "^1.0.1",
3199 + "@humanwhocodes/retry": "^0.4.2",
3200 + "@types/estree": "^1.0.6",
3201 + "ajv": "^6.12.4",
3202 + "chalk": "^4.0.0",
3203 + "cross-spawn": "^7.0.6",
3204 + "debug": "^4.3.2",
3205 + "escape-string-regexp": "^4.0.0",
3206 + "eslint-scope": "^8.4.0",
3207 + "eslint-visitor-keys": "^4.2.1",
3208 + "espree": "^10.4.0",
3209 + "esquery": "^1.5.0",
3210 + "esutils": "^2.0.2",
3211 + "fast-deep-equal": "^3.1.3",
3212 + "file-entry-cache": "^8.0.0",
3213 + "find-up": "^5.0.0",
3214 + "glob-parent": "^6.0.2",
3215 + "ignore": "^5.2.0",
3216 + "imurmurhash": "^0.1.4",
3217 + "is-glob": "^4.0.0",
3218 + "json-stable-stringify-without-jsonify": "^1.0.1",
3219 + "lodash.merge": "^4.6.2",
3220 + "minimatch": "^3.1.2",
3221 + "natural-compare": "^1.4.0",
3222 + "optionator": "^0.9.3"
3223 + },
3224 + "bin": {
3225 + "eslint": "bin/eslint.js"
3226 + },
3227 + "engines": {
3228 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
3229 + },
3230 + "funding": {
3231 + "url": "https://eslint.org/donate"
3232 + },
3233 + "peerDependencies": {
3234 + "jiti": "*"
3235 + },
3236 + "peerDependenciesMeta": {
3237 + "jiti": {
3238 + "optional": true
3239 + }
3240 + }
3241 + },
3242 + "node_modules/eslint-plugin-react-hooks": {
3243 + "version": "7.0.1",
3244 + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.0.1.tgz",
3245 + "integrity": "sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==",
3246 + "dev": true,
3247 + "license": "MIT",
3248 + "dependencies": {
3249 + "@babel/core": "^7.24.4",
3250 + "@babel/parser": "^7.24.4",
3251 + "hermes-parser": "^0.25.1",
3252 + "zod": "^3.25.0 || ^4.0.0",
3253 + "zod-validation-error": "^3.5.0 || ^4.0.0"
3254 + },
3255 + "engines": {
3256 + "node": ">=18"
3257 + },
3258 + "peerDependencies": {
3259 + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0"
3260 + }
3261 + },
3262 + "node_modules/eslint-plugin-react-refresh": {
3263 + "version": "0.4.24",
3264 + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.24.tgz",
3265 + "integrity": "sha512-nLHIW7TEq3aLrEYWpVaJ1dRgFR+wLDPN8e8FpYAql/bMV2oBEfC37K0gLEGgv9fy66juNShSMV8OkTqzltcG/w==",
3266 + "dev": true,
3267 + "license": "MIT",
3268 + "peerDependencies": {
3269 + "eslint": ">=8.40"
3270 + }
3271 + },
3272 + "node_modules/eslint-scope": {
3273 + "version": "8.4.0",
3274 + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz",
3275 + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
3276 + "dev": true,
3277 + "license": "BSD-2-Clause",
3278 + "dependencies": {
3279 + "esrecurse": "^4.3.0",
3280 + "estraverse": "^5.2.0"
3281 + },
3282 + "engines": {
3283 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
3284 + },
3285 + "funding": {
3286 + "url": "https://opencollective.com/eslint"
3287 + }
3288 + },
3289 + "node_modules/eslint-visitor-keys": {
3290 + "version": "3.4.3",
3291 + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
3292 + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
3293 + "dev": true,
3294 + "license": "Apache-2.0",
3295 + "engines": {
3296 + "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
3297 + },
3298 + "funding": {
3299 + "url": "https://opencollective.com/eslint"
3300 + }
3301 + },
3302 + "node_modules/eslint/node_modules/brace-expansion": {
3303 + "version": "1.1.12",
3304 + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
3305 + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
3306 + "dev": true,
3307 + "license": "MIT",
3308 + "dependencies": {
3309 + "balanced-match": "^1.0.0",
3310 + "concat-map": "0.0.1"
3311 + }
3312 + },
3313 + "node_modules/eslint/node_modules/eslint-visitor-keys": {
3314 + "version": "4.2.1",
3315 + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
3316 + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
3317 + "dev": true,
3318 + "license": "Apache-2.0",
3319 + "engines": {
3320 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
3321 + },
3322 + "funding": {
3323 + "url": "https://opencollective.com/eslint"
3324 + }
3325 + },
3326 + "node_modules/eslint/node_modules/ignore": {
3327 + "version": "5.3.2",
3328 + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
3329 + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
3330 + "dev": true,
3331 + "license": "MIT",
3332 + "engines": {
3333 + "node": ">= 4"
3334 + }
3335 + },
3336 + "node_modules/eslint/node_modules/minimatch": {
3337 + "version": "3.1.2",
3338 + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
3339 + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
3340 + "dev": true,
3341 + "license": "ISC",
3342 + "dependencies": {
3343 + "brace-expansion": "^1.1.7"
3344 + },
3345 + "engines": {
3346 + "node": "*"
3347 + }
3348 + },
3349 + "node_modules/espree": {
3350 + "version": "10.4.0",
3351 + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
3352 + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
3353 + "dev": true,
3354 + "license": "BSD-2-Clause",
3355 + "dependencies": {
3356 + "acorn": "^8.15.0",
3357 + "acorn-jsx": "^5.3.2",
3358 + "eslint-visitor-keys": "^4.2.1"
3359 + },
3360 + "engines": {
3361 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
3362 + },
3363 + "funding": {
3364 + "url": "https://opencollective.com/eslint"
3365 + }
3366 + },
3367 + "node_modules/espree/node_modules/eslint-visitor-keys": {
3368 + "version": "4.2.1",
3369 + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
3370 + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
3371 + "dev": true,
3372 + "license": "Apache-2.0",
3373 + "engines": {
3374 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
3375 + },
3376 + "funding": {
3377 + "url": "https://opencollective.com/eslint"
3378 + }
3379 + },
3380 + "node_modules/esquery": {
3381 + "version": "1.6.0",
3382 + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
3383 + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",
3384 + "dev": true,
3385 + "license": "BSD-3-Clause",
3386 + "dependencies": {
3387 + "estraverse": "^5.1.0"
3388 + },
3389 + "engines": {
3390 + "node": ">=0.10"
3391 + }
3392 + },
3393 + "node_modules/esrecurse": {
3394 + "version": "4.3.0",
3395 + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
3396 + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
3397 + "dev": true,
3398 + "license": "BSD-2-Clause",
3399 + "dependencies": {
3400 + "estraverse": "^5.2.0"
3401 + },
3402 + "engines": {
3403 + "node": ">=4.0"
3404 + }
3405 + },
3406 + "node_modules/estraverse": {
3407 + "version": "5.3.0",
3408 + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
3409 + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
3410 + "dev": true,
3411 + "license": "BSD-2-Clause",
3412 + "engines": {
3413 + "node": ">=4.0"
3414 + }
3415 + },
3416 + "node_modules/esutils": {
3417 + "version": "2.0.3",
3418 + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
3419 + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
3420 + "dev": true,
3421 + "license": "BSD-2-Clause",
3422 + "engines": {
3423 + "node": ">=0.10.0"
3424 + }
3425 + },
3426 + "node_modules/fast-deep-equal": {
3427 + "version": "3.1.3",
3428 + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
3429 + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
3430 + "dev": true,
3431 + "license": "MIT"
3432 + },
3433 + "node_modules/fast-glob": {
3434 + "version": "3.3.3",
3435 + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
3436 + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
3437 + "dev": true,
3438 + "license": "MIT",
3439 + "dependencies": {
3440 + "@nodelib/fs.stat": "^2.0.2",
3441 + "@nodelib/fs.walk": "^1.2.3",
3442 + "glob-parent": "^5.1.2",
3443 + "merge2": "^1.3.0",
3444 + "micromatch": "^4.0.8"
3445 + },
3446 + "engines": {
3447 + "node": ">=8.6.0"
3448 + }
3449 + },
3450 + "node_modules/fast-glob/node_modules/glob-parent": {
3451 + "version": "5.1.2",
3452 + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
3453 + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
3454 + "dev": true,
3455 + "license": "ISC",
3456 + "dependencies": {
3457 + "is-glob": "^4.0.1"
3458 + },
3459 + "engines": {
3460 + "node": ">= 6"
3461 + }
3462 + },
3463 + "node_modules/fast-json-stable-stringify": {
3464 + "version": "2.1.0",
3465 + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
3466 + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
3467 + "dev": true,
3468 + "license": "MIT"
3469 + },
3470 + "node_modules/fast-levenshtein": {
3471 + "version": "2.0.6",
3472 + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
3473 + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
3474 + "dev": true,
3475 + "license": "MIT"
3476 + },
3477 + "node_modules/fastq": {
3478 + "version": "1.19.1",
3479 + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz",
3480 + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==",
3481 + "dev": true,
3482 + "license": "ISC",
3483 + "dependencies": {
3484 + "reusify": "^1.0.4"
3485 + }
3486 + },
3487 + "node_modules/file-entry-cache": {
3488 + "version": "8.0.0",
3489 + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
3490 + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==",
3491 + "dev": true,
3492 + "license": "MIT",
3493 + "dependencies": {
3494 + "flat-cache": "^4.0.0"
3495 + },
3496 + "engines": {
3497 + "node": ">=16.0.0"
3498 + }
3499 + },
3500 + "node_modules/fill-range": {
3501 + "version": "7.1.1",
3502 + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
3503 + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
3504 + "dev": true,
3505 + "license": "MIT",
3506 + "dependencies": {
3507 + "to-regex-range": "^5.0.1"
3508 + },
3509 + "engines": {
3510 + "node": ">=8"
3511 + }
3512 + },
3513 + "node_modules/find-up": {
3514 + "version": "5.0.0",
3515 + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
3516 + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
3517 + "dev": true,
3518 + "license": "MIT",
3519 + "dependencies": {
3520 + "locate-path": "^6.0.0",
3521 + "path-exists": "^4.0.0"
3522 + },
3523 + "engines": {
3524 + "node": ">=10"
3525 + },
3526 + "funding": {
3527 + "url": "https://github.com/sponsors/sindresorhus"
3528 + }
3529 + },
3530 + "node_modules/flat-cache": {
3531 + "version": "4.0.1",
3532 + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
3533 + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==",
3534 + "dev": true,
3535 + "license": "MIT",
3536 + "dependencies": {
3537 + "flatted": "^3.2.9",
3538 + "keyv": "^4.5.4"
3539 + },
3540 + "engines": {
3541 + "node": ">=16"
3542 + }
3543 + },
3544 + "node_modules/flatted": {
3545 + "version": "3.3.3",
3546 + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
3547 + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
3548 + "dev": true,
3549 + "license": "ISC"
3550 + },
3551 + "node_modules/fsevents": {
3552 + "version": "2.3.3",
3553 + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
3554 + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
3555 + "dev": true,
3556 + "hasInstallScript": true,
3557 + "license": "MIT",
3558 + "optional": true,
3559 + "os": [
3560 + "darwin"
3561 + ],
3562 + "engines": {
3563 + "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
3564 + }
3565 + },
3566 + "node_modules/gensync": {
3567 + "version": "1.0.0-beta.2",
3568 + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
3569 + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
3570 + "dev": true,
3571 + "license": "MIT",
3572 + "engines": {
3573 + "node": ">=6.9.0"
3574 + }
3575 + },
3576 + "node_modules/get-nonce": {
3577 + "version": "1.0.1",
3578 + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz",
3579 + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==",
3580 + "license": "MIT",
3581 + "engines": {
3582 + "node": ">=6"
3583 + }
3584 + },
3585 + "node_modules/glob-parent": {
3586 + "version": "6.0.2",
3587 + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
3588 + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
3589 + "dev": true,
3590 + "license": "ISC",
3591 + "dependencies": {
3592 + "is-glob": "^4.0.3"
3593 + },
3594 + "engines": {
3595 + "node": ">=10.13.0"
3596 + }
3597 + },
3598 + "node_modules/globals": {
3599 + "version": "14.0.0",
3600 + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
3601 + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
3602 + "dev": true,
3603 + "license": "MIT",
3604 + "engines": {
3605 + "node": ">=18"
3606 + },
3607 + "funding": {
3608 + "url": "https://github.com/sponsors/sindresorhus"
3609 + }
3610 + },
3611 + "node_modules/graceful-fs": {
3612 + "version": "4.2.11",
3613 + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
3614 + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
3615 + "dev": true,
3616 + "license": "ISC"
3617 + },
3618 + "node_modules/graphemer": {
3619 + "version": "1.4.0",
3620 + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
3621 + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
3622 + "dev": true,
3623 + "license": "MIT"
3624 + },
3625 + "node_modules/has-flag": {
3626 + "version": "4.0.0",
3627 + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
3628 + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
3629 + "dev": true,
3630 + "license": "MIT",
3631 + "engines": {
3632 + "node": ">=8"
3633 + }
3634 + },
3635 + "node_modules/hermes-estree": {
3636 + "version": "0.25.1",
3637 + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz",
3638 + "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==",
3639 + "dev": true,
3640 + "license": "MIT"
3641 + },
3642 + "node_modules/hermes-parser": {
3643 + "version": "0.25.1",
3644 + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz",
3645 + "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==",
3646 + "dev": true,
3647 + "license": "MIT",
3648 + "dependencies": {
3649 + "hermes-estree": "0.25.1"
3650 + }
3651 + },
3652 + "node_modules/ignore": {
3653 + "version": "7.0.5",
3654 + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz",
3655 + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==",
3656 + "dev": true,
3657 + "license": "MIT",
3658 + "engines": {
3659 + "node": ">= 4"
3660 + }
3661 + },
3662 + "node_modules/import-fresh": {
3663 + "version": "3.3.1",
3664 + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
3665 + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
3666 + "dev": true,
3667 + "license": "MIT",
3668 + "dependencies": {
3669 + "parent-module": "^1.0.0",
3670 + "resolve-from": "^4.0.0"
3671 + },
3672 + "engines": {
3673 + "node": ">=6"
3674 + },
3675 + "funding": {
3676 + "url": "https://github.com/sponsors/sindresorhus"
3677 + }
3678 + },
3679 + "node_modules/imurmurhash": {
3680 + "version": "0.1.4",
3681 + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
3682 + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
3683 + "dev": true,
3684 + "license": "MIT",
3685 + "engines": {
3686 + "node": ">=0.8.19"
3687 + }
3688 + },
3689 + "node_modules/is-extglob": {
3690 + "version": "2.1.1",
3691 + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
3692 + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
3693 + "dev": true,
3694 + "license": "MIT",
3695 + "engines": {
3696 + "node": ">=0.10.0"
3697 + }
3698 + },
3699 + "node_modules/is-glob": {
3700 + "version": "4.0.3",
3701 + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
3702 + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
3703 + "dev": true,
3704 + "license": "MIT",
3705 + "dependencies": {
3706 + "is-extglob": "^2.1.1"
3707 + },
3708 + "engines": {
3709 + "node": ">=0.10.0"
3710 + }
3711 + },
3712 + "node_modules/is-number": {
3713 + "version": "7.0.0",
3714 + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
3715 + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
3716 + "dev": true,
3717 + "license": "MIT",
3718 + "engines": {
3719 + "node": ">=0.12.0"
3720 + }
3721 + },
3722 + "node_modules/isexe": {
3723 + "version": "2.0.0",
3724 + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
3725 + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
3726 + "dev": true,
3727 + "license": "ISC"
3728 + },
3729 + "node_modules/jiti": {
3730 + "version": "2.6.1",
3731 + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz",
3732 + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==",
3733 + "dev": true,
3734 + "license": "MIT",
3735 + "bin": {
3736 + "jiti": "lib/jiti-cli.mjs"
3737 + }
3738 + },
3739 + "node_modules/js-tokens": {
3740 + "version": "4.0.0",
3741 + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
3742 + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
3743 + "dev": true,
3744 + "license": "MIT"
3745 + },
3746 + "node_modules/js-yaml": {
3747 + "version": "4.1.1",
3748 + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
3749 + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
3750 + "dev": true,
3751 + "license": "MIT",
3752 + "dependencies": {
3753 + "argparse": "^2.0.1"
3754 + },
3755 + "bin": {
3756 + "js-yaml": "bin/js-yaml.js"
3757 + }
3758 + },
3759 + "node_modules/jsesc": {
3760 + "version": "3.1.0",
3761 + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
3762 + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
3763 + "dev": true,
3764 + "license": "MIT",
3765 + "bin": {
3766 + "jsesc": "bin/jsesc"
3767 + },
3768 + "engines": {
3769 + "node": ">=6"
3770 + }
3771 + },
3772 + "node_modules/json-buffer": {
3773 + "version": "3.0.1",
3774 + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
3775 + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
3776 + "dev": true,
3777 + "license": "MIT"
3778 + },
3779 + "node_modules/json-schema-traverse": {
3780 + "version": "0.4.1",
3781 + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
3782 + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
3783 + "dev": true,
3784 + "license": "MIT"
3785 + },
3786 + "node_modules/json-stable-stringify-without-jsonify": {
3787 + "version": "1.0.1",
3788 + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
3789 + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
3790 + "dev": true,
3791 + "license": "MIT"
3792 + },
3793 + "node_modules/json5": {
3794 + "version": "2.2.3",
3795 + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
3796 + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
3797 + "dev": true,
3798 + "license": "MIT",
3799 + "bin": {
3800 + "json5": "lib/cli.js"
3801 + },
3802 + "engines": {
3803 + "node": ">=6"
3804 + }
3805 + },
3806 + "node_modules/keyv": {
3807 + "version": "4.5.4",
3808 + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
3809 + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
3810 + "dev": true,
3811 + "license": "MIT",
3812 + "dependencies": {
3813 + "json-buffer": "3.0.1"
3814 + }
3815 + },
3816 + "node_modules/levn": {
3817 + "version": "0.4.1",
3818 + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
3819 + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
3820 + "dev": true,
3821 + "license": "MIT",
3822 + "dependencies": {
3823 + "prelude-ls": "^1.2.1",
3824 + "type-check": "~0.4.0"
3825 + },
3826 + "engines": {
3827 + "node": ">= 0.8.0"
3828 + }
3829 + },
3830 + "node_modules/lightningcss": {
3831 + "version": "1.30.2",
3832 + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.2.tgz",
3833 + "integrity": "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==",
3834 + "dev": true,
3835 + "license": "MPL-2.0",
3836 + "dependencies": {
3837 + "detect-libc": "^2.0.3"
3838 + },
3839 + "engines": {
3840 + "node": ">= 12.0.0"
3841 + },
3842 + "funding": {
3843 + "type": "opencollective",
3844 + "url": "https://opencollective.com/parcel"
3845 + },
3846 + "optionalDependencies": {
3847 + "lightningcss-android-arm64": "1.30.2",
3848 + "lightningcss-darwin-arm64": "1.30.2",
3849 + "lightningcss-darwin-x64": "1.30.2",
3850 + "lightningcss-freebsd-x64": "1.30.2",
3851 + "lightningcss-linux-arm-gnueabihf": "1.30.2",
3852 + "lightningcss-linux-arm64-gnu": "1.30.2",
3853 + "lightningcss-linux-arm64-musl": "1.30.2",
3854 + "lightningcss-linux-x64-gnu": "1.30.2",
3855 + "lightningcss-linux-x64-musl": "1.30.2",
3856 + "lightningcss-win32-arm64-msvc": "1.30.2",
3857 + "lightningcss-win32-x64-msvc": "1.30.2"
3858 + }
3859 + },
3860 + "node_modules/lightningcss-android-arm64": {
3861 + "version": "1.30.2",
3862 + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.30.2.tgz",
3863 + "integrity": "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==",
3864 + "cpu": [
3865 + "arm64"
3866 + ],
3867 + "dev": true,
3868 + "license": "MPL-2.0",
3869 + "optional": true,
3870 + "os": [
3871 + "android"
3872 + ],
3873 + "engines": {
3874 + "node": ">= 12.0.0"
3875 + },
3876 + "funding": {
3877 + "type": "opencollective",
3878 + "url": "https://opencollective.com/parcel"
3879 + }
3880 + },
3881 + "node_modules/lightningcss-darwin-arm64": {
3882 + "version": "1.30.2",
3883 + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.2.tgz",
3884 + "integrity": "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==",
3885 + "cpu": [
3886 + "arm64"
3887 + ],
3888 + "dev": true,
3889 + "license": "MPL-2.0",
3890 + "optional": true,
3891 + "os": [
3892 + "darwin"
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-darwin-x64": {
3903 + "version": "1.30.2",
3904 + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.2.tgz",
3905 + "integrity": "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==",
3906 + "cpu": [
3907 + "x64"
3908 + ],
3909 + "dev": true,
3910 + "license": "MPL-2.0",
3911 + "optional": true,
3912 + "os": [
3913 + "darwin"
3914 + ],
3915 + "engines": {
3916 + "node": ">= 12.0.0"
3917 + },
3918 + "funding": {
3919 + "type": "opencollective",
3920 + "url": "https://opencollective.com/parcel"
3921 + }
3922 + },
3923 + "node_modules/lightningcss-freebsd-x64": {
3924 + "version": "1.30.2",
3925 + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.2.tgz",
3926 + "integrity": "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==",
3927 + "cpu": [
3928 + "x64"
3929 + ],
3930 + "dev": true,
3931 + "license": "MPL-2.0",
3932 + "optional": true,
3933 + "os": [
3934 + "freebsd"
3935 + ],
3936 + "engines": {
3937 + "node": ">= 12.0.0"
3938 + },
3939 + "funding": {
3940 + "type": "opencollective",
3941 + "url": "https://opencollective.com/parcel"
3942 + }
3943 + },
3944 + "node_modules/lightningcss-linux-arm-gnueabihf": {
3945 + "version": "1.30.2",
3946 + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.2.tgz",
3947 + "integrity": "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==",
3948 + "cpu": [
3949 + "arm"
3950 + ],
3951 + "dev": true,
3952 + "license": "MPL-2.0",
3953 + "optional": true,
3954 + "os": [
3955 + "linux"
3956 + ],
3957 + "engines": {
3958 + "node": ">= 12.0.0"
3959 + },
3960 + "funding": {
3961 + "type": "opencollective",
3962 + "url": "https://opencollective.com/parcel"
3963 + }
3964 + },
3965 + "node_modules/lightningcss-linux-arm64-gnu": {
3966 + "version": "1.30.2",
3967 + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.2.tgz",
3968 + "integrity": "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==",
3969 + "cpu": [
3970 + "arm64"
3971 + ],
3972 + "dev": true,
3973 + "license": "MPL-2.0",
3974 + "optional": true,
3975 + "os": [
3976 + "linux"
3977 + ],
3978 + "engines": {
3979 + "node": ">= 12.0.0"
3980 + },
3981 + "funding": {
3982 + "type": "opencollective",
3983 + "url": "https://opencollective.com/parcel"
3984 + }
3985 + },
3986 + "node_modules/lightningcss-linux-arm64-musl": {
3987 + "version": "1.30.2",
3988 + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.2.tgz",
3989 + "integrity": "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==",
3990 + "cpu": [
3991 + "arm64"
3992 + ],
3993 + "dev": true,
3994 + "license": "MPL-2.0",
3995 + "optional": true,
3996 + "os": [
3997 + "linux"
3998 + ],
3999 + "engines": {
4000 + "node": ">= 12.0.0"
4001 + },
4002 + "funding": {
4003 + "type": "opencollective",
4004 + "url": "https://opencollective.com/parcel"
4005 + }
4006 + },
4007 + "node_modules/lightningcss-linux-x64-gnu": {
4008 + "version": "1.30.2",
4009 + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.2.tgz",
4010 + "integrity": "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==",
4011 + "cpu": [
4012 + "x64"
4013 + ],
4014 + "dev": true,
4015 + "license": "MPL-2.0",
4016 + "optional": true,
4017 + "os": [
4018 + "linux"
4019 + ],
4020 + "engines": {
4021 + "node": ">= 12.0.0"
4022 + },
4023 + "funding": {
4024 + "type": "opencollective",
4025 + "url": "https://opencollective.com/parcel"
4026 + }
4027 + },
4028 + "node_modules/lightningcss-linux-x64-musl": {
4029 + "version": "1.30.2",
4030 + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.2.tgz",
4031 + "integrity": "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==",
4032 + "cpu": [
4033 + "x64"
4034 + ],
4035 + "dev": true,
4036 + "license": "MPL-2.0",
4037 + "optional": true,
4038 + "os": [
4039 + "linux"
4040 + ],
4041 + "engines": {
4042 + "node": ">= 12.0.0"
4043 + },
4044 + "funding": {
4045 + "type": "opencollective",
4046 + "url": "https://opencollective.com/parcel"
4047 + }
4048 + },
4049 + "node_modules/lightningcss-win32-arm64-msvc": {
4050 + "version": "1.30.2",
4051 + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.2.tgz",
4052 + "integrity": "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==",
4053 + "cpu": [
4054 + "arm64"
4055 + ],
4056 + "dev": true,
4057 + "license": "MPL-2.0",
4058 + "optional": true,
4059 + "os": [
4060 + "win32"
4061 + ],
4062 + "engines": {
4063 + "node": ">= 12.0.0"
4064 + },
4065 + "funding": {
4066 + "type": "opencollective",
4067 + "url": "https://opencollective.com/parcel"
4068 + }
4069 + },
4070 + "node_modules/lightningcss-win32-x64-msvc": {
4071 + "version": "1.30.2",
4072 + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.2.tgz",
4073 + "integrity": "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==",
4074 + "cpu": [
4075 + "x64"
4076 + ],
4077 + "dev": true,
4078 + "license": "MPL-2.0",
4079 + "optional": true,
4080 + "os": [
4081 + "win32"
4082 + ],
4083 + "engines": {
4084 + "node": ">= 12.0.0"
4085 + },
4086 + "funding": {
4087 + "type": "opencollective",
4088 + "url": "https://opencollective.com/parcel"
4089 + }
4090 + },
4091 + "node_modules/locate-path": {
4092 + "version": "6.0.0",
4093 + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
4094 + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
4095 + "dev": true,
4096 + "license": "MIT",
4097 + "dependencies": {
4098 + "p-locate": "^5.0.0"
4099 + },
4100 + "engines": {
4101 + "node": ">=10"
4102 + },
4103 + "funding": {
4104 + "url": "https://github.com/sponsors/sindresorhus"
4105 + }
4106 + },
4107 + "node_modules/lodash.merge": {
4108 + "version": "4.6.2",
4109 + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
4110 + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
4111 + "dev": true,
4112 + "license": "MIT"
4113 + },
4114 + "node_modules/lru-cache": {
4115 + "version": "5.1.1",
4116 + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
4117 + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
4118 + "dev": true,
4119 + "license": "ISC",
4120 + "dependencies": {
4121 + "yallist": "^3.0.2"
4122 + }
4123 + },
4124 + "node_modules/lucide-react": {
4125 + "version": "0.553.0",
4126 + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.553.0.tgz",
4127 + "integrity": "sha512-BRgX5zrWmNy/lkVAe0dXBgd7XQdZ3HTf+Hwe3c9WK6dqgnj9h+hxV+MDncM88xDWlCq27+TKvHGE70ViODNILw==",
4128 + "license": "ISC",
4129 + "peerDependencies": {
4130 + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
4131 + }
4132 + },
4133 + "node_modules/magic-string": {
4134 + "version": "0.30.21",
4135 + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
4136 + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
4137 + "dev": true,
4138 + "license": "MIT",
4139 + "dependencies": {
4140 + "@jridgewell/sourcemap-codec": "^1.5.5"
4141 + }
4142 + },
4143 + "node_modules/merge2": {
4144 + "version": "1.4.1",
4145 + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
4146 + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
4147 + "dev": true,
4148 + "license": "MIT",
4149 + "engines": {
4150 + "node": ">= 8"
4151 + }
4152 + },
4153 + "node_modules/micromatch": {
4154 + "version": "4.0.8",
4155 + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
4156 + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
4157 + "dev": true,
4158 + "license": "MIT",
4159 + "dependencies": {
4160 + "braces": "^3.0.3",
4161 + "picomatch": "^2.3.1"
4162 + },
4163 + "engines": {
4164 + "node": ">=8.6"
4165 + }
4166 + },
4167 + "node_modules/minimatch": {
4168 + "version": "9.0.5",
4169 + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
4170 + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
4171 + "dev": true,
4172 + "license": "ISC",
4173 + "dependencies": {
4174 + "brace-expansion": "^2.0.1"
4175 + },
4176 + "engines": {
4177 + "node": ">=16 || 14 >=14.17"
4178 + },
4179 + "funding": {
4180 + "url": "https://github.com/sponsors/isaacs"
4181 + }
4182 + },
4183 + "node_modules/ms": {
4184 + "version": "2.1.3",
4185 + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
4186 + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
4187 + "dev": true,
4188 + "license": "MIT"
4189 + },
4190 + "node_modules/nanoid": {
4191 + "version": "3.3.11",
4192 + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
4193 + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
4194 + "dev": true,
4195 + "funding": [
4196 + {
4197 + "type": "github",
4198 + "url": "https://github.com/sponsors/ai"
4199 + }
4200 + ],
4201 + "license": "MIT",
4202 + "bin": {
4203 + "nanoid": "bin/nanoid.cjs"
4204 + },
4205 + "engines": {
4206 + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
4207 + }
4208 + },
4209 + "node_modules/natural-compare": {
4210 + "version": "1.4.0",
4211 + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
4212 + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
4213 + "dev": true,
4214 + "license": "MIT"
4215 + },
4216 + "node_modules/node-releases": {
4217 + "version": "2.0.27",
4218 + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz",
4219 + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==",
4220 + "dev": true,
4221 + "license": "MIT"
4222 + },
4223 + "node_modules/optionator": {
4224 + "version": "0.9.4",
4225 + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
4226 + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
4227 + "dev": true,
4228 + "license": "MIT",
4229 + "dependencies": {
4230 + "deep-is": "^0.1.3",
4231 + "fast-levenshtein": "^2.0.6",
4232 + "levn": "^0.4.1",
4233 + "prelude-ls": "^1.2.1",
4234 + "type-check": "^0.4.0",
4235 + "word-wrap": "^1.2.5"
4236 + },
4237 + "engines": {
4238 + "node": ">= 0.8.0"
4239 + }
4240 + },
4241 + "node_modules/p-limit": {
4242 + "version": "3.1.0",
4243 + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
4244 + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
4245 + "dev": true,
4246 + "license": "MIT",
4247 + "dependencies": {
4248 + "yocto-queue": "^0.1.0"
4249 + },
4250 + "engines": {
4251 + "node": ">=10"
4252 + },
4253 + "funding": {
4254 + "url": "https://github.com/sponsors/sindresorhus"
4255 + }
4256 + },
4257 + "node_modules/p-locate": {
4258 + "version": "5.0.0",
4259 + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
4260 + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
4261 + "dev": true,
4262 + "license": "MIT",
4263 + "dependencies": {
4264 + "p-limit": "^3.0.2"
4265 + },
4266 + "engines": {
4267 + "node": ">=10"
4268 + },
4269 + "funding": {
4270 + "url": "https://github.com/sponsors/sindresorhus"
4271 + }
4272 + },
4273 + "node_modules/parent-module": {
4274 + "version": "1.0.1",
4275 + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
4276 + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
4277 + "dev": true,
4278 + "license": "MIT",
4279 + "dependencies": {
4280 + "callsites": "^3.0.0"
4281 + },
4282 + "engines": {
4283 + "node": ">=6"
4284 + }
4285 + },
4286 + "node_modules/path-exists": {
4287 + "version": "4.0.0",
4288 + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
4289 + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
4290 + "dev": true,
4291 + "license": "MIT",
4292 + "engines": {
4293 + "node": ">=8"
4294 + }
4295 + },
4296 + "node_modules/path-key": {
4297 + "version": "3.1.1",
4298 + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
4299 + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
4300 + "dev": true,
4301 + "license": "MIT",
4302 + "engines": {
4303 + "node": ">=8"
4304 + }
4305 + },
4306 + "node_modules/picocolors": {
4307 + "version": "1.1.1",
4308 + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
4309 + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
4310 + "dev": true,
4311 + "license": "ISC"
4312 + },
4313 + "node_modules/picomatch": {
4314 + "version": "2.3.1",
4315 + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
4316 + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
4317 + "dev": true,
4318 + "license": "MIT",
4319 + "engines": {
4320 + "node": ">=8.6"
4321 + },
4322 + "funding": {
4323 + "url": "https://github.com/sponsors/jonschlinkert"
4324 + }
4325 + },
4326 + "node_modules/postcss": {
4327 + "version": "8.5.6",
4328 + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
4329 + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
4330 + "dev": true,
4331 + "funding": [
4332 + {
4333 + "type": "opencollective",
4334 + "url": "https://opencollective.com/postcss/"
4335 + },
4336 + {
4337 + "type": "tidelift",
4338 + "url": "https://tidelift.com/funding/github/npm/postcss"
4339 + },
4340 + {
4341 + "type": "github",
4342 + "url": "https://github.com/sponsors/ai"
4343 + }
4344 + ],
4345 + "license": "MIT",
4346 + "dependencies": {
4347 + "nanoid": "^3.3.11",
4348 + "picocolors": "^1.1.1",
4349 + "source-map-js": "^1.2.1"
4350 + },
4351 + "engines": {
4352 + "node": "^10 || ^12 || >=14"
4353 + }
4354 + },
4355 + "node_modules/prelude-ls": {
4356 + "version": "1.2.1",
4357 + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
4358 + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
4359 + "dev": true,
4360 + "license": "MIT",
4361 + "engines": {
4362 + "node": ">= 0.8.0"
4363 + }
4364 + },
4365 + "node_modules/punycode": {
4366 + "version": "2.3.1",
4367 + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
4368 + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
4369 + "dev": true,
4370 + "license": "MIT",
4371 + "engines": {
4372 + "node": ">=6"
4373 + }
4374 + },
4375 + "node_modules/queue-microtask": {
4376 + "version": "1.2.3",
4377 + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
4378 + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
4379 + "dev": true,
4380 + "funding": [
4381 + {
4382 + "type": "github",
4383 + "url": "https://github.com/sponsors/feross"
4384 + },
4385 + {
4386 + "type": "patreon",
4387 + "url": "https://www.patreon.com/feross"
4388 + },
4389 + {
4390 + "type": "consulting",
4391 + "url": "https://feross.org/support"
4392 + }
4393 + ],
4394 + "license": "MIT"
4395 + },
4396 + "node_modules/react": {
4397 + "version": "19.2.0",
4398 + "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz",
4399 + "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==",
4400 + "license": "MIT",
4401 + "engines": {
4402 + "node": ">=0.10.0"
4403 + }
4404 + },
4405 + "node_modules/react-dom": {
4406 + "version": "19.2.0",
4407 + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz",
4408 + "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==",
4409 + "license": "MIT",
4410 + "dependencies": {
4411 + "scheduler": "^0.27.0"
4412 + },
4413 + "peerDependencies": {
4414 + "react": "^19.2.0"
4415 + }
4416 + },
4417 + "node_modules/react-refresh": {
4418 + "version": "0.18.0",
4419 + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz",
4420 + "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==",
4421 + "dev": true,
4422 + "license": "MIT",
4423 + "engines": {
4424 + "node": ">=0.10.0"
4425 + }
4426 + },
4427 + "node_modules/react-remove-scroll": {
4428 + "version": "2.7.1",
4429 + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.1.tgz",
4430 + "integrity": "sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==",
4431 + "license": "MIT",
4432 + "dependencies": {
4433 + "react-remove-scroll-bar": "^2.3.7",
4434 + "react-style-singleton": "^2.2.3",
4435 + "tslib": "^2.1.0",
4436 + "use-callback-ref": "^1.3.3",
4437 + "use-sidecar": "^1.1.3"
4438 + },
4439 + "engines": {
4440 + "node": ">=10"
4441 + },
4442 + "peerDependencies": {
4443 + "@types/react": "*",
4444 + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
4445 + },
4446 + "peerDependenciesMeta": {
4447 + "@types/react": {
4448 + "optional": true
4449 + }
4450 + }
4451 + },
4452 + "node_modules/react-remove-scroll-bar": {
4453 + "version": "2.3.8",
4454 + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz",
4455 + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==",
4456 + "license": "MIT",
4457 + "dependencies": {
4458 + "react-style-singleton": "^2.2.2",
4459 + "tslib": "^2.0.0"
4460 + },
4461 + "engines": {
4462 + "node": ">=10"
4463 + },
4464 + "peerDependencies": {
4465 + "@types/react": "*",
4466 + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
4467 + },
4468 + "peerDependenciesMeta": {
4469 + "@types/react": {
4470 + "optional": true
4471 + }
4472 + }
4473 + },
4474 + "node_modules/react-style-singleton": {
4475 + "version": "2.2.3",
4476 + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz",
4477 + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==",
4478 + "license": "MIT",
4479 + "dependencies": {
4480 + "get-nonce": "^1.0.0",
4481 + "tslib": "^2.0.0"
4482 + },
4483 + "engines": {
4484 + "node": ">=10"
4485 + },
4486 + "peerDependencies": {
4487 + "@types/react": "*",
4488 + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
4489 + },
4490 + "peerDependenciesMeta": {
4491 + "@types/react": {
4492 + "optional": true
4493 + }
4494 + }
4495 + },
4496 + "node_modules/resolve-from": {
4497 + "version": "4.0.0",
4498 + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
4499 + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
4500 + "dev": true,
4501 + "license": "MIT",
4502 + "engines": {
4503 + "node": ">=4"
4504 + }
4505 + },
4506 + "node_modules/reusify": {
4507 + "version": "1.1.0",
4508 + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
4509 + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
4510 + "dev": true,
4511 + "license": "MIT",
4512 + "engines": {
4513 + "iojs": ">=1.0.0",
4514 + "node": ">=0.10.0"
4515 + }
4516 + },
4517 + "node_modules/rollup": {
4518 + "version": "4.53.2",
4519 + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.2.tgz",
4520 + "integrity": "sha512-MHngMYwGJVi6Fmnk6ISmnk7JAHRNF0UkuucA0CUW3N3a4KnONPEZz+vUanQP/ZC/iY1Qkf3bwPWzyY84wEks1g==",
4521 + "dev": true,
4522 + "license": "MIT",
4523 + "dependencies": {
4524 + "@types/estree": "1.0.8"
4525 + },
4526 + "bin": {
4527 + "rollup": "dist/bin/rollup"
4528 + },
4529 + "engines": {
4530 + "node": ">=18.0.0",
4531 + "npm": ">=8.0.0"
4532 + },
4533 + "optionalDependencies": {
4534 + "@rollup/rollup-android-arm-eabi": "4.53.2",
4535 + "@rollup/rollup-android-arm64": "4.53.2",
4536 + "@rollup/rollup-darwin-arm64": "4.53.2",
4537 + "@rollup/rollup-darwin-x64": "4.53.2",
4538 + "@rollup/rollup-freebsd-arm64": "4.53.2",
4539 + "@rollup/rollup-freebsd-x64": "4.53.2",
4540 + "@rollup/rollup-linux-arm-gnueabihf": "4.53.2",
4541 + "@rollup/rollup-linux-arm-musleabihf": "4.53.2",
4542 + "@rollup/rollup-linux-arm64-gnu": "4.53.2",
4543 + "@rollup/rollup-linux-arm64-musl": "4.53.2",
4544 + "@rollup/rollup-linux-loong64-gnu": "4.53.2",
4545 + "@rollup/rollup-linux-ppc64-gnu": "4.53.2",
4546 + "@rollup/rollup-linux-riscv64-gnu": "4.53.2",
4547 + "@rollup/rollup-linux-riscv64-musl": "4.53.2",
4548 + "@rollup/rollup-linux-s390x-gnu": "4.53.2",
4549 + "@rollup/rollup-linux-x64-gnu": "4.53.2",
4550 + "@rollup/rollup-linux-x64-musl": "4.53.2",
4551 + "@rollup/rollup-openharmony-arm64": "4.53.2",
4552 + "@rollup/rollup-win32-arm64-msvc": "4.53.2",
4553 + "@rollup/rollup-win32-ia32-msvc": "4.53.2",
4554 + "@rollup/rollup-win32-x64-gnu": "4.53.2",
4555 + "@rollup/rollup-win32-x64-msvc": "4.53.2",
4556 + "fsevents": "~2.3.2"
4557 + }
4558 + },
4559 + "node_modules/run-parallel": {
4560 + "version": "1.2.0",
4561 + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
4562 + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
4563 + "dev": true,
4564 + "funding": [
4565 + {
4566 + "type": "github",
4567 + "url": "https://github.com/sponsors/feross"
4568 + },
4569 + {
4570 + "type": "patreon",
4571 + "url": "https://www.patreon.com/feross"
4572 + },
4573 + {
4574 + "type": "consulting",
4575 + "url": "https://feross.org/support"
4576 + }
4577 + ],
4578 + "license": "MIT",
4579 + "dependencies": {
4580 + "queue-microtask": "^1.2.2"
4581 + }
4582 + },
4583 + "node_modules/scheduler": {
4584 + "version": "0.27.0",
4585 + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
4586 + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
4587 + "license": "MIT"
4588 + },
4589 + "node_modules/semver": {
4590 + "version": "7.7.3",
4591 + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
4592 + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
4593 + "dev": true,
4594 + "license": "ISC",
4595 + "bin": {
4596 + "semver": "bin/semver.js"
4597 + },
4598 + "engines": {
4599 + "node": ">=10"
4600 + }
4601 + },
4602 + "node_modules/shebang-command": {
4603 + "version": "2.0.0",
4604 + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
4605 + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
4606 + "dev": true,
4607 + "license": "MIT",
4608 + "dependencies": {
4609 + "shebang-regex": "^3.0.0"
4610 + },
4611 + "engines": {
4612 + "node": ">=8"
4613 + }
4614 + },
4615 + "node_modules/shebang-regex": {
4616 + "version": "3.0.0",
4617 + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
4618 + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
4619 + "dev": true,
4620 + "license": "MIT",
4621 + "engines": {
4622 + "node": ">=8"
4623 + }
4624 + },
4625 + "node_modules/source-map-js": {
4626 + "version": "1.2.1",
4627 + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
4628 + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
4629 + "dev": true,
4630 + "license": "BSD-3-Clause",
4631 + "engines": {
4632 + "node": ">=0.10.0"
4633 + }
4634 + },
4635 + "node_modules/strip-json-comments": {
4636 + "version": "3.1.1",
4637 + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
4638 + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
4639 + "dev": true,
4640 + "license": "MIT",
4641 + "engines": {
4642 + "node": ">=8"
4643 + },
4644 + "funding": {
4645 + "url": "https://github.com/sponsors/sindresorhus"
4646 + }
4647 + },
4648 + "node_modules/supports-color": {
4649 + "version": "7.2.0",
4650 + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
4651 + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
4652 + "dev": true,
4653 + "license": "MIT",
4654 + "dependencies": {
4655 + "has-flag": "^4.0.0"
4656 + },
4657 + "engines": {
4658 + "node": ">=8"
4659 + }
4660 + },
4661 + "node_modules/tailwind-merge": {
4662 + "version": "3.4.0",
4663 + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.4.0.tgz",
4664 + "integrity": "sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==",
4665 + "license": "MIT",
4666 + "funding": {
4667 + "type": "github",
4668 + "url": "https://github.com/sponsors/dcastil"
4669 + }
4670 + },
4671 + "node_modules/tailwindcss": {
4672 + "version": "4.1.17",
4673 + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.17.tgz",
4674 + "integrity": "sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q==",
4675 + "dev": true,
4676 + "license": "MIT"
4677 + },
4678 + "node_modules/tapable": {
4679 + "version": "2.3.0",
4680 + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz",
4681 + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==",
4682 + "dev": true,
4683 + "license": "MIT",
4684 + "engines": {
4685 + "node": ">=6"
4686 + },
4687 + "funding": {
4688 + "type": "opencollective",
4689 + "url": "https://opencollective.com/webpack"
4690 + }
4691 + },
4692 + "node_modules/tinyglobby": {
4693 + "version": "0.2.15",
4694 + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
4695 + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
4696 + "dev": true,
4697 + "license": "MIT",
4698 + "dependencies": {
4699 + "fdir": "^6.5.0",
4700 + "picomatch": "^4.0.3"
4701 + },
4702 + "engines": {
4703 + "node": ">=12.0.0"
4704 + },
4705 + "funding": {
4706 + "url": "https://github.com/sponsors/SuperchupuDev"
4707 + }
4708 + },
4709 + "node_modules/tinyglobby/node_modules/fdir": {
4710 + "version": "6.5.0",
4711 + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
4712 + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
4713 + "dev": true,
4714 + "license": "MIT",
4715 + "engines": {
4716 + "node": ">=12.0.0"
4717 + },
4718 + "peerDependencies": {
4719 + "picomatch": "^3 || ^4"
4720 + },
4721 + "peerDependenciesMeta": {
4722 + "picomatch": {
4723 + "optional": true
4724 + }
4725 + }
4726 + },
4727 + "node_modules/tinyglobby/node_modules/picomatch": {
4728 + "version": "4.0.3",
4729 + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
4730 + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
4731 + "dev": true,
4732 + "license": "MIT",
4733 + "engines": {
4734 + "node": ">=12"
4735 + },
4736 + "funding": {
4737 + "url": "https://github.com/sponsors/jonschlinkert"
4738 + }
4739 + },
4740 + "node_modules/to-regex-range": {
4741 + "version": "5.0.1",
4742 + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
4743 + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
4744 + "dev": true,
4745 + "license": "MIT",
4746 + "dependencies": {
4747 + "is-number": "^7.0.0"
4748 + },
4749 + "engines": {
4750 + "node": ">=8.0"
4751 + }
4752 + },
4753 + "node_modules/ts-api-utils": {
4754 + "version": "2.1.0",
4755 + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz",
4756 + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==",
4757 + "dev": true,
4758 + "license": "MIT",
4759 + "engines": {
4760 + "node": ">=18.12"
4761 + },
4762 + "peerDependencies": {
4763 + "typescript": ">=4.8.4"
4764 + }
4765 + },
4766 + "node_modules/tslib": {
4767 + "version": "2.8.1",
4768 + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
4769 + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
4770 + "license": "0BSD"
4771 + },
4772 + "node_modules/type-check": {
4773 + "version": "0.4.0",
4774 + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
4775 + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
4776 + "dev": true,
4777 + "license": "MIT",
4778 + "dependencies": {
4779 + "prelude-ls": "^1.2.1"
4780 + },
4781 + "engines": {
4782 + "node": ">= 0.8.0"
4783 + }
4784 + },
4785 + "node_modules/typescript": {
4786 + "version": "5.9.3",
4787 + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
4788 + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
4789 + "dev": true,
4790 + "license": "Apache-2.0",
4791 + "bin": {
4792 + "tsc": "bin/tsc",
4793 + "tsserver": "bin/tsserver"
4794 + },
4795 + "engines": {
4796 + "node": ">=14.17"
4797 + }
4798 + },
4799 + "node_modules/undici-types": {
4800 + "version": "7.16.0",
4801 + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
4802 + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
4803 + "dev": true,
4804 + "license": "MIT"
4805 + },
4806 + "node_modules/update-browserslist-db": {
4807 + "version": "1.1.4",
4808 + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz",
4809 + "integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==",
4810 + "dev": true,
4811 + "funding": [
4812 + {
4813 + "type": "opencollective",
4814 + "url": "https://opencollective.com/browserslist"
4815 + },
4816 + {
4817 + "type": "tidelift",
4818 + "url": "https://tidelift.com/funding/github/npm/browserslist"
4819 + },
4820 + {
4821 + "type": "github",
4822 + "url": "https://github.com/sponsors/ai"
4823 + }
4824 + ],
4825 + "license": "MIT",
4826 + "dependencies": {
4827 + "escalade": "^3.2.0",
4828 + "picocolors": "^1.1.1"
4829 + },
4830 + "bin": {
4831 + "update-browserslist-db": "cli.js"
4832 + },
4833 + "peerDependencies": {
4834 + "browserslist": ">= 4.21.0"
4835 + }
4836 + },
4837 + "node_modules/uri-js": {
4838 + "version": "4.4.1",
4839 + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
4840 + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
4841 + "dev": true,
4842 + "license": "BSD-2-Clause",
4843 + "dependencies": {
4844 + "punycode": "^2.1.0"
4845 + }
4846 + },
4847 + "node_modules/use-callback-ref": {
4848 + "version": "1.3.3",
4849 + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz",
4850 + "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==",
4851 + "license": "MIT",
4852 + "dependencies": {
4853 + "tslib": "^2.0.0"
4854 + },
4855 + "engines": {
4856 + "node": ">=10"
4857 + },
4858 + "peerDependencies": {
4859 + "@types/react": "*",
4860 + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
4861 + },
4862 + "peerDependenciesMeta": {
4863 + "@types/react": {
4864 + "optional": true
4865 + }
4866 + }
4867 + },
4868 + "node_modules/use-sidecar": {
4869 + "version": "1.1.3",
4870 + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz",
4871 + "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==",
4872 + "license": "MIT",
4873 + "dependencies": {
4874 + "detect-node-es": "^1.1.0",
4875 + "tslib": "^2.0.0"
4876 + },
4877 + "engines": {
4878 + "node": ">=10"
4879 + },
4880 + "peerDependencies": {
4881 + "@types/react": "*",
4882 + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
4883 + },
4884 + "peerDependenciesMeta": {
4885 + "@types/react": {
4886 + "optional": true
4887 + }
4888 + }
4889 + },
4890 + "node_modules/vite": {
4891 + "version": "7.2.2",
4892 + "resolved": "https://registry.npmjs.org/vite/-/vite-7.2.2.tgz",
4893 + "integrity": "sha512-BxAKBWmIbrDgrokdGZH1IgkIk/5mMHDreLDmCJ0qpyJaAteP8NvMhkwr/ZCQNqNH97bw/dANTE9PDzqwJghfMQ==",
4894 + "dev": true,
4895 + "license": "MIT",
4896 + "dependencies": {
4897 + "esbuild": "^0.25.0",
4898 + "fdir": "^6.5.0",
4899 + "picomatch": "^4.0.3",
4900 + "postcss": "^8.5.6",
4901 + "rollup": "^4.43.0",
4902 + "tinyglobby": "^0.2.15"
4903 + },
4904 + "bin": {
4905 + "vite": "bin/vite.js"
4906 + },
4907 + "engines": {
4908 + "node": "^20.19.0 || >=22.12.0"
4909 + },
4910 + "funding": {
4911 + "url": "https://github.com/vitejs/vite?sponsor=1"
4912 + },
4913 + "optionalDependencies": {
4914 + "fsevents": "~2.3.3"
4915 + },
4916 + "peerDependencies": {
4917 + "@types/node": "^20.19.0 || >=22.12.0",
4918 + "jiti": ">=1.21.0",
4919 + "less": "^4.0.0",
4920 + "lightningcss": "^1.21.0",
4921 + "sass": "^1.70.0",
4922 + "sass-embedded": "^1.70.0",
4923 + "stylus": ">=0.54.8",
4924 + "sugarss": "^5.0.0",
4925 + "terser": "^5.16.0",
4926 + "tsx": "^4.8.1",
4927 + "yaml": "^2.4.2"
4928 + },
4929 + "peerDependenciesMeta": {
4930 + "@types/node": {
4931 + "optional": true
4932 + },
4933 + "jiti": {
4934 + "optional": true
4935 + },
4936 + "less": {
4937 + "optional": true
4938 + },
4939 + "lightningcss": {
4940 + "optional": true
4941 + },
4942 + "sass": {
4943 + "optional": true
4944 + },
4945 + "sass-embedded": {
4946 + "optional": true
4947 + },
4948 + "stylus": {
4949 + "optional": true
4950 + },
4951 + "sugarss": {
4952 + "optional": true
4953 + },
4954 + "terser": {
4955 + "optional": true
4956 + },
4957 + "tsx": {
4958 + "optional": true
4959 + },
4960 + "yaml": {
4961 + "optional": true
4962 + }
4963 + }
4964 + },
4965 + "node_modules/vite/node_modules/fdir": {
4966 + "version": "6.5.0",
4967 + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
4968 + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
4969 + "dev": true,
4970 + "license": "MIT",
4971 + "engines": {
4972 + "node": ">=12.0.0"
4973 + },
4974 + "peerDependencies": {
4975 + "picomatch": "^3 || ^4"
4976 + },
4977 + "peerDependenciesMeta": {
4978 + "picomatch": {
4979 + "optional": true
4980 + }
4981 + }
4982 + },
4983 + "node_modules/vite/node_modules/picomatch": {
4984 + "version": "4.0.3",
4985 + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
4986 + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
4987 + "dev": true,
4988 + "license": "MIT",
4989 + "engines": {
4990 + "node": ">=12"
4991 + },
4992 + "funding": {
4993 + "url": "https://github.com/sponsors/jonschlinkert"
4994 + }
4995 + },
4996 + "node_modules/which": {
4997 + "version": "2.0.2",
4998 + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
4999 + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",

This file is too large to show in full.

cmd/relay-server/frontend/package.json new
+42
@@ -0,0 +1,42 @@
1 +{
2 + "name": "relay-server-frontend",
3 + "private": true,
4 + "version": "0.0.0",
5 + "type": "module",
6 + "scripts": {
7 + "dev": "vite",
8 + "build": "tsc && vite build",
9 + "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
10 + "preview": "vite preview",
11 + "build:go": "cd ../../.. && CGO_ENABLED=0 go build -o bin/relay-server cmd/relay-server/*.go",
12 + "serve": "npm run build && npm run build:go && STATIC_DIR=../../../dist ../../../bin/relay-server -port 4017"
13 + },
14 + "dependencies": {
15 + "@radix-ui/react-dialog": "^1.1.15",
16 + "@radix-ui/react-popover": "^1.1.15",
17 + "@radix-ui/react-select": "^2.2.6",
18 + "@radix-ui/react-slot": "^1.2.4",
19 + "class-variance-authority": "^0.7.1",
20 + "clsx": "^2.1.1",
21 + "cmdk": "^1.1.1",
22 + "lucide-react": "^0.553.0",
23 + "react": "^19.2.0",
24 + "react-dom": "^19.2.0",
25 + "tailwind-merge": "^3.4.0"
26 + },
27 + "devDependencies": {
28 + "@tailwindcss/vite": "^4.1.17",
29 + "@types/node": "^24.10.1",
30 + "@types/react": "^19.2.5",
31 + "@types/react-dom": "^19.2.3",
32 + "@typescript-eslint/eslint-plugin": "^8.46.4",
33 + "@typescript-eslint/parser": "^8.46.4",
34 + "@vitejs/plugin-react": "^5.1.1",
35 + "eslint": "^9.39.1",
36 + "eslint-plugin-react-hooks": "^7.0.1",
37 + "eslint-plugin-react-refresh": "^0.4.24",
38 + "tailwindcss": "^4.1.17",
39 + "typescript": "^5.9.3",
40 + "vite": "^7.2.2"
41 + }
42 +}
cmd/relay-server/frontend/public/apple-touch-icon.png
Binary files /dev/null and b/cmd/relay-server/frontend/public/apple-touch-icon.png differ
cmd/relay-server/frontend/public/favicon-96x96.png
Binary files /dev/null and b/cmd/relay-server/frontend/public/favicon-96x96.png differ
cmd/relay-server/frontend/public/favicon.ico
Binary files /dev/null and b/cmd/relay-server/frontend/public/favicon.ico differ
cmd/relay-server/frontend/public/favicon.svg new
+3
@@ -0,0 +1,3 @@
1 +<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="1554" height="2500"><svg xmlns="http://www.w3.org/2000/svg" width="1554" height="2500" viewBox="0 0 906.26 1457.543"><path fill="#17C0E9" d="M254.854 137.158c-34.46 84.407-88.363 149.39-110.934 245.675 90.926-187.569 308.397-483.654 554.729-348.685 135.487 74.216 194.878 270.78 206.058 467.566 21.924 385.996-190.977 853.604-467.585 943.057-174.879 56.543-307.375-86.447-364.527-198.115-176.498-344.82 2.041-910.077 182.259-1109.498zm198.13 7.918C202.61 280.257 4.622 968.542 207.322 1270.414c51.713 77.029 194.535 160.648 285.294 71.318-209.061 31.529-288.389-176.143-301.145-340.765 31.411 147.743 139.396 326.12 309.075 253.588 251.957-107.723 376.778-648.46 269.433-966.817 22.394 134.616 15.572 317.711-47.551 412.087 86.655-230.615 7.903-704.478-269.444-554.749z"></path></svg><style>@media (prefers-color-scheme: light) { :root { filter: none; } }
2 +@media (prefers-color-scheme: dark) { :root { filter: none; } }
3 +</style></svg>
\ No newline at end of file
cmd/relay-server/frontend/public/web-app-manifest-192x192.png
Binary files /dev/null and b/cmd/relay-server/frontend/public/web-app-manifest-192x192.png differ
cmd/relay-server/frontend/public/web-app-manifest-512x512.png
Binary files /dev/null and b/cmd/relay-server/frontend/public/web-app-manifest-512x512.png differ
cmd/relay-server/frontend/src/App.tsx new
+219
@@ -0,0 +1,219 @@
1 +import { useState, useMemo } from "react";
2 +import { Header } from "./components/Header";
3 +import { SearchBar } from "./components/SearchBar";
4 +import { ServerCard } from "./components/ServerCard";
5 +import { Pagination } from "./components/Pagination";
6 +import { useSSRData } from "./hooks/useSSRData";
7 +import type { ServerData, Metadata } from "./hooks/useSSRData";
8 +
9 +const ITEMS_PER_PAGE = 6;
10 +
11 +// Helper function to convert SSR ServerData to frontend format
12 +function convertSSRDataToServers(ssrData: ServerData[]) {
13 + return ssrData.map((row, index) => {
14 + // Parse metadata JSON string
15 + let metadata: Metadata = {
16 + description: "",
17 + tags: [],
18 + thumbnail: "",
19 + owner: "",
20 + hide: false,
21 + };
22 +
23 + try {
24 + if (row.Metadata) {
25 + metadata = JSON.parse(row.Metadata);
26 + }
27 + } catch (err) {
28 + console.error("[App] Failed to parse metadata:", err, row.Metadata);
29 + }
30 +
31 + // Get region from SSR data (GeoIP-detected region)
32 + const region = row.Region || "unknown";
33 +
34 + // Combine region tag with metadata tags
35 + const metadataTags = Array.isArray(metadata.tags) ? metadata.tags : [];
36 + const allTags =
37 + region !== "unknown" ? [region, ...metadataTags] : metadataTags;
38 +
39 + return {
40 + id: index + 1,
41 + name: row.Name || row.DNS || "(unnamed)",
42 + description: metadata.description || "",
43 + tags: allTags,
44 + thumbnail: metadata.thumbnail || "",
45 + owner: metadata.owner || "",
46 + online: row.Connected,
47 + dns: row.DNS || "",
48 + link: row.Link,
49 + region: region,
50 + countryCode: row.CountryCode || "",
51 + };
52 + });
53 +}
54 +
55 +function App() {
56 + const [currentPage, setCurrentPage] = useState(1);
57 + const [searchQuery, setSearchQuery] = useState("");
58 + const [region, setRegion] = useState("all");
59 + const [status, setStatus] = useState("all");
60 + const [sortBy, setSortBy] = useState("default");
61 +
62 + // Get SSR data
63 + const ssrData = useSSRData();
64 +
65 + // Use SSR data if available, otherwise fall back to sample servers
66 + const servers = useMemo(() => {
67 + console.log("[App] SSR data length:", ssrData.length);
68 + if (ssrData.length > 0) {
69 + console.log("[App] Using SSR data");
70 + const converted = convertSSRDataToServers(ssrData);
71 + console.log("[App] Converted servers:", converted);
72 + return converted;
73 + }
74 + console.log("[App] Using sample servers");
75 + return [];
76 + }, [ssrData]);
77 +
78 + // Extract unique available countries from servers
79 + const availableCountries = useMemo(() => {
80 + const countryCodes = new Set<string>();
81 + servers.forEach((server) => {
82 + if (server.countryCode) {
83 + countryCodes.add(server.countryCode);
84 + }
85 + });
86 + return Array.from(countryCodes).sort();
87 + }, [servers]);
88 +
89 + // Filter and sort servers
90 + const filteredServers = useMemo(() => {
91 + let filtered = servers.filter((server) => {
92 + // Search filter - searches name, description, and tags
93 + const matchesSearch =
94 + searchQuery === "" ||
95 + server.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
96 + server.description.toLowerCase().includes(searchQuery.toLowerCase()) ||
97 + server.tags.some((tag) =>
98 + tag.toLowerCase().includes(searchQuery.toLowerCase())
99 + );
100 +
101 + // Country filter (using country code)
102 + const matchesRegion =
103 + region === "all" ||
104 + server.countryCode === region;
105 +
106 + // Status filter
107 + const matchesStatus =
108 + status === "all" ||
109 + (status === "online" && server.online) ||
110 + (status === "offline" && !server.online);
111 +
112 + return matchesSearch && matchesRegion && matchesStatus;
113 + });
114 +
115 + // Sort based on sortBy value
116 + if (sortBy === "description") {
117 + filtered = [...filtered].sort((a, b) =>
118 + a.description.localeCompare(b.description)
119 + );
120 + } else if (sortBy === "tags") {
121 + filtered = [...filtered].sort((a, b) => {
122 + const aTag = a.tags[0] || "";
123 + const bTag = b.tags[0] || "";
124 + return aTag.localeCompare(bTag);
125 + });
126 + } else if (sortBy === "owner") {
127 + filtered = [...filtered].sort((a, b) =>
128 + a.owner.localeCompare(b.owner)
129 + );
130 + }
131 +
132 + return filtered;
133 + }, [servers, searchQuery, region, status, sortBy]);
134 +
135 + // Pagination
136 + const totalPages = Math.ceil(filteredServers.length / ITEMS_PER_PAGE);
137 + const paginatedServers = useMemo(() => {
138 + const startIndex = (currentPage - 1) * ITEMS_PER_PAGE;
139 + return filteredServers.slice(startIndex, startIndex + ITEMS_PER_PAGE);
140 + }, [filteredServers, currentPage]);
141 +
142 + // Reset to page 1 when filters change
143 + const handleSearchChange = (value: string) => {
144 + setSearchQuery(value);
145 + setCurrentPage(1);
146 + };
147 +
148 + const handleRegionChange = (value: string) => {
149 + setRegion(value);
150 + setCurrentPage(1);
151 + };
152 +
153 + const handleStatusChange = (value: string) => {
154 + setStatus(value);
155 + setCurrentPage(1);
156 + };
157 +
158 + const handleSortByChange = (value: string) => {
159 + setSortBy(value);
160 + setCurrentPage(1);
161 + };
162 +
163 + return (
164 + <div className="relative flex h-auto min-h-screen w-full flex-col overflow-x-hidden">
165 + <div className="layout-container flex h-full grow flex-col">
166 + <div className="flex flex-1 justify-center py-5">
167 + <div className="layout-content-container flex flex-col w-full max-w-6xl flex-1 px-4 md:px-8">
168 + <Header />
169 + <main className="flex-1 mt-6">
170 + <SearchBar
171 + searchQuery={searchQuery}
172 + onSearchChange={handleSearchChange}
173 + region={region}
174 + onRegionChange={handleRegionChange}
175 + status={status}
176 + onStatusChange={handleStatusChange}
177 + sortBy={sortBy}
178 + onSortByChange={handleSortByChange}
179 + availableCountries={availableCountries}
180 + />
181 + <div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-6 p-4 sm:p-6 mt-4">
182 + {paginatedServers.length > 0 ? (
183 + paginatedServers.map((server) => (
184 + <ServerCard
185 + key={server.id}
186 + name={server.name}
187 + description={server.description}
188 + tags={server.tags}
189 + thumbnail={server.thumbnail}
190 + owner={server.owner}
191 + online={server.online}
192 + dns={server.dns}
193 + serverUrl={server.link}
194 + />
195 + ))
196 + ) : (
197 + <div className="col-span-full text-center py-12">
198 + <p className="text-text-muted text-lg">
199 + No servers found matching your criteria
200 + </p>
201 + </div>
202 + )}
203 + </div>
204 + {totalPages > 0 && (
205 + <Pagination
206 + currentPage={currentPage}
207 + totalPages={totalPages}
208 + onPageChange={setCurrentPage}
209 + />
210 + )}
211 + </main>
212 + </div>
213 + </div>
214 + </div>
215 + </div>
216 + );
217 +}
218 +
219 +export default App;
cmd/relay-server/frontend/src/components/Header.tsx new
+46
@@ -0,0 +1,46 @@
1 +export function Header() {
2 + return (
3 + <header className="flex items-center justify-between whitespace-nowrap border-b border-solid border-border-dark px-4 sm:px-6 py-3">
4 + <div className="flex items-center gap-4 text-white">
5 + <div className="text-primary size-6">
6 + <svg
7 + xmlns="http://www.w3.org/2000/svg"
8 + width="24"
9 + height="24"
10 + viewBox="0 0 906.26 1457.543"
11 + >
12 + <path
13 + fill="#17C0E9"
14 + d="M254.854 137.158c-34.46 84.407-88.363 149.39-110.934 245.675 90.926-187.569 308.397-483.654 554.729-348.685 135.487 74.216 194.878 270.78 206.058 467.566 21.924 385.996-190.977 853.604-467.585 943.057-174.879 56.543-307.375-86.447-364.527-198.115-176.498-344.82 2.041-910.077 182.259-1109.498zm198.13 7.918C202.61 280.257 4.622 968.542 207.322 1270.414c51.713 77.029 194.535 160.648 285.294 71.318-209.061 31.529-288.389-176.143-301.145-340.765 31.411 147.743 139.396 326.12 309.075 253.588 251.957-107.723 376.778-648.46 269.433-966.817 22.394 134.616 15.572 317.711-47.551 412.087 86.655-230.615 7.903-704.478-269.444-554.749z"
15 + ></path>
16 + </svg>
17 + </div>
18 + <h2 className="text-white text-lg font-bold leading-tight tracking-[-0.015em]">
19 + PORTAL
20 + </h2>
21 + </div>
22 + <div className="flex items-center gap-3">
23 + <a
24 + href="https://github.com/gosuda/portal"
25 + target="_blank"
26 + rel="noopener noreferrer"
27 + className="text-white hover:text-primary transition-colors"
28 + aria-label="View source on GitHub"
29 + >
30 + <svg
31 + height="32"
32 + width="32"
33 + viewBox="0 0 24 24"
34 + fill="currentColor"
35 + className="opacity-80 hover:opacity-100"
36 + >
37 + <path d="M12 1C5.923 1 1 5.923 1 12c0 4.867 3.149 8.979 7.521 10.436.55.096.756-.233.756-.522 0-.262-.013-1.128-.013-2.049-2.764.509-3.479-.674-3.699-1.292-.124-.317-.66-1.293-1.127-1.554-.385-.207-.936-.715-.014-.729.866-.014 1.485.797 1.691 1.128.99 1.663 2.571 1.196 3.204.907.096-.715.385-1.196.701-1.471-2.448-.275-5.005-1.224-5.005-5.432 0-1.196.426-2.186 1.128-2.956-.111-.275-.496-1.402.11-2.915 0 0 .921-.288 3.024 1.128a10.193 10.193 0 0 1 2.75-.371c.936 0 1.871.123 2.75.371 2.104-1.43 3.025-1.128 3.025-1.128.605 1.513.221 2.64.111 2.915.701.77 1.127 1.747 1.127 2.956 0 4.222-2.571 5.157-5.019 5.432.399.344.743 1.004.743 2.035 0 1.471-.014 2.654-.014 3.025 0 .289.206.632.756.522C19.851 20.979 23 16.854 23 12c0-6.077-4.922-11-11-11Z"></path>
38 + </svg>
39 + </a>
40 + {/* <Button>
41 + <span className="truncate">Add Your Server</span>
42 + </Button> */}
43 + </div>
44 + </header>
45 + );
46 +}
cmd/relay-server/frontend/src/components/Pagination.tsx new
+35
@@ -0,0 +1,35 @@
1 +import { ChevronLeft, ChevronRight } from "lucide-react";
2 +
3 +interface PaginationProps {
4 + currentPage: number;
5 + totalPages: number;
6 + onPageChange: (page: number) => void;
7 +}
8 +
9 +export function Pagination({
10 + currentPage,
11 + totalPages,
12 + onPageChange,
13 +}: PaginationProps) {
14 + return (
15 + <div className="flex items-center justify-center gap-4 px-4 sm:px-6 py-8">
16 + <button
17 + onClick={() => onPageChange(currentPage - 1)}
18 + disabled={currentPage === 1}
19 + className="flex h-10 w-10 cursor-pointer items-center justify-center overflow-hidden rounded-full bg-[#233348] text-white hover:bg-[#2d3f58] transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
20 + >
21 + <ChevronLeft className="w-6 h-6" />
22 + </button>
23 + <span className="text-sm text-gray-400">
24 + Page {currentPage} of {totalPages}
25 + </span>
26 + <button
27 + onClick={() => onPageChange(currentPage + 1)}
28 + disabled={currentPage === totalPages}
29 + className="flex h-10 w-10 cursor-pointer items-center justify-center overflow-hidden rounded-full bg-[#233348] text-white hover:bg-[#2d3f58] transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
30 + >
31 + <ChevronRight className="w-6 h-6" />
32 + </button>
33 + </div>
34 + );
35 +}
cmd/relay-server/frontend/src/components/SearchBar.tsx new
+89
@@ -0,0 +1,89 @@
1 +import { Search } from "lucide-react";
2 +import { Input } from "./ui/input";
3 +import {
4 + Select,
5 + SelectContent,
6 + SelectItem,
7 + SelectTrigger,
8 + SelectValue,
9 +} from "./ui/select";
10 +import { COUNTRY_NAMES } from "../lib/countries";
11 +
12 +interface SearchBarProps {
13 + searchQuery: string;
14 + onSearchChange: (value: string) => void;
15 + region: string;
16 + onRegionChange: (value: string) => void;
17 + status: string;
18 + onStatusChange: (value: string) => void;
19 + sortBy: string;
20 + onSortByChange: (value: string) => void;
21 + availableCountries: string[];
22 +}
23 +
24 +export function SearchBar({
25 + searchQuery,
26 + onSearchChange,
27 + region,
28 + onRegionChange,
29 + status,
30 + onStatusChange,
31 + sortBy,
32 + onSortByChange,
33 + availableCountries,
34 +}: SearchBarProps) {
35 + return (
36 + <div className="space-y-4 px-4 sm:px-6">
37 + <label className="flex flex-col min-w-40 h-12 w-full">
38 + <div className="flex w-full flex-1 items-stretch rounded-lg h-full">
39 + <div className="text-[#92a9c9] flex border-none bg-[#233348] items-center justify-center pl-4 rounded-l-lg border-r-0">
40 + <Search className="w-5 h-5" />
41 + </div>
42 + <Input
43 + placeholder="Search by server name..."
44 + value={searchQuery}
45 + onChange={(e) => onSearchChange(e.target.value)}
46 + />
47 + </div>
48 + </label>
49 + <div className="flex flex-wrap gap-3">
50 + <Select value={region} onValueChange={onRegionChange}>
51 + <SelectTrigger className="w-[140px] h-8">
52 + <SelectValue placeholder="Country" />
53 + </SelectTrigger>
54 + <SelectContent>
55 + <SelectItem value="all">All Countries</SelectItem>
56 + {availableCountries.map((countryCode) => (
57 + <SelectItem key={countryCode} value={countryCode}>
58 + {COUNTRY_NAMES[countryCode] || countryCode}
59 + </SelectItem>
60 + ))}
61 + </SelectContent>
62 + </Select>
63 +
64 + <Select value={status} onValueChange={onStatusChange}>
65 + <SelectTrigger className="w-[140px] h-8">
66 + <SelectValue placeholder="Status" />
67 + </SelectTrigger>
68 + <SelectContent>
69 + <SelectItem value="all">All Status</SelectItem>
70 + <SelectItem value="online">Online</SelectItem>
71 + <SelectItem value="offline">Offline</SelectItem>
72 + </SelectContent>
73 + </Select>
74 +
75 + <Select value={sortBy} onValueChange={onSortByChange}>
76 + <SelectTrigger className="w-[140px] h-8">
77 + <SelectValue placeholder="Sort By" />
78 + </SelectTrigger>
79 + <SelectContent>
80 + <SelectItem value="default">Default</SelectItem>
81 + <SelectItem value="description">Description</SelectItem>
82 + <SelectItem value="tags">Tags</SelectItem>
83 + <SelectItem value="owner">Owner</SelectItem>
84 + </SelectContent>
85 + </Select>
86 + </div>
87 + </div>
88 + );
89 +}
cmd/relay-server/frontend/src/components/ServerCard.tsx new
+81
@@ -0,0 +1,81 @@
1 +import { Button } from "./ui/button";
2 +
3 +interface ServerCardProps {
4 + name: string;
5 + description: string;
6 + tags: string[];
7 + thumbnail: string;
8 + owner: string;
9 + online: boolean;
10 + dns: string;
11 + serverUrl: string;
12 +}
13 +
14 +export function ServerCard({
15 + name,
16 + description,
17 + tags,
18 + thumbnail,
19 + owner,
20 + online,
21 + serverUrl,
22 +}: ServerCardProps) {
23 + const defaultThumbnail =
24 + "https://cdn.jsdelivr.net/gh/gosuda/portal@main/portal.jpg";
25 +
26 + const goServer = () => {
27 + window.location.href = serverUrl;
28 + };
29 + return (
30 + <div className="flex flex-col gap-4 rounded-xl bg-card-dark p-4 shadow-sm hover:shadow-lg transition-shadow duration-300">
31 + <div
32 + className="w-full bg-center bg-no-repeat aspect-video bg-cover rounded-lg"
33 + style={{ backgroundImage: `url(${thumbnail || defaultThumbnail})` }}
34 + />
35 + <div className="flex flex-1 flex-col justify-between gap-4">
36 + <div className="flex flex-col gap-2">
37 + <div className="flex items-center gap-2">
38 + <div
39 + className={`w-2.5 h-2.5 rounded-full ${
40 + online ? "bg-green-status" : "bg-red-500"
41 + }`}
42 + />
43 + <p
44 + className={`text-sm font-medium leading-normal ${
45 + online ? "text-green-status" : "text-red-500"
46 + }`}
47 + >
48 + {online ? "Online" : "Offline"}
49 + </p>
50 + </div>
51 + <p className="text-white text-lg font-bold leading-tight">{name}</p>
52 + {description && (
53 + <p className="text-text-muted text-sm font-normal leading-normal line-clamp-2">
54 + {description}
55 + </p>
56 + )}
57 + {tags && tags.length > 0 && (
58 + <div className="flex flex-wrap gap-1.5 mt-1">
59 + {tags.map((tag, index) => (
60 + <span
61 + key={index}
62 + className="px-2 py-1 bg-border-dark text-primary text-xs font-medium rounded"
63 + >
64 + {tag}
65 + </span>
66 + ))}
67 + </div>
68 + )}
69 + {owner && (
70 + <p className="text-text-muted text-xs font-normal leading-normal">
71 + by {owner}
72 + </p>
73 + )}
74 + </div>
75 + <Button variant="secondary" className="w-full" onClick={goServer}>
76 + <span className="truncate">Connect</span>
77 + </Button>
78 + </div>
79 + </div>
80 + );
81 +}
cmd/relay-server/frontend/src/components/ui/button.tsx new
+49
@@ -0,0 +1,49 @@
1 +import * as React from "react";
2 +import { Slot } from "@radix-ui/react-slot";
3 +import { cva, type VariantProps } from "class-variance-authority";
4 +import { cn } from "@/lib/utils";
5 +
6 +const buttonVariants = cva(
7 + "inline-flex items-center justify-center overflow-hidden rounded-lg text-sm font-bold leading-normal tracking-[0.015em] transition-colors cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed",
8 + {
9 + variants: {
10 + variant: {
11 + default: "bg-primary text-black hover:bg-primary/90",
12 + secondary: "bg-border-dark text-white hover:bg-[#2d3f58]",
13 + ghost: "hover:bg-[#2d3f58] text-white",
14 + },
15 + size: {
16 + default: "h-10 px-4",
17 + sm: "h-9 px-4",
18 + lg: "h-11 px-8",
19 + icon: "h-10 w-10",
20 + },
21 + },
22 + defaultVariants: {
23 + variant: "default",
24 + size: "default",
25 + },
26 + }
27 +);
28 +
29 +export interface ButtonProps
30 + extends React.ButtonHTMLAttributes<HTMLButtonElement>,
31 + VariantProps<typeof buttonVariants> {
32 + asChild?: boolean;
33 +}
34 +
35 +const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
36 + ({ className, variant, size, asChild = false, ...props }, ref) => {
37 + const Comp = asChild ? Slot : "button";
38 + return (
39 + <Comp
40 + className={cn(buttonVariants({ variant, size, className }))}
41 + ref={ref}
42 + {...props}
43 + />
44 + );
45 + }
46 +);
47 +Button.displayName = "Button";
48 +
49 +export { Button, buttonVariants };
cmd/relay-server/frontend/src/components/ui/input.tsx new
+24
@@ -0,0 +1,24 @@
1 +import * as React from "react";
2 +import { cn } from "@/lib/utils";
3 +
4 +export interface InputProps
5 + extends React.InputHTMLAttributes<HTMLInputElement> {}
6 +
7 +const Input = React.forwardRef<HTMLInputElement, InputProps>(
8 + ({ className, type, ...props }, ref) => {
9 + return (
10 + <input
11 + type={type}
12 + className={cn(
13 + "flex w-full min-w-0 flex-1 resize-none overflow-hidden rounded-r-lg text-white focus:outline-0 focus:ring-2 focus:ring-primary/50 border-none bg-border-dark h-full placeholder:text-text-muted px-4 pl-2 text-base font-normal leading-normal",
14 + className
15 + )}
16 + ref={ref}
17 + {...props}
18 + />
19 + );
20 + }
21 +);
22 +Input.displayName = "Input";
23 +
24 +export { Input };
cmd/relay-server/frontend/src/components/ui/select.tsx new
+159
@@ -0,0 +1,159 @@
1 +import * as React from "react";
2 +import * as SelectPrimitive from "@radix-ui/react-select";
3 +import { Check, ChevronDown, ChevronUp } from "lucide-react";
4 +import { cn } from "@/lib/utils";
5 +
6 +const Select = SelectPrimitive.Root;
7 +
8 +const SelectGroup = SelectPrimitive.Group;
9 +
10 +const SelectValue = SelectPrimitive.Value;
11 +
12 +const SelectTrigger = React.forwardRef<
13 + React.ElementRef<typeof SelectPrimitive.Trigger>,
14 + React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
15 +>(({ className, children, ...props }, ref) => (
16 + <SelectPrimitive.Trigger
17 + ref={ref}
18 + className={cn(
19 + "flex h-9 w-full items-center justify-between whitespace-nowrap rounded-lg bg-[#233348] px-3 py-2 text-sm text-white shadow-sm ring-offset-background placeholder:text-[#92a9c9] focus:outline-none focus:ring-2 focus:ring-primary/50 cursor-pointer disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
20 + className
21 + )}
22 + {...props}
23 + >
24 + {children}
25 + <SelectPrimitive.Icon asChild>
26 + <ChevronDown className="h-4 w-4 opacity-50" />
27 + </SelectPrimitive.Icon>
28 + </SelectPrimitive.Trigger>
29 +));
30 +SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
31 +
32 +const SelectScrollUpButton = React.forwardRef<
33 + React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
34 + React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
35 +>(({ className, ...props }, ref) => (
36 + <SelectPrimitive.ScrollUpButton
37 + ref={ref}
38 + className={cn(
39 + "flex cursor-default items-center justify-center py-1",
40 + className
41 + )}
42 + {...props}
43 + >
44 + <ChevronUp className="h-4 w-4" />
45 + </SelectPrimitive.ScrollUpButton>
46 +));
47 +SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
48 +
49 +const SelectScrollDownButton = React.forwardRef<
50 + React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
51 + React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
52 +>(({ className, ...props }, ref) => (
53 + <SelectPrimitive.ScrollDownButton
54 + ref={ref}
55 + className={cn(
56 + "flex cursor-default items-center justify-center py-1",
57 + className
58 + )}
59 + {...props}
60 + >
61 + <ChevronDown className="h-4 w-4" />
62 + </SelectPrimitive.ScrollDownButton>
63 +));
64 +SelectScrollDownButton.displayName =
65 + SelectPrimitive.ScrollDownButton.displayName;
66 +
67 +const SelectContent = React.forwardRef<
68 + React.ElementRef<typeof SelectPrimitive.Content>,
69 + React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
70 +>(({ className, children, position = "popper", ...props }, ref) => (
71 + <SelectPrimitive.Portal>
72 + <SelectPrimitive.Content
73 + ref={ref}
74 + className={cn(
75 + "relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-lg bg-[#192433] text-white shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
76 + position === "popper" &&
77 + "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
78 + className
79 + )}
80 + position={position}
81 + {...props}
82 + >
83 + <SelectScrollUpButton />
84 + <SelectPrimitive.Viewport
85 + className={cn(
86 + "p-1",
87 + position === "popper" &&
88 + "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
89 + )}
90 + >
91 + {children}
92 + </SelectPrimitive.Viewport>
93 + <SelectScrollDownButton />
94 + </SelectPrimitive.Content>
95 + </SelectPrimitive.Portal>
96 +));
97 +SelectContent.displayName = SelectPrimitive.Content.displayName;
98 +
99 +const SelectLabel = React.forwardRef<
100 + React.ElementRef<typeof SelectPrimitive.Label>,
101 + React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
102 +>(({ className, ...props }, ref) => (
103 + <SelectPrimitive.Label
104 + ref={ref}
105 + className={cn(
106 + "px-2 py-1.5 text-sm font-semibold text-text-muted",
107 + className
108 + )}
109 + {...props}
110 + />
111 +));
112 +SelectLabel.displayName = SelectPrimitive.Label.displayName;
113 +
114 +const SelectItem = React.forwardRef<
115 + React.ElementRef<typeof SelectPrimitive.Item>,
116 + React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
117 +>(({ className, children, ...props }, ref) => (
118 + <SelectPrimitive.Item
119 + ref={ref}
120 + className={cn(
121 + "relative flex w-full cursor-pointer select-none items-center rounded-md py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-[#233348] focus:text-white data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
122 + className
123 + )}
124 + {...props}
125 + >
126 + <span className="absolute right-2 flex h-3.5 w-3.5 items-center justify-center">
127 + <SelectPrimitive.ItemIndicator>
128 + <Check className="h-4 w-4" />
129 + </SelectPrimitive.ItemIndicator>
130 + </span>
131 + <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
132 + </SelectPrimitive.Item>
133 +));
134 +SelectItem.displayName = SelectPrimitive.Item.displayName;
135 +
136 +const SelectSeparator = React.forwardRef<
137 + React.ElementRef<typeof SelectPrimitive.Separator>,
138 + React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
139 +>(({ className, ...props }, ref) => (
140 + <SelectPrimitive.Separator
141 + ref={ref}
142 + className={cn("-mx-1 my-1 h-px bg-[#233348]", className)}
143 + {...props}
144 + />
145 +));
146 +SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
147 +
148 +export {
149 + Select,
150 + SelectGroup,
151 + SelectValue,
152 + SelectTrigger,
153 + SelectContent,
154 + SelectLabel,
155 + SelectItem,
156 + SelectSeparator,
157 + SelectScrollUpButton,
158 + SelectScrollDownButton,
159 +};
cmd/relay-server/frontend/src/hooks/useSSRData.ts new
+62
@@ -0,0 +1,62 @@
1 +import { useState, useEffect } from "react";
2 +
3 +export interface Metadata {
4 + description: string;
5 + tags: string[];
6 + thumbnail: string;
7 + owner: string;
8 + hide: boolean;
9 +}
10 +
11 +export interface ServerData {
12 + Peer: string;
13 + Name: string;
14 + Kind: string;
15 + Connected: boolean;
16 + DNS: string;
17 + LastSeen: string;
18 + LastSeenISO: string;
19 + TTL: string;
20 + Link: string;
21 + StaleRed: boolean;
22 + Hide: boolean;
23 + Metadata: string;
24 + Region: string;
25 + CountryCode: string;
26 + City: string;
27 +}
28 +
29 +/**
30 + * useSSRData hook reads server data injected by Go SSR
31 + * The data is embedded in a <script id="__SSR_DATA__"> tag in the HTML
32 + */
33 +export function useSSRData(): ServerData[] {
34 + const [data, setData] = useState<ServerData[]>([]);
35 +
36 + useEffect(() => {
37 + // Try to read SSR data from the script tag
38 + const ssrScript = document.getElementById("__SSR_DATA__");
39 + console.log("[SSR] Script tag found:", !!ssrScript);
40 +
41 + if (ssrScript && ssrScript.textContent) {
42 + console.log(
43 + "[SSR] Script content:",
44 + ssrScript.textContent.substring(0, 200)
45 + );
46 + try {
47 + const parsed = JSON.parse(ssrScript.textContent);
48 + console.log("[SSR] Parsed data:", parsed);
49 + console.log("[SSR] Is array:", Array.isArray(parsed));
50 + console.log("[SSR] Length:", Array.isArray(parsed) ? parsed.length : 0);
51 + setData(Array.isArray(parsed) ? parsed : []);
52 + } catch (err) {
53 + console.error("[SSR] Failed to parse SSR data:", err);
54 + setData([]);
55 + }
56 + } else {
57 + console.log("[SSR] No script tag or content found");
58 + }
59 + }, []);
60 +
61 + return data;
62 +}
cmd/relay-server/frontend/src/index.css new
+60
@@ -0,0 +1,60 @@
1 +@import url('https://fonts.googleapis.com/css2?family=Public+Sans:wght@400;500;700;900&display=swap');
2 +@import "tailwindcss";
3 +
4 +@theme {
5 + /* ServerShare Custom Colors - Dark Mode Only */
6 + --color-primary: #47cdff;
7 + --color-background-dark: #0f1e23;
8 + --color-green-status: #50e3c2;
9 + --color-card-dark: #192433;
10 + --color-border-dark: #233348;
11 + --color-text-muted: #92a9c9;
12 +
13 + /* Font families */
14 + --font-family-display: "Public Sans", sans-serif;
15 +
16 + /* Border radius */
17 + --radius: 0.5rem;
18 + --radius-lg: 0.75rem;
19 + --radius-xl: 1rem;
20 +}
21 +
22 +@layer base {
23 + :root {
24 + /* Dark mode only - using ServerShare color palette */
25 + --background: 197 56% 9%; /* #0f1e23 */
26 + --foreground: 210 40% 98%; /* white text */
27 + --card: 200 48% 12%; /* #192433 */
28 + --card-foreground: 210 40% 98%;
29 + --popover: 200 48% 12%;
30 + --popover-foreground: 210 40% 98%;
31 + --primary: 195 100% 64%; /* #47cdff */
32 + --primary-foreground: 0 0% 0%;
33 + --secondary: 200 34% 18%; /* #233348 */
34 + --secondary-foreground: 210 40% 98%;
35 + --muted: 200 34% 18%;
36 + --muted-foreground: 207 39% 68%; /* #92a9c9 */
37 + --accent: 200 34% 18%;
38 + --accent-foreground: 210 40% 98%;
39 + --destructive: 0 84.2% 60.2%;
40 + --destructive-foreground: 210 40% 98%;
41 + --border: 207 28% 21%; /* #233348 */
42 + --input: 207 28% 21%;
43 + --ring: 195 100% 64%; /* #47cdff */
44 + }
45 +
46 + * {
47 + border-color: hsl(var(--border));
48 + }
49 +
50 + body {
51 + background-color: var(--color-background-dark);
52 + color: rgb(255 255 255);
53 + font-family: var(--font-family-display);
54 + }
55 +
56 + /* Force dark mode always */
57 + html {
58 + color-scheme: dark;
59 + }
60 +}
cmd/relay-server/frontend/src/lib/countries.ts new
+199
@@ -0,0 +1,199 @@
1 +// ISO 3166-1 alpha-2 country code to country name mapping
2 +export const COUNTRY_NAMES: Record<string, string> = {
3 + AF: "Afghanistan",
4 + AL: "Albania",
5 + DZ: "Algeria",
6 + AD: "Andorra",
7 + AO: "Angola",
8 + AR: "Argentina",
9 + AM: "Armenia",
10 + AU: "Australia",
11 + AT: "Austria",
12 + AZ: "Azerbaijan",
13 + BS: "Bahamas",
14 + BH: "Bahrain",
15 + BD: "Bangladesh",
16 + BB: "Barbados",
17 + BY: "Belarus",
18 + BE: "Belgium",
19 + BZ: "Belize",
20 + BJ: "Benin",
21 + BT: "Bhutan",
22 + BO: "Bolivia",
23 + BA: "Bosnia and Herzegovina",
24 + BW: "Botswana",
25 + BR: "Brazil",
26 + BN: "Brunei",
27 + BG: "Bulgaria",
28 + BF: "Burkina Faso",
29 + BI: "Burundi",
30 + KH: "Cambodia",
31 + CM: "Cameroon",
32 + CA: "Canada",
33 + CV: "Cape Verde",
34 + CF: "Central African Republic",
35 + TD: "Chad",
36 + CL: "Chile",
37 + CN: "China",
38 + CO: "Colombia",
39 + KM: "Comoros",
40 + CG: "Congo",
41 + CD: "Congo (DRC)",
42 + CR: "Costa Rica",
43 + HR: "Croatia",
44 + CU: "Cuba",
45 + CY: "Cyprus",
46 + CZ: "Czech Republic",
47 + DK: "Denmark",
48 + DJ: "Djibouti",
49 + DM: "Dominica",
50 + DO: "Dominican Republic",
51 + EC: "Ecuador",
52 + EG: "Egypt",
53 + SV: "El Salvador",
54 + GQ: "Equatorial Guinea",
55 + ER: "Eritrea",
56 + EE: "Estonia",
57 + ET: "Ethiopia",
58 + FJ: "Fiji",
59 + FI: "Finland",
60 + FR: "France",
61 + GA: "Gabon",
62 + GM: "Gambia",
63 + GE: "Georgia",
64 + DE: "Germany",
65 + GH: "Ghana",
66 + GR: "Greece",
67 + GD: "Grenada",
68 + GT: "Guatemala",
69 + GN: "Guinea",
70 + GW: "Guinea-Bissau",
71 + GY: "Guyana",
72 + HT: "Haiti",
73 + HN: "Honduras",
74 + HK: "Hong Kong",
75 + HU: "Hungary",
76 + IS: "Iceland",
77 + IN: "India",
78 + ID: "Indonesia",
79 + IR: "Iran",
80 + IQ: "Iraq",
81 + IE: "Ireland",
82 + IL: "Israel",
83 + IT: "Italy",
84 + JM: "Jamaica",
85 + JP: "Japan",
86 + JO: "Jordan",
87 + KZ: "Kazakhstan",
88 + KE: "Kenya",
89 + KI: "Kiribati",
90 + KP: "North Korea",
91 + KR: "South Korea",
92 + KW: "Kuwait",
93 + KG: "Kyrgyzstan",
94 + LA: "Laos",
95 + LV: "Latvia",
96 + LB: "Lebanon",
97 + LS: "Lesotho",
98 + LR: "Liberia",
99 + LY: "Libya",
100 + LI: "Liechtenstein",
101 + LT: "Lithuania",
102 + LU: "Luxembourg",
103 + MO: "Macau",
104 + MK: "North Macedonia",
105 + MG: "Madagascar",
106 + MW: "Malawi",
107 + MY: "Malaysia",
108 + MV: "Maldives",
109 + ML: "Mali",
110 + MT: "Malta",
111 + MH: "Marshall Islands",
112 + MR: "Mauritania",
113 + MU: "Mauritius",
114 + MX: "Mexico",
115 + FM: "Micronesia",
116 + MD: "Moldova",
117 + MC: "Monaco",
118 + MN: "Mongolia",
119 + ME: "Montenegro",
120 + MA: "Morocco",
121 + MZ: "Mozambique",
122 + MM: "Myanmar",
123 + NA: "Namibia",
124 + NR: "Nauru",
125 + NP: "Nepal",
126 + NL: "Netherlands",
127 + NZ: "New Zealand",
128 + NI: "Nicaragua",
129 + NE: "Niger",
130 + NG: "Nigeria",
131 + NO: "Norway",
132 + OM: "Oman",
133 + PK: "Pakistan",
134 + PW: "Palau",
135 + PS: "Palestine",
136 + PA: "Panama",
137 + PG: "Papua New Guinea",
138 + PY: "Paraguay",
139 + PE: "Peru",
140 + PH: "Philippines",
141 + PL: "Poland",
142 + PT: "Portugal",
143 + QA: "Qatar",
144 + RO: "Romania",
145 + RU: "Russia",
146 + RW: "Rwanda",
147 + KN: "Saint Kitts and Nevis",
148 + LC: "Saint Lucia",
149 + VC: "Saint Vincent",
150 + WS: "Samoa",
151 + SM: "San Marino",
152 + ST: "Sao Tome and Principe",
153 + SA: "Saudi Arabia",
154 + SN: "Senegal",
155 + RS: "Serbia",
156 + SC: "Seychelles",
157 + SL: "Sierra Leone",
158 + SG: "Singapore",
159 + SK: "Slovakia",
160 + SI: "Slovenia",
161 + SB: "Solomon Islands",
162 + SO: "Somalia",
163 + ZA: "South Africa",
164 + SS: "South Sudan",
165 + ES: "Spain",
166 + LK: "Sri Lanka",
167 + SD: "Sudan",
168 + SR: "Suriname",
169 + SZ: "Swaziland",
170 + SE: "Sweden",
171 + CH: "Switzerland",
172 + SY: "Syria",
173 + TW: "Taiwan",
174 + TJ: "Tajikistan",
175 + TZ: "Tanzania",
176 + TH: "Thailand",
177 + TL: "Timor-Leste",
178 + TG: "Togo",
179 + TO: "Tonga",
180 + TT: "Trinidad and Tobago",
181 + TN: "Tunisia",
182 + TR: "Turkey",
183 + TM: "Turkmenistan",
184 + TV: "Tuvalu",
185 + UG: "Uganda",
186 + UA: "Ukraine",
187 + AE: "United Arab Emirates",
188 + GB: "United Kingdom",
189 + US: "United States",
190 + UY: "Uruguay",
191 + UZ: "Uzbekistan",
192 + VU: "Vanuatu",
193 + VA: "Vatican City",
194 + VE: "Venezuela",
195 + VN: "Vietnam",
196 + YE: "Yemen",
197 + ZM: "Zambia",
198 + ZW: "Zimbabwe",
199 +};
cmd/relay-server/frontend/src/lib/utils.ts new
+6
@@ -0,0 +1,6 @@
1 +import { type ClassValue, clsx } from "clsx";
2 +import { twMerge } from "tailwind-merge";
3 +
4 +export function cn(...inputs: ClassValue[]) {
5 + return twMerge(clsx(inputs));
6 +}
cmd/relay-server/frontend/src/main.tsx new
+10
@@ -0,0 +1,10 @@
1 +import React from "react";
2 +import ReactDOM from "react-dom/client";
3 +import App from "./App.tsx";
4 +import "./index.css";
5 +
6 +ReactDOM.createRoot(document.getElementById("root")!).render(
7 + <React.StrictMode>
8 + <App />
9 + </React.StrictMode>
10 +);
cmd/relay-server/frontend/src/vite-env.d.ts new
+1
@@ -0,0 +1 @@
1 +/// <reference types="vite/client" />
cmd/relay-server/frontend/tsconfig.json new
+31
@@ -0,0 +1,31 @@
1 +{
2 + "compilerOptions": {
3 + "target": "ES2020",
4 + "useDefineForClassFields": true,
5 + "lib": ["ES2020", "DOM", "DOM.Iterable"],
6 + "module": "ESNext",
7 + "skipLibCheck": true,
8 +
9 + /* Bundler mode */
10 + "moduleResolution": "bundler",
11 + "allowImportingTsExtensions": true,
12 + "resolveJsonModule": true,
13 + "isolatedModules": true,
14 + "noEmit": true,
15 + "jsx": "react-jsx",
16 +
17 + /* Linting */
18 + "strict": true,
19 + "noUnusedLocals": true,
20 + "noUnusedParameters": true,
21 + "noFallthroughCasesInSwitch": true,
22 +
23 + /* Path aliases */
24 + "baseUrl": ".",
25 + "paths": {
26 + "@/*": ["./src/*"]
27 + }
28 + },
29 + "include": ["src"],
30 + "references": [{ "path": "./tsconfig.node.json" }]
31 +}
cmd/relay-server/frontend/tsconfig.node.json new
+10
@@ -0,0 +1,10 @@
1 +{
2 + "compilerOptions": {
3 + "composite": true,
4 + "skipLibCheck": true,
5 + "module": "ESNext",
6 + "moduleResolution": "bundler",
7 + "allowSyntheticDefaultImports": true
8 + },
9 + "include": ["vite.config.ts"]
10 +}
cmd/relay-server/frontend/vite.config.ts new
+41
@@ -0,0 +1,41 @@
1 +import { defineConfig } from "vite";
2 +import react from "@vitejs/plugin-react";
3 +import tailwindcss from "@tailwindcss/vite";
4 +import { resolve } from "path";
5 +import { renameSync } from "fs";
6 +
7 +// https://vitejs.dev/config/
8 +export default defineConfig({
9 + plugins: [
10 + react(),
11 + tailwindcss(),
12 + {
13 + name: "rename-index",
14 + closeBundle() {
15 + const appDir = resolve(process.cwd(), "../app");
16 + const indexPath = resolve(appDir, "index.html");
17 + const portalPath = resolve(appDir, "portal.html");
18 + try {
19 + renameSync(indexPath, portalPath);
20 + console.log("✓ Renamed index.html to portal.html");
21 + } catch (err) {
22 + console.error("Failed to rename index.html:", err);
23 + }
24 + },
25 + },
26 + ],
27 + resolve: {
28 + alias: {
29 + "@": resolve(process.cwd(), "./src"),
30 + },
31 + },
32 + build: {
33 + outDir: "../app",
34 + emptyOutDir: false,
35 + rollupOptions: {
36 + output: {
37 + manualChunks: undefined,
38 + },
39 + },
40 + },
41 +});
cmd/relay-server/main.go
+2 -2
@@ -49,7 +49,7 @@ func main() {
49 var flagBootstrapsCSV string
50 flag.StringVar(&flagBootstrapsCSV, "bootstraps", defaultBootstraps, "bootstrap addresses (comma-separated)")
51 flag.StringVar(&flagALPN, "alpn", "http/1.1", "ALPN identifier for this service")
52 - flag.IntVar(&flagPort, "port", 4017, "admin UI and HTTP proxy port")
52 + flag.IntVar(&flagPort, "port", 4017, "app UI and HTTP proxy port")
53 flag.StringVar(&flagPortalHost, "portal-host", defaultPortalHost, "portal host for frontend serving (env: PORTAL_HOST)")
54 flag.IntVar(&flagMaxLease, "max-lease", 0, "maximum active relayed connections per lease (0 = unlimited)")
55 flag.IntVar(&flagLeaseBPS, "lease-bps", 0, "default bytes-per-second limit per lease (0 = unlimited)")
@@ -125,7 +125,7 @@ func runServer() error {
125 serv.Start()
126 defer serv.Stop()
127
128 - // Admin UI + Relay + Static Frontend
128 + // App UI + Relay + Static Frontend
129 httpSrv := serveHTTP(ctx, fmt.Sprintf(":%d", flagPort), serv, cred.ID(), flagBootstraps, stop)
130
131 <-ctx.Done()
cmd/relay-server/static/GeoLite2-Country.mmdb
Binary files /dev/null and b/cmd/relay-server/static/GeoLite2-Country.mmdb differ
cmd/relay-server/view.go
+187 -55
@@ -5,12 +5,14 @@ import (
5 "embed"
6 "encoding/json"
7 "fmt"
8 - "html/template"
8 + "net"
9 "net/http"
10 "strings"
11 + "sync"
12 "time"
13
14 "github.com/gorilla/websocket"
15 + "github.com/oschwald/geoip2-golang"
16 "github.com/rs/zerolog/log"
17
18 "gosuda.org/portal/portal"
@@ -21,6 +23,16 @@ import (
23 //go:embed static
24 var assetsFS embed.FS
25
26 +//go:embed static/GeoLite2-Country.mmdb
27 +var geoipFS embed.FS
28 +
29 +// GeoIP database reader (global instance with lazy initialization)
30 +var (
31 + geoipReader *geoip2.Reader
32 + geoipReaderOnce sync.Once
33 + geoipReaderErr error
34 +)
35 +
36 func serveAsset(mux *http.ServeMux, route, assetPath, contentType string) {
37 mux.HandleFunc(route, func(w http.ResponseWriter, r *http.Request) {
38 b, err := assetsFS.ReadFile(assetPath)
@@ -42,30 +54,27 @@ func serveHTTP(_ context.Context, addr string, serv *portal.RelayServer, nodeID
54 addr = ":0"
55 }
56
45 - // Parse template once per server instance (no global var)
46 - tmpl := template.Must(template.ParseFS(assetsFS, "static/index.html"))
57 + // Create app UI mux
58 + appMux := http.NewServeMux()
59
48 - // Create admin UI mux
49 - adminMux := http.NewServeMux()
60 + // Serve embedded favicons (ico/png/svg) for portal UI
61 + serveAsset(appMux, "/favicon.ico", "static/favicon/favicon.ico", "image/x-icon")
62 + serveAsset(appMux, "/favicon.png", "static/favicon/favicon.png", "image/png")
63 + serveAsset(appMux, "/favicon.svg", "static/favicon/favicon.svg", "image/svg+xml")
64
51 - // Serve embedded favicons (ico/png/svg) for admin UI
52 - serveAsset(adminMux, "/favicon.ico", "static/favicon/favicon.ico", "image/x-icon")
53 - serveAsset(adminMux, "/favicon.png", "static/favicon/favicon.png", "image/png")
54 - serveAsset(adminMux, "/favicon.svg", "static/favicon/favicon.svg", "image/svg+xml")
55 -
56 - // Static assets for admin UI (embedded files)
57 - adminMux.HandleFunc("/static/", func(w http.ResponseWriter, r *http.Request) {
65 + // Portal app assets (JS, CSS, etc.) - served from /app/
66 + appMux.HandleFunc("/app/", func(w http.ResponseWriter, r *http.Request) {
67 setCORSHeaders(w)
68 if r.Method == http.MethodOptions {
69 w.WriteHeader(http.StatusOK)
70 return
71 }
63 - path := strings.TrimPrefix(r.URL.Path, "/static/")
64 - serveAdminStatic(w, r, path)
72 + path := strings.TrimPrefix(r.URL.Path, "/app/")
73 + serveAppStatic(w, r, path, serv)
74 })
75
67 - // Portal frontend files (for unified caching)
68 - adminMux.HandleFunc("/frontend/", func(w http.ResponseWriter, r *http.Request) {
76 + // Portal frontend files (for unified caching)
77 + appMux.HandleFunc("/frontend/", func(w http.ResponseWriter, r *http.Request) {
78 setCORSHeaders(w)
79 if r.Method == http.MethodOptions {
80 w.WriteHeader(http.StatusOK)
@@ -75,14 +84,14 @@ func serveHTTP(_ context.Context, addr string, serv *portal.RelayServer, nodeID
84
85 // Special handling for manifest.json - generate dynamically
86 if path == "manifest.json" {
78 - serveDynamicManifest(w, r)
87 + serveDynamicManifest(w)
88 return
89 }
90
91 servePortalStaticFile(w, r, path)
92 })
93
85 - adminMux.HandleFunc("/relay", func(w http.ResponseWriter, r *http.Request) {
94 + appMux.HandleFunc("/relay", func(w http.ResponseWriter, r *http.Request) {
95 if r.Method != http.MethodGet {
96 w.Header().Set("Allow", http.MethodGet)
97 http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
@@ -96,36 +105,21 @@ func serveHTTP(_ context.Context, addr string, serv *portal.RelayServer, nodeID
105 }
106
107 stream := &wsstream.WsStream{Conn: wsConn}
99 - if err := serv.HandleConnection(stream); err != nil {
108 + if err := serv.HandleConnection(stream, r.RemoteAddr); err != nil {
109 log.Error().Err(err).Msg("[server] websocket relay connection error")
110 wsConn.Close()
111 return
112 }
113 })
114
106 - // Admin UI index page
107 - adminMux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
108 - if r.URL.Path != "/" {
109 - http.NotFound(w, r)
110 - return
111 - }
112 -
113 - // Convert lease entries to rows for the admin page
114 - rows := convertLeaseEntriesToRows(serv)
115 -
116 - data := adminPageData{
117 - NodeID: nodeID,
118 - Bootstraps: bootstraps,
119 - Rows: rows,
120 - }
121 -
122 - w.Header().Set("Content-Type", "text/html; charset=utf-8")
123 - if err := tmpl.Execute(w, data); err != nil {
124 - log.Error().Err(err).Msg("[server] error rendering admin index")
125 - }
115 + // App UI index page - serve React frontend with SSR (delegates to serveAppStatic)
116 + appMux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
117 + // serveAppStatic handles both "/" and 404 fallback with SSR
118 + path := strings.TrimPrefix(r.URL.Path, "/")
119 + serveAppStatic(w, r, path, serv)
120 })
121
128 - adminMux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
122 + appMux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
123 w.WriteHeader(http.StatusOK)
124 w.Write([]byte("{\"status\":\"ok\"}"))
125 })
@@ -133,12 +127,12 @@ func serveHTTP(_ context.Context, addr string, serv *portal.RelayServer, nodeID
127 // Create portal frontend mux
128 portalMux := createPortalMux()
129
136 - // Top-level handler that routes based on host
130 + // Top-level handler that routes based on host and path
131 topHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
132 if isPortalSubdomain(r.Host) {
133 portalMux.ServeHTTP(w, r)
134 } else {
141 - adminMux.ServeHTTP(w, r)
135 + appMux.ServeHTTP(w, r)
136 }
137 })
138
@@ -170,23 +164,131 @@ type leaseRow struct {
164 Link string
165 StaleRed bool
166 Hide bool
173 - Description string
174 - Tags string
175 - Owner string
167 + Metadata string
168 + Region string
169 + CountryCode string
170 }
171
178 -type adminPageData struct {
179 - NodeID string
180 - Bootstraps []string
181 - Rows []leaseRow
172 +// initGeoIP initializes the GeoIP database reader (lazy loaded)
173 +func initGeoIP() error {
174 + geoipReaderOnce.Do(func() {
175 + // Try to load from embedded FS first
176 + data, err := geoipFS.ReadFile("static/GeoLite2-Country.mmdb")
177 + if err == nil {
178 + reader, err := geoip2.FromBytes(data)
179 + if err == nil {
180 + geoipReader = reader
181 + log.Info().
182 + Str("source", "embedded").
183 + Int("size", len(data)).
184 + Msg("GeoIP database loaded successfully from embedded FS")
185 + return
186 + }
187 + log.Warn().Err(err).Msg("Failed to parse embedded GeoIP database")
188 + } else {
189 + log.Debug().Err(err).Msg("Embedded GeoIP database not found, trying file paths")
190 + }
191 + })
192 +
193 + return geoipReaderErr
194 }
195
184 -// convertLeaseEntriesToRows converts LeaseEntry data from LeaseManager to leaseRow format for the admin page
196 +// getRegionFromIP extracts region information from an IP address
197 +func getRegionFromIP(ipStr string) (region, countryCode string) {
198 + // Initialize GeoIP if needed
199 + if err := initGeoIP(); err != nil {
200 + return "unknown", ""
201 + }
202 +
203 + // Parse IP address
204 + ip := net.ParseIP(ipStr)
205 + if ip == nil {
206 + return "unknown", ""
207 + }
208 +
209 + // Skip private/local IPs
210 + if ip.IsLoopback() || ip.IsPrivate() {
211 + log.Debug().Str("ip", ipStr).Msg("[GeoIP] Skipping local/private IP")
212 + return "local", ""
213 + }
214 +
215 + // Lookup country record
216 + record, err := geoipReader.Country(ip)
217 + if err != nil {
218 + log.Debug().Err(err).Str("ip", ipStr).Msg("GeoIP lookup failed")
219 + return "unknown", ""
220 + }
221 +
222 + // Extract country code
223 + countryCode = record.Country.IsoCode
224 +
225 + // Map country code to region
226 + // Based on common regional groupings used in gaming/CDN services
227 + switch countryCode {
228 + // North America
229 + case "US", "CA", "MX", "GT", "HN", "SV", "NI", "CR", "PA", "BZ":
230 + region = "us-east"
231 +
232 + // South America
233 + case "BR", "AR", "CL", "CO", "PE", "VE", "EC", "BO", "PY", "UY", "GY", "SR", "GF":
234 + region = "south-america"
235 +
236 + // Europe - West
237 + case "GB", "IE", "PT", "ES", "FR", "BE", "NL", "LU":
238 + region = "eu-west"
239 +
240 + // Europe - Central/East
241 + case "DE", "AT", "CH", "IT", "PL", "CZ", "SK", "HU", "RO", "BG", "SI", "HR", "BA", "RS", "ME", "AL", "MK", "GR", "CY":
242 + region = "eu-central"
243 +
244 + // Europe - North
245 + case "SE", "NO", "DK", "FI", "IS", "EE", "LV", "LT":
246 + region = "eu-west"
247 +
248 + // Asia - East
249 + case "JP", "KR", "CN", "TW", "HK", "MO":
250 + region = "asia-pacific"
251 +
252 + // Asia - Southeast
253 + case "SG", "MY", "TH", "ID", "PH", "VN", "LA", "KH", "MM", "BN":
254 + region = "asia-pacific"
255 +
256 + // Asia - South
257 + case "IN", "PK", "BD", "LK", "NP", "BT", "MV":
258 + region = "asia-pacific"
259 +
260 + // Oceania
261 + case "AU", "NZ", "FJ", "PG", "NC", "PF", "SB", "VU", "WS", "TO":
262 + region = "asia-pacific"
263 +
264 + // Middle East
265 + case "AE", "SA", "IL", "TR", "EG", "IQ", "IR", "JO", "LB", "SY", "YE", "OM", "KW", "BH", "QA":
266 + region = "eu-central"
267 +
268 + // Africa
269 + case "ZA", "NG", "KE", "GH", "TZ", "UG", "ET", "MA", "DZ", "TN", "LY", "SD", "AO", "MZ", "ZW", "BW", "NA", "ZM", "MW", "MG":
270 + region = "eu-west"
271 +
272 + default:
273 + region = "unknown"
274 + }
275 +
276 + log.Debug().
277 + Str("ip", ipStr).
278 + Str("region", region).
279 + Str("country", countryCode).
280 + Msg("[GeoIP] Region mapped successfully")
281 +
282 + return region, countryCode
283 +}
284 +
285 +// convertLeaseEntriesToRows converts LeaseEntry data from LeaseManager to leaseRow format for the app page
286 func convertLeaseEntriesToRows(serv *portal.RelayServer) []leaseRow {
287 // Get all lease entries directly from the lease manager
288 leaseEntries := serv.GetAllLeaseEntries()
289
189 - var rows []leaseRow
290 + // Initialize with empty slice instead of nil to avoid "null" in JSON
291 + rows := []leaseRow{}
292 now := time.Now()
293
294 for _, leaseEntry := range leaseEntries {
@@ -285,6 +387,34 @@ func convertLeaseEntriesToRows(serv *portal.RelayServer) []leaseRow {
387 link = fmt.Sprintf("//%s.%s/", lease.Name, portalHost)
388 }
389
390 + // Get GeoIP information from RemoteAddr
391 + var region string
392 + var countryCode string
393 + if leaseEntry.RemoteAddr != "" {
394 + // Extract IP from RemoteAddr (format: "ip:port")
395 + ipStr := leaseEntry.RemoteAddr
396 + if idx := strings.LastIndex(ipStr, ":"); idx != -1 {
397 + ipStr = ipStr[:idx]
398 + }
399 + log.Info().
400 + Str("lease_id", identityID).
401 + Str("remote_addr", leaseEntry.RemoteAddr).
402 + Str("extracted_ip", ipStr).
403 + Msg("[GeoIP] Processing lease RemoteAddr")
404 + region, countryCode = getRegionFromIP(ipStr)
405 + log.Info().
406 + Str("lease_id", identityID).
407 + Str("region", region).
408 + Str("country_code", countryCode).
409 + Msg("[GeoIP] Region detected")
410 + } else {
411 + log.Info().
412 + Str("lease_id", identityID).
413 + Msg("[GeoIP] No RemoteAddr available for lease")
414 + region = "unknown"
415 + countryCode = ""
416 + }
417 +
418 row := leaseRow{
419 Peer: identityID,
420 Name: name,
@@ -297,12 +427,14 @@ func convertLeaseEntriesToRows(serv *portal.RelayServer) []leaseRow {
427 Link: link,
428 StaleRed: !connected && since >= 15*time.Second,
429 Hide: meta.Hide,
300 - Description: strings.TrimSpace(meta.Description),
301 - Tags: strings.Join(meta.Tags, ", "),
302 - Owner: strings.TrimSpace(meta.Owner),
430 + Metadata: lease.Metadata,
431 + Region: region,
432 + CountryCode: countryCode,
433 }
434
305 - rows = append(rows, row)
435 + if row.Hide != true {
436 + rows = append(rows, row)
437 + }
438 }
439
440 return rows
go.mod
+2
@@ -5,6 +5,7 @@ go 1.25.3
5 require (
6 github.com/gorilla/websocket v1.5.3
7 github.com/hashicorp/yamux v0.1.2
8 + github.com/oschwald/geoip2-golang v1.13.0
9 github.com/planetscale/vtprotobuf v0.6.0
10 github.com/rs/zerolog v1.34.0
11 github.com/stretchr/testify v1.9.0
@@ -19,6 +20,7 @@ require (
20 github.com/davecgh/go-spew v1.1.1 // indirect
21 github.com/mattn/go-colorable v0.1.14 // indirect
22 github.com/mattn/go-isatty v0.0.20 // indirect
23 + github.com/oschwald/maxminddb-golang v1.13.0 // indirect
24 github.com/pmezard/go-difflib v1.0.0 // indirect
25 golang.org/x/sys v0.37.0 // indirect
26 golang.org/x/text v0.30.0 // indirect
go.sum
+4
@@ -15,6 +15,10 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
15 github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
16 github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
17 github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
18 +github.com/oschwald/geoip2-golang v1.13.0 h1:Q44/Ldc703pasJeP5V9+aFSZFmBN7DKHbNsSFzQATJI=
19 +github.com/oschwald/geoip2-golang v1.13.0/go.mod h1:P9zG+54KPEFOliZ29i7SeYZ/GM6tfEL+rgSn03hYuUo=
20 +github.com/oschwald/maxminddb-golang v1.13.0 h1:R8xBorY71s84yO06NgTmQvqvTvlS/bnYZrrWX1MElnU=
21 +github.com/oschwald/maxminddb-golang v1.13.0/go.mod h1:BU0z8BfFVhi1LQaonTwwGQlsHUEu9pWNdMfmq4ztm0o=
22 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
23 github.com/planetscale/vtprotobuf v0.6.0 h1:nBeETjudeJ5ZgBHUz1fVHvbqUKnYOXNhsIEabROxmNA=
24 github.com/planetscale/vtprotobuf v0.6.0/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
portal/core/cryptoops/handshaker.go
+3
@@ -190,6 +190,9 @@ func (sc *SecureConnection) writeFragmentation(p []byte) (int, error) {
190
191 // Read reads and decrypts data from the underlying connection
192 func (sc *SecureConnection) Read(p []byte) (int, error) {
193 + if sc == nil || sc.conn == nil {
194 + return 0, errors.New("connection is nil")
195 + }
196 if len(sc.readBuffer.B) > 0 {
197 n := copy(p, sc.readBuffer.B)
198 copy(sc.readBuffer.B[:len(sc.readBuffer.B)-n], sc.readBuffer.B[n:])
portal/handlers.go
+1 -1
@@ -65,7 +65,7 @@ func (g *RelayServer) handleLeaseUpdateRequest(ctx *StreamContext, packet *rdver
65 var resp rdverb.LeaseUpdateResponse
66
67 // Update lease in lease manager
68 - if g.leaseManager.UpdateLease(req.Lease, ctx.ConnectionID) {
68 + if g.leaseManager.UpdateLease(req.Lease, ctx.ConnectionID, ctx.Connection.RemoteAddr) {
69 resp.Code = rdverb.ResponseCode_RESPONSE_CODE_ACCEPTED
70
71 // Register lease connection
portal/lease.go
+4 -2
@@ -13,7 +13,8 @@ type LeaseEntry struct {
13 Lease *rdverb.Lease
14 Expires time.Time
15 LastSeen time.Time
16 - ConnectionID int64 // Store the connection ID
16 + ConnectionID int64 // Store the connection ID
17 + RemoteAddr string // Store the remote IP address
18 }
19
20 type LeaseManager struct {
@@ -78,7 +79,7 @@ func (lm *LeaseManager) cleanupExpiredLeases() {
79 }
80 }
81
81 -func (lm *LeaseManager) UpdateLease(lease *rdverb.Lease, connectionID int64) bool {
82 +func (lm *LeaseManager) UpdateLease(lease *rdverb.Lease, connectionID int64, remoteAddr string) bool {
83 lm.leasesLock.Lock()
84 defer lm.leasesLock.Unlock()
85
@@ -128,6 +129,7 @@ func (lm *LeaseManager) UpdateLease(lease *rdverb.Lease, connectionID int64) boo
129 Expires: expires,
130 LastSeen: time.Now(),
131 ConnectionID: connectionID,
132 + RemoteAddr: remoteAddr,
133 }
134
135 // Apply default BPS limit for this lease if configured and no explicit limit set
portal/lease_test.go
+10 -10
@@ -40,12 +40,12 @@ func TestLeaseManager_NameConflict(t *testing.T) {
40 }
41
42 // First lease should succeed
43 - if !lm.UpdateLease(lease1, 1) {
43 + if !lm.UpdateLease(lease1, 1, "192.168.1.1:1234") {
44 t.Fatal("First lease registration should succeed")
45 }
46
47 // Second lease with same name should fail (name conflict)
48 - if lm.UpdateLease(lease2, 2) {
48 + if lm.UpdateLease(lease2, 2, "192.168.1.2:1234") {
49 t.Fatal("Second lease registration should fail due to name conflict")
50 }
51
@@ -91,12 +91,12 @@ func TestLeaseManager_SameIdentityUpdate(t *testing.T) {
91 }
92
93 // First registration
94 - if !lm.UpdateLease(lease1, 1) {
94 + if !lm.UpdateLease(lease1, 1, "192.168.1.1:1234") {
95 t.Fatal("First lease registration should succeed")
96 }
97
98 // Update with same identity should succeed (no conflict)
99 - if !lm.UpdateLease(lease2, 1) {
99 + if !lm.UpdateLease(lease2, 1, "192.168.1.1:1234") {
100 t.Fatal("Updating own lease should succeed")
101 }
102
@@ -139,11 +139,11 @@ func TestLeaseManager_EmptyNameAllowed(t *testing.T) {
139 Expires: time.Now().Add(10 * time.Minute).Unix(),
140 }
141
142 - if !lm.UpdateLease(lease1, 1) {
142 + if !lm.UpdateLease(lease1, 1, "192.168.1.1:1234") {
143 t.Fatal("First lease with empty name should succeed")
144 }
145
146 - if !lm.UpdateLease(lease2, 2) {
146 + if !lm.UpdateLease(lease2, 2, "192.168.1.2:1234") {
147 t.Fatal("Second lease with empty name should succeed (empty names don't conflict)")
148 }
149 }
@@ -177,11 +177,11 @@ func TestLeaseManager_UnnamedAllowed(t *testing.T) {
177 Expires: time.Now().Add(10 * time.Minute).Unix(),
178 }
179
180 - if !lm.UpdateLease(lease1, 1) {
180 + if !lm.UpdateLease(lease1, 1, "192.168.1.1:1234") {
181 t.Fatal("First lease with '(unnamed)' should succeed")
182 }
183
184 - if !lm.UpdateLease(lease2, 2) {
184 + if !lm.UpdateLease(lease2, 2, "192.168.1.2:1234") {
185 t.Fatal("Second lease with '(unnamed)' should succeed (unnamed don't conflict)")
186 }
187 }
@@ -215,11 +215,11 @@ func TestLeaseManager_UnicodeNameConflict(t *testing.T) {
215 Expires: time.Now().Add(10 * time.Minute).Unix(),
216 }
217
218 - if !lm.UpdateLease(lease1, 1) {
218 + if !lm.UpdateLease(lease1, 1, "192.168.1.1:1234") {
219 t.Fatal("First lease with Korean name should succeed")
220 }
221
222 - if lm.UpdateLease(lease2, 2) {
222 + if lm.UpdateLease(lease2, 2, "192.168.1.2:1234") {
223 t.Fatal("Second lease with same Korean name should fail")
224 }
225 }
portal/relay.go
+8 -6
@@ -14,8 +14,9 @@ import (
14 )
15
16 type Connection struct {
17 - conn io.ReadWriteCloser
18 - sess *yamux.Session
17 + conn io.ReadWriteCloser
18 + sess *yamux.Session
19 + RemoteAddr string
20
21 streams map[uint32]*yamux.Stream
22 streamsLock sync.Mutex
@@ -253,7 +254,7 @@ func (g *RelayServer) handleStream(stream *yamux.Stream, id int64, connection *C
254 }
255 }
256
256 -func (g *RelayServer) HandleConnection(conn io.ReadWriteCloser) error {
257 +func (g *RelayServer) HandleConnection(conn io.ReadWriteCloser, remoteAddr string) error {
258 log.Debug().Msg("[RelayServer] New connection received")
259
260 sess, err := yamux.Server(conn, _yamux_config)
@@ -266,9 +267,10 @@ func (g *RelayServer) HandleConnection(conn io.ReadWriteCloser) error {
267 g.connidCounter++
268 connID := g.connidCounter
269 connection := &Connection{
269 - conn: conn,
270 - sess: sess,
271 - streams: make(map[uint32]*yamux.Stream),
270 + conn: conn,
271 + sess: sess,
272 + RemoteAddr: remoteAddr,
273 + streams: make(map[uint32]*yamux.Stream),
274 }
275 g.connections[connID] = connection
276 g.connectionsLock.Unlock()