-
-
Save shricodev/4f87d7434e75d1cc24f861b5c4915356 to your computer and use it in GitHub Desktop.
Test 1: Claude Opus 4.5 (Patch file)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| From 6c6604a90b7acac0441c1b3c8919b8ca7ad4a1d4 Mon Sep 17 00:00:00 2001 | |
| From: Shrijal Acharya <shrijal.acharya@gmail.com> | |
| Date: Thu, 5 Feb 2026 12:55:47 +0545 | |
| Subject: [PATCH 1/2] working globe | |
| --- | |
| .env.example | 11 + | |
| .eslintrc.json | 7 + | |
| .gitignore | 42 + | |
| PROMPT.md | 123 + | |
| README.md | 236 + | |
| app/globals.css | 113 + | |
| app/layout.tsx | 37 + | |
| app/page.tsx | 112 + | |
| app/providers.tsx | 21 + | |
| components/Header.tsx | 85 + | |
| components/LoadingScreen.tsx | 23 + | |
| components/globe/CameraControls.tsx | 80 + | |
| components/globe/CoordinateDisplay.tsx | 47 + | |
| components/globe/GlobeViewer.tsx | 401 ++ | |
| components/globe/GlobeWrapper.tsx | 20 + | |
| components/globe/MeasurementOverlay.tsx | 36 + | |
| components/modals/KeyboardShortcuts.tsx | 72 + | |
| components/modals/PinModal.tsx | 165 + | |
| components/panels/LayersPanel.tsx | 139 + | |
| components/panels/MeasurePanel.tsx | 132 + | |
| components/panels/PlacesPanel.tsx | 245 + | |
| components/panels/SidePanel.tsx | 60 + | |
| components/search/SearchBar.tsx | 180 + | |
| components/search/SearchResults.tsx | 89 + | |
| components/ui/button.tsx | 55 + | |
| components/ui/dialog.tsx | 121 + | |
| components/ui/dropdown-menu.tsx | 199 + | |
| components/ui/input.tsx | 24 + | |
| components/ui/label.tsx | 23 + | |
| components/ui/scroll-area.tsx | 47 + | |
| components/ui/switch.tsx | 28 + | |
| components/ui/tabs.tsx | 54 + | |
| components/ui/textarea.tsx | 23 + | |
| components/ui/toast.tsx | 129 + | |
| components/ui/toaster.tsx | 35 + | |
| components/ui/tooltip.tsx | 29 + | |
| components/ui/use-toast.ts | 187 + | |
| hooks/index.ts | 3 + | |
| hooks/useDebounce.ts | 42 + | |
| hooks/useKeyboardShortcuts.ts | 89 + | |
| lib/cesium-config.ts | 78 + | |
| lib/formatting.ts | 78 + | |
| lib/geocoding.ts | 143 + | |
| lib/storage.ts | 102 + | |
| lib/utils.ts | 35 + | |
| next.config.js | 37 + | |
| package-lock.json | 7567 +++++++++++++++++++++++ | |
| package.json | 46 + | |
| postcss.config.js | 6 + | |
| store/index.ts | 4 + | |
| store/useGlobeStore.ts | 44 + | |
| store/useLayersStore.ts | 73 + | |
| store/useMeasureStore.ts | 70 + | |
| store/usePlacesStore.ts | 82 + | |
| tailwind.config.ts | 76 + | |
| tsconfig.json | 26 + | |
| types/index.ts | 97 + | |
| 57 files changed, 12128 insertions(+) | |
| create mode 100644 .env.example | |
| create mode 100644 .eslintrc.json | |
| create mode 100644 .gitignore | |
| create mode 100644 PROMPT.md | |
| create mode 100644 README.md | |
| create mode 100644 app/globals.css | |
| create mode 100644 app/layout.tsx | |
| create mode 100644 app/page.tsx | |
| create mode 100644 app/providers.tsx | |
| create mode 100644 components/Header.tsx | |
| create mode 100644 components/LoadingScreen.tsx | |
| create mode 100644 components/globe/CameraControls.tsx | |
| create mode 100644 components/globe/CoordinateDisplay.tsx | |
| create mode 100644 components/globe/GlobeViewer.tsx | |
| create mode 100644 components/globe/GlobeWrapper.tsx | |
| create mode 100644 components/globe/MeasurementOverlay.tsx | |
| create mode 100644 components/modals/KeyboardShortcuts.tsx | |
| create mode 100644 components/modals/PinModal.tsx | |
| create mode 100644 components/panels/LayersPanel.tsx | |
| create mode 100644 components/panels/MeasurePanel.tsx | |
| create mode 100644 components/panels/PlacesPanel.tsx | |
| create mode 100644 components/panels/SidePanel.tsx | |
| create mode 100644 components/search/SearchBar.tsx | |
| create mode 100644 components/search/SearchResults.tsx | |
| create mode 100644 components/ui/button.tsx | |
| create mode 100644 components/ui/dialog.tsx | |
| create mode 100644 components/ui/dropdown-menu.tsx | |
| create mode 100644 components/ui/input.tsx | |
| create mode 100644 components/ui/label.tsx | |
| create mode 100644 components/ui/scroll-area.tsx | |
| create mode 100644 components/ui/switch.tsx | |
| create mode 100644 components/ui/tabs.tsx | |
| create mode 100644 components/ui/textarea.tsx | |
| create mode 100644 components/ui/toast.tsx | |
| create mode 100644 components/ui/toaster.tsx | |
| create mode 100644 components/ui/tooltip.tsx | |
| create mode 100644 components/ui/use-toast.ts | |
| create mode 100644 hooks/index.ts | |
| create mode 100644 hooks/useDebounce.ts | |
| create mode 100644 hooks/useKeyboardShortcuts.ts | |
| create mode 100644 lib/cesium-config.ts | |
| create mode 100644 lib/formatting.ts | |
| create mode 100644 lib/geocoding.ts | |
| create mode 100644 lib/storage.ts | |
| create mode 100644 lib/utils.ts | |
| create mode 100644 next.config.js | |
| create mode 100644 package-lock.json | |
| create mode 100644 package.json | |
| create mode 100644 postcss.config.js | |
| create mode 100644 store/index.ts | |
| create mode 100644 store/useGlobeStore.ts | |
| create mode 100644 store/useLayersStore.ts | |
| create mode 100644 store/useMeasureStore.ts | |
| create mode 100644 store/usePlacesStore.ts | |
| create mode 100644 tailwind.config.ts | |
| create mode 100644 tsconfig.json | |
| create mode 100644 types/index.ts | |
| diff --git a/.env.example b/.env.example | |
| new file mode 100644 | |
| index 0000000..3e61e42 | |
| --- /dev/null | |
| +++ b/.env.example | |
| @@ -0,0 +1,11 @@ | |
| +# TerraView Environment Variables | |
| + | |
| +# Optional: Cesium Ion Access Token | |
| +# Get a free token at: https://cesium.com/ion/tokens | |
| +# This enables Cesium World Terrain and premium imagery | |
| +# The app works without this, using free OpenStreetMap tiles | |
| +NEXT_PUBLIC_CESIUM_ION_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI0OTM4NTBkYy1iZmFjLTQ1Y2ItOWE5ZS1kYzM1MjhhNTFkNzIiLCJpZCI6Mzg2NjMzLCJpYXQiOjE3NzAxMzUyMjZ9.YQ6I5xZJ8LV4SoEIYEYUbBHXb2wqUdwlJghJjErkHaI | |
| + | |
| +# Optional: Custom base URL for Cesium assets | |
| +# Defaults to /cesium if not set | |
| +NEXT_PUBLIC_CESIUM_BASE_URL= | |
| diff --git a/.eslintrc.json b/.eslintrc.json | |
| new file mode 100644 | |
| index 0000000..a3baadd | |
| --- /dev/null | |
| +++ b/.eslintrc.json | |
| @@ -0,0 +1,7 @@ | |
| +{ | |
| + "extends": ["next/core-web-vitals"], | |
| + "rules": { | |
| + "react-hooks/exhaustive-deps": "warn", | |
| + "no-console": ["warn", { "allow": ["warn", "error"] }] | |
| + } | |
| +} | |
| diff --git a/.gitignore b/.gitignore | |
| new file mode 100644 | |
| index 0000000..c2a2d4c | |
| --- /dev/null | |
| +++ b/.gitignore | |
| @@ -0,0 +1,42 @@ | |
| +# dependencies | |
| +/node_modules | |
| +/.pnp | |
| +.pnp.js | |
| +.yarn/install-state.gz | |
| + | |
| +# testing | |
| +/coverage | |
| + | |
| +# next.js | |
| +/.next/ | |
| +/out/ | |
| + | |
| +# production | |
| +/build | |
| + | |
| +# misc | |
| +.DS_Store | |
| +*.pem | |
| + | |
| +# debug | |
| +npm-debug.log* | |
| +yarn-debug.log* | |
| +yarn-error.log* | |
| + | |
| +# local env files | |
| +.env*.local | |
| +.env | |
| + | |
| +# vercel | |
| +.vercel | |
| + | |
| +# typescript | |
| +*.tsbuildinfo | |
| +next-env.d.ts | |
| + | |
| +# cesium assets (copied during build) | |
| +/public/cesium | |
| + | |
| +# IDE | |
| +.idea | |
| +.vscode | |
| diff --git a/PROMPT.md b/PROMPT.md | |
| new file mode 100644 | |
| index 0000000..1a2ca8d | |
| --- /dev/null | |
| +++ b/PROMPT.md | |
| @@ -0,0 +1,123 @@ | |
| +Build a **Google Earth inspired** web application called **TerraView** using **Next.js (App Router)** with a polished, modern UI and fully working core features. The app should run locally with minimal setup and be structured like a real production app (clean architecture, reusable components, good state management, performance minded). | |
| + | |
| +### 1) Tech stack and constraints | |
| + | |
| +- Framework: **Next.js** (latest stable), **TypeScript**, **App Router** | |
| +- Styling: **Tailwind CSS** (and/or shadcn/ui if you want) | |
| +- 3D globe engine: use a mature library that supports terrain and map imagery well. Pick the option that results in the most functional “Earth-like” experience in a browser. | |
| +- Must work without paid keys. If an optional key improves imagery, support it via environment variable, but provide a default that still works. | |
| +- The project must include: linting, sensible folder structure, and clear README instructions. | |
| + | |
| +### 2) What the app should do (functional requirements) | |
| + | |
| +Implement a working 3D globe with: | |
| + | |
| +1. **3D globe viewer** | |
| + - Smooth pan, rotate, zoom | |
| + - Home button to reset view | |
| + - Display coordinates under cursor (lat, lon) and camera altitude | |
| + | |
| +2. **Search** | |
| + - A search bar that lets users search places by name | |
| + - Use a free geocoding option (like OpenStreetMap Nominatim) with rate limiting and debouncing | |
| + - Search results dropdown, keyboard navigation, click to fly to location | |
| + | |
| +3. **Fly-to and camera controls** | |
| + - Fly-to animation for search and for saved places | |
| + - UI buttons for zoom in/out, tilt, rotate left/right (small increments) | |
| + | |
| +4. **Layer system** | |
| + - A layers panel with toggles, at minimum: | |
| + - Base imagery layer options (at least 2) | |
| + - Optional overlays (borders, labels, or roads if feasible) | |
| + | |
| + - Layer state persists in localStorage | |
| + | |
| +5. **Pins and saved places** | |
| + - Click on the globe to drop a pin | |
| + - Pin modal lets user: | |
| + - Name it | |
| + - Add a note | |
| + - Save it | |
| + | |
| + - Sidebar “Saved Places” list with: | |
| + - fly-to on click | |
| + - rename, delete | |
| + - export/import JSON | |
| + | |
| +6. **Measurement tool** | |
| + - Simple distance measurement: click two or more points, show total distance | |
| + - Clear measurement button | |
| + | |
| +7. **Performance and UX** | |
| + - Viewer loads fast, show a good loading state | |
| + - Avoid blocking renders, use dynamic imports for the globe viewer | |
| + - Make UI responsive for laptop and tablet sizes | |
| + - Error handling for failed geocoding requests and missing imagery support | |
| + | |
| +### 3) UI and product design requirements (this matters a lot) | |
| + | |
| +The UI should feel like a real app, not a demo. | |
| + | |
| +- Layout: | |
| + - Top bar with logo/title on left, search centered, utility icons on right | |
| + - Left side panel with tabs: “Layers”, “Places”, “Measure” | |
| + - Main area is full-screen globe behind the UI | |
| + | |
| +- Visual style: | |
| + - Clean dark mode by default, with a light mode toggle | |
| + - Smooth transitions, hover states, subtle shadows, consistent spacing | |
| + - Use a modern component system (shadcn/ui is fine) and Tailwind for layout | |
| + | |
| +- Small details: | |
| + - Toast notifications for “Saved place”, “Copied coordinates”, “Exported JSON” | |
| + - Keyboard shortcuts tooltip list (for example: / to focus search, Esc to close modals) | |
| + - Empty states that look good (Places panel when nothing is saved) | |
| + - Make sure UI overlays do not interfere with globe interactions except where intentional | |
| + | |
| +### 4) Architecture requirements (do not skip) | |
| + | |
| +Implement with a clean structure: | |
| + | |
| +- `app/` routes with a single main page | |
| +- `components/` for UI and viewer components | |
| +- `lib/` for helpers (geocoding client, localStorage persistence, formatting) | |
| +- `store/` for state management (Zustand recommended) | |
| +- Use dynamic import for the globe viewer so Next.js SSR does not break | |
| +- Strong typing everywhere | |
| + | |
| +### 5) Implementation details (be specific) | |
| + | |
| +- Provide a working globe viewer component that: | |
| + - Initializes the globe | |
| + - Exposes methods like `flyTo(lat, lon, height?)` | |
| + - Lets user click to create pins | |
| + - Emits cursor lat/lon (throttled) | |
| + | |
| +- Geocoding: | |
| + - Debounce input 300 to 500 ms | |
| + - Abort in-flight requests when query changes | |
| + - Show a “Searching…” state and “No results” state | |
| + | |
| +- Persistence: | |
| + - Save places, layer toggles, theme mode in localStorage | |
| + - Provide import/export with schema validation | |
| + | |
| +### 6) Deliverables (what you must output) | |
| + | |
| +When you respond, output: | |
| + | |
| +1. A short explanation of which globe library you chose and why | |
| +2. A file-by-file project scaffold with code blocks for each file | |
| +3. A README with setup steps, scripts, environment variables, and troubleshooting | |
| +4. Notes about limitations and next improvements | |
| + | |
| +### 7) Quality bar | |
| + | |
| +- No pseudo-code for core functionality. The globe, search, pins, layers, and measurement must be implemented in real code. | |
| +- Avoid fragile hacks. Prefer standard approaches used in Next.js apps. | |
| +- The final result should run with: | |
| + - `npm install` | |
| + - `npm run dev` | |
| + | |
| +- Keep the UI polished and consistent. | |
| diff --git a/README.md b/README.md | |
| new file mode 100644 | |
| index 0000000..9fbe984 | |
| --- /dev/null | |
| +++ b/README.md | |
| @@ -0,0 +1,236 @@ | |
| +# TerraView | |
| + | |
| +A Google Earth-inspired 3D globe web application built with Next.js, CesiumJS, and modern web technologies. | |
| + | |
| + | |
| + | |
| +## Features | |
| + | |
| +- **3D Globe Viewer**: Smooth pan, rotate, and zoom with mouse/touch controls | |
| +- **Place Search**: Search locations using OpenStreetMap Nominatim geocoding | |
| +- **Saved Places**: Drop pins, add notes, and save your favorite locations | |
| +- **Layer System**: Switch between multiple base maps (OpenStreetMap, Satellite, Terrain) | |
| +- **Measurement Tool**: Measure distances between points on the globe | |
| +- **Keyboard Shortcuts**: Quick access to all features | |
| +- **Dark/Light Mode**: Theme toggle with system preference support | |
| +- **Data Persistence**: All settings and places saved to localStorage | |
| +- **Export/Import**: Backup and restore your saved places as JSON | |
| + | |
| +## Tech Stack | |
| + | |
| +- **Framework**: Next.js 14 (App Router) | |
| +- **Language**: TypeScript | |
| +- **3D Globe**: CesiumJS via Resium | |
| +- **Styling**: Tailwind CSS + shadcn/ui | |
| +- **State Management**: Zustand | |
| +- **Geocoding**: OpenStreetMap Nominatim API | |
| + | |
| +## Getting Started | |
| + | |
| +### Prerequisites | |
| + | |
| +- Node.js 18.17 or later | |
| +- npm, yarn, or pnpm | |
| + | |
| +### Installation | |
| + | |
| +1. Clone the repository: | |
| +```bash | |
| +git clone <repository-url> | |
| +cd terraview | |
| +``` | |
| + | |
| +2. Install dependencies: | |
| +```bash | |
| +npm install | |
| +``` | |
| + | |
| +3. (Optional) Set up environment variables: | |
| +```bash | |
| +cp .env.example .env.local | |
| +``` | |
| + | |
| +Edit `.env.local` and add your Cesium Ion token for enhanced terrain: | |
| +``` | |
| +NEXT_PUBLIC_CESIUM_ION_TOKEN=your_token_here | |
| +``` | |
| + | |
| +> **Note**: The app works without a Cesium Ion token using free OpenStreetMap/ArcGIS tiles. | |
| +> Get a free token at [cesium.com/ion](https://cesium.com/ion/tokens) for Cesium World Terrain. | |
| + | |
| +4. Start the development server: | |
| +```bash | |
| +npm run dev | |
| +``` | |
| + | |
| +5. Open [http://localhost:3000](http://localhost:3000) in your browser. | |
| + | |
| +## Scripts | |
| + | |
| +| Command | Description | | |
| +|---------|-------------| | |
| +| `npm run dev` | Start development server | | |
| +| `npm run build` | Build for production | | |
| +| `npm run start` | Start production server | | |
| +| `npm run lint` | Run ESLint | | |
| +| `npm run lint:fix` | Fix ESLint issues | | |
| + | |
| +## Keyboard Shortcuts | |
| + | |
| +| Shortcut | Action | | |
| +|----------|--------| | |
| +| `/` | Focus search bar | | |
| +| `Esc` | Close modal / Cancel | | |
| +| `l` | Show Layers panel | | |
| +| `p` | Show Places panel | | |
| +| `m` | Toggle Measure mode | | |
| +| `h` | Go to home view | | |
| +| `+` | Zoom in | | |
| +| `-` | Zoom out | | |
| +| `Shift + ?` | Show shortcuts | | |
| + | |
| +## Project Structure | |
| + | |
| +``` | |
| +terraview/ | |
| +├── app/ # Next.js App Router | |
| +│ ├── globals.css # Global styles + Tailwind | |
| +│ ├── layout.tsx # Root layout | |
| +│ ├── page.tsx # Main page | |
| +│ └── providers.tsx # Theme + context providers | |
| +├── components/ | |
| +│ ├── globe/ # Globe viewer components | |
| +│ │ ├── GlobeViewer.tsx # Main Cesium viewer | |
| +│ │ ├── GlobeWrapper.tsx# Dynamic import wrapper | |
| +│ │ ├── CameraControls.tsx | |
| +│ │ ├── CoordinateDisplay.tsx | |
| +│ │ └── MeasurementOverlay.tsx | |
| +│ ├── modals/ # Modal dialogs | |
| +│ │ ├── PinModal.tsx | |
| +│ │ └── KeyboardShortcuts.tsx | |
| +│ ├── panels/ # Side panel tabs | |
| +│ │ ├── SidePanel.tsx | |
| +│ │ ├── LayersPanel.tsx | |
| +│ │ ├── PlacesPanel.tsx | |
| +│ │ └── MeasurePanel.tsx | |
| +│ ├── search/ # Search components | |
| +│ │ ├── SearchBar.tsx | |
| +│ │ └── SearchResults.tsx | |
| +│ ├── ui/ # shadcn/ui components | |
| +│ ├── Header.tsx | |
| +│ └── LoadingScreen.tsx | |
| +├── hooks/ # Custom React hooks | |
| +│ ├── useDebounce.ts | |
| +│ └── useKeyboardShortcuts.ts | |
| +├── lib/ # Utility functions | |
| +│ ├── cesium-config.ts # Cesium configuration | |
| +│ ├── formatting.ts # Coordinate/distance formatting | |
| +│ ├── geocoding.ts # Nominatim API client | |
| +│ ├── storage.ts # localStorage persistence | |
| +│ └── utils.ts # General utilities | |
| +├── store/ # Zustand stores | |
| +│ ├── useGlobeStore.ts | |
| +│ ├── useLayersStore.ts | |
| +│ ├── useMeasureStore.ts | |
| +│ └── usePlacesStore.ts | |
| +└── types/ # TypeScript definitions | |
| + └── index.ts | |
| +``` | |
| + | |
| +## Environment Variables | |
| + | |
| +| Variable | Description | Required | | |
| +|----------|-------------|----------| | |
| +| `NEXT_PUBLIC_CESIUM_ION_TOKEN` | Cesium Ion access token for enhanced terrain | No | | |
| +| `NEXT_PUBLIC_CESIUM_BASE_URL` | Custom Cesium assets URL | No | | |
| + | |
| +## Available Base Layers | |
| + | |
| +1. **OpenStreetMap**: Standard street map with roads and labels | |
| +2. **ArcGIS Satellite**: High-resolution satellite imagery | |
| +3. **Stamen Terrain**: Terrain visualization with shaded relief | |
| + | |
| +## Data Persistence | |
| + | |
| +All user data is stored in the browser's localStorage: | |
| + | |
| +- **Saved Places**: `terraview-places` | |
| +- **Layer Settings**: `terraview-layers` | |
| +- **Theme Preference**: `terraview-theme` | |
| + | |
| +### Export/Import | |
| + | |
| +1. Go to the Places panel | |
| +2. Click the download icon to export places as JSON | |
| +3. Click the upload icon to import places from a JSON file | |
| + | |
| +The import validates the JSON schema and merges with existing places. | |
| + | |
| +## Troubleshooting | |
| + | |
| +### Globe not loading | |
| + | |
| +1. Check browser console for errors | |
| +2. Ensure you're using a modern browser (Chrome, Firefox, Edge, Safari) | |
| +3. WebGL must be enabled in your browser | |
| +4. Try clearing browser cache | |
| + | |
| +### Search not working | |
| + | |
| +1. OpenStreetMap Nominatim has rate limits (1 request/second) | |
| +2. Check your internet connection | |
| +3. Some queries may return no results | |
| + | |
| +### Cesium assets loading slowly | |
| + | |
| +Cesium assets are loaded from Cesium's official CDN by default. If you experience slow loading: | |
| + | |
| +1. Check your internet connection | |
| +2. Consider self-hosting Cesium assets by setting `NEXT_PUBLIC_CESIUM_BASE_URL` to a local path | |
| +3. Clear browser cache and try again | |
| + | |
| +### Performance issues | |
| + | |
| +1. Close other browser tabs | |
| +2. Try reducing browser window size | |
| +3. Disable unnecessary overlays | |
| +4. Use a dedicated GPU if available | |
| + | |
| +## Limitations | |
| + | |
| +- No 3D terrain without Cesium Ion token (uses 2D globe) | |
| +- Geocoding limited to 1 request/second (Nominatim policy) | |
| +- Overlays (borders, roads) are placeholder toggles without actual tile layers | |
| +- No offline support | |
| +- localStorage has ~5MB limit for saved places | |
| + | |
| +## Future Improvements | |
| + | |
| +- [ ] Add actual overlay tile layers (borders, roads) | |
| +- [ ] Implement 3D buildings in major cities | |
| +- [ ] Add street view integration | |
| +- [ ] Support GPX/KML file import | |
| +- [ ] Add route planning | |
| +- [ ] Implement collaborative sharing | |
| +- [ ] Add weather/climate overlays | |
| +- [ ] Mobile app version | |
| + | |
| +## Contributing | |
| + | |
| +1. Fork the repository | |
| +2. Create a feature branch | |
| +3. Make your changes | |
| +4. Run linting: `npm run lint` | |
| +5. Submit a pull request | |
| + | |
| +## License | |
| + | |
| +MIT License - see LICENSE file for details. | |
| + | |
| +## Acknowledgments | |
| + | |
| +- [CesiumJS](https://cesium.com/) - 3D globe engine | |
| +- [Resium](https://resium.reearth.io/) - React bindings for Cesium | |
| +- [OpenStreetMap](https://www.openstreetmap.org/) - Map data and tiles | |
| +- [shadcn/ui](https://ui.shadcn.com/) - UI components | |
| +- [Lucide](https://lucide.dev/) - Icons | |
| diff --git a/app/globals.css b/app/globals.css | |
| new file mode 100644 | |
| index 0000000..f04146d | |
| --- /dev/null | |
| +++ b/app/globals.css | |
| @@ -0,0 +1,113 @@ | |
| +@tailwind base; | |
| +@tailwind components; | |
| +@tailwind utilities; | |
| + | |
| +@layer base { | |
| + :root { | |
| + --background: 0 0% 100%; | |
| + --foreground: 222.2 84% 4.9%; | |
| + --card: 0 0% 100%; | |
| + --card-foreground: 222.2 84% 4.9%; | |
| + --popover: 0 0% 100%; | |
| + --popover-foreground: 222.2 84% 4.9%; | |
| + --primary: 221.2 83.2% 53.3%; | |
| + --primary-foreground: 210 40% 98%; | |
| + --secondary: 210 40% 96.1%; | |
| + --secondary-foreground: 222.2 47.4% 11.2%; | |
| + --muted: 210 40% 96.1%; | |
| + --muted-foreground: 215.4 16.3% 46.9%; | |
| + --accent: 210 40% 96.1%; | |
| + --accent-foreground: 222.2 47.4% 11.2%; | |
| + --destructive: 0 84.2% 60.2%; | |
| + --destructive-foreground: 210 40% 98%; | |
| + --border: 214.3 31.8% 91.4%; | |
| + --input: 214.3 31.8% 91.4%; | |
| + --ring: 221.2 83.2% 53.3%; | |
| + --radius: 0.5rem; | |
| + } | |
| + | |
| + .dark { | |
| + --background: 222.2 84% 4.9%; | |
| + --foreground: 210 40% 98%; | |
| + --card: 222.2 84% 4.9%; | |
| + --card-foreground: 210 40% 98%; | |
| + --popover: 222.2 84% 6%; | |
| + --popover-foreground: 210 40% 98%; | |
| + --primary: 217.2 91.2% 59.8%; | |
| + --primary-foreground: 222.2 47.4% 11.2%; | |
| + --secondary: 217.2 32.6% 17.5%; | |
| + --secondary-foreground: 210 40% 98%; | |
| + --muted: 217.2 32.6% 17.5%; | |
| + --muted-foreground: 215 20.2% 65.1%; | |
| + --accent: 217.2 32.6% 17.5%; | |
| + --accent-foreground: 210 40% 98%; | |
| + --destructive: 0 62.8% 50.6%; | |
| + --destructive-foreground: 210 40% 98%; | |
| + --border: 217.2 32.6% 17.5%; | |
| + --input: 217.2 32.6% 17.5%; | |
| + --ring: 224.3 76.3% 48%; | |
| + } | |
| +} | |
| + | |
| +@layer base { | |
| + * { | |
| + @apply border-border; | |
| + } | |
| + body { | |
| + @apply bg-background text-foreground; | |
| + } | |
| +} | |
| + | |
| +/* Hide Cesium credits - we acknowledge in UI instead */ | |
| +.cesium-credit-logoContainer, | |
| +.cesium-credit-textContainer { | |
| + display: none !important; | |
| +} | |
| + | |
| +/* Cesium widget overrides for theme */ | |
| +.cesium-viewer { | |
| + font-family: inherit; | |
| +} | |
| + | |
| +.cesium-viewer-bottom { | |
| + display: none !important; | |
| +} | |
| + | |
| +/* Ensure globe canvas fills container */ | |
| +.cesium-widget, | |
| +.cesium-widget canvas { | |
| + width: 100% !important; | |
| + height: 100% !important; | |
| +} | |
| + | |
| +/* Custom scrollbar */ | |
| +::-webkit-scrollbar { | |
| + width: 8px; | |
| + height: 8px; | |
| +} | |
| + | |
| +::-webkit-scrollbar-track { | |
| + background: transparent; | |
| +} | |
| + | |
| +::-webkit-scrollbar-thumb { | |
| + background: hsl(var(--muted-foreground) / 0.3); | |
| + border-radius: 4px; | |
| +} | |
| + | |
| +::-webkit-scrollbar-thumb:hover { | |
| + background: hsl(var(--muted-foreground) / 0.5); | |
| +} | |
| + | |
| +/* Focus visible improvements */ | |
| +:focus-visible { | |
| + outline: 2px solid hsl(var(--ring)); | |
| + outline-offset: 2px; | |
| +} | |
| + | |
| +/* Smooth transitions */ | |
| +* { | |
| + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke; | |
| + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); | |
| + transition-duration: 150ms; | |
| +} | |
| diff --git a/app/layout.tsx b/app/layout.tsx | |
| new file mode 100644 | |
| index 0000000..01f938e | |
| --- /dev/null | |
| +++ b/app/layout.tsx | |
| @@ -0,0 +1,37 @@ | |
| +import type { Metadata } from 'next'; | |
| +import { Inter } from 'next/font/google'; | |
| +import './globals.css'; | |
| +import { Providers } from './providers'; | |
| +import { Toaster } from '@/components/ui/toaster'; | |
| + | |
| +const inter = Inter({ subsets: ['latin'] }); | |
| + | |
| +export const metadata: Metadata = { | |
| + title: 'TerraView - 3D Globe Explorer', | |
| + description: | |
| + 'Explore the world with TerraView - a modern 3D globe application with search, saved places, and measurement tools.', | |
| + keywords: ['globe', 'map', '3D', 'earth', 'geography', 'cesium'], | |
| +}; | |
| + | |
| +export default function RootLayout({ | |
| + children, | |
| +}: Readonly<{ | |
| + children: React.ReactNode; | |
| +}>) { | |
| + return ( | |
| + <html lang="en" suppressHydrationWarning> | |
| + <head> | |
| + <link | |
| + rel="stylesheet" | |
| + href="https://cesium.com/downloads/cesiumjs/releases/1.122/Build/Cesium/Widgets/widgets.css" | |
| + /> | |
| + </head> | |
| + <body className={inter.className}> | |
| + <Providers> | |
| + {children} | |
| + <Toaster /> | |
| + </Providers> | |
| + </body> | |
| + </html> | |
| + ); | |
| +} | |
| diff --git a/app/page.tsx b/app/page.tsx | |
| new file mode 100644 | |
| index 0000000..82119cb | |
| --- /dev/null | |
| +++ b/app/page.tsx | |
| @@ -0,0 +1,112 @@ | |
| +'use client'; | |
| + | |
| +import { useEffect, useState, useCallback } from 'react'; | |
| +import { Header } from '@/components/Header'; | |
| +import { SidePanel } from '@/components/panels/SidePanel'; | |
| +import { GlobeWrapper } from '@/components/globe/GlobeWrapper'; | |
| +import { PinModal } from '@/components/modals/PinModal'; | |
| +import { KeyboardShortcuts } from '@/components/modals/KeyboardShortcuts'; | |
| +import { useKeyboardShortcuts } from '@/hooks'; | |
| +import { | |
| + useGlobeStore, | |
| + usePlacesStore, | |
| + useLayersStore, | |
| + useMeasureStore, | |
| +} from '@/store'; | |
| +import type { SavedPlace } from '@/types'; | |
| + | |
| +export default function Home() { | |
| + const [showShortcuts, setShowShortcuts] = useState(false); | |
| + const [showPinModal, setShowPinModal] = useState(false); | |
| + const [editingPlace, setEditingPlace] = useState<SavedPlace | null>(null); | |
| + | |
| + const { | |
| + pendingPinLocation, | |
| + setPendingPinLocation, | |
| + setActiveTab, | |
| + globeRef, | |
| + setIsMeasuring, | |
| + } = useGlobeStore(); | |
| + const { initializePlaces, places } = usePlacesStore(); | |
| + const { initializeLayers } = useLayersStore(); | |
| + const { isActive: isMeasuring, startMeasuring, stopMeasuring } = useMeasureStore(); | |
| + | |
| + useEffect(() => { | |
| + initializePlaces(); | |
| + initializeLayers(); | |
| + }, [initializePlaces, initializeLayers]); | |
| + | |
| + useEffect(() => { | |
| + if (pendingPinLocation && !isMeasuring) { | |
| + setShowPinModal(true); | |
| + } | |
| + }, [pendingPinLocation, isMeasuring]); | |
| + | |
| + const handleClosePinModal = useCallback(() => { | |
| + setShowPinModal(false); | |
| + setEditingPlace(null); | |
| + }, []); | |
| + | |
| + const handleEditPlace = useCallback( | |
| + (placeId: string) => { | |
| + const place = places.find((p) => p.id === placeId); | |
| + if (place) { | |
| + setEditingPlace(place); | |
| + setShowPinModal(true); | |
| + } | |
| + }, | |
| + [places] | |
| + ); | |
| + | |
| + const handleToggleMeasure = useCallback(() => { | |
| + if (isMeasuring) { | |
| + stopMeasuring(); | |
| + } else { | |
| + startMeasuring(); | |
| + setActiveTab('measure'); | |
| + } | |
| + setIsMeasuring(!isMeasuring); | |
| + }, [isMeasuring, startMeasuring, stopMeasuring, setActiveTab, setIsMeasuring]); | |
| + | |
| + useKeyboardShortcuts({ | |
| + onFocusSearch: () => { | |
| + const input = document.querySelector<HTMLInputElement>( | |
| + 'input[placeholder="Search places..."]' | |
| + ); | |
| + input?.focus(); | |
| + }, | |
| + onEscape: () => { | |
| + if (showShortcuts) { | |
| + setShowShortcuts(false); | |
| + } else if (showPinModal) { | |
| + handleClosePinModal(); | |
| + } | |
| + }, | |
| + onToggleLayers: () => setActiveTab('layers'), | |
| + onTogglePlaces: () => setActiveTab('places'), | |
| + onToggleMeasure: handleToggleMeasure, | |
| + onHome: () => globeRef?.resetView(), | |
| + onZoomIn: () => globeRef?.zoomIn(), | |
| + onZoomOut: () => globeRef?.zoomOut(), | |
| + onShowShortcuts: () => setShowShortcuts(true), | |
| + }); | |
| + | |
| + return ( | |
| + <main className="min-h-screen bg-background"> | |
| + <Header onShowShortcuts={() => setShowShortcuts(true)} /> | |
| + <SidePanel onEditPlace={handleEditPlace} /> | |
| + <GlobeWrapper /> | |
| + | |
| + <PinModal | |
| + isOpen={showPinModal} | |
| + onClose={handleClosePinModal} | |
| + editingPlace={editingPlace} | |
| + /> | |
| + | |
| + <KeyboardShortcuts | |
| + isOpen={showShortcuts} | |
| + onClose={() => setShowShortcuts(false)} | |
| + /> | |
| + </main> | |
| + ); | |
| +} | |
| diff --git a/app/providers.tsx b/app/providers.tsx | |
| new file mode 100644 | |
| index 0000000..d696087 | |
| --- /dev/null | |
| +++ b/app/providers.tsx | |
| @@ -0,0 +1,21 @@ | |
| +'use client'; | |
| + | |
| +import { ThemeProvider } from 'next-themes'; | |
| +import { TooltipProvider } from '@/components/ui/tooltip'; | |
| + | |
| +interface ProvidersProps { | |
| + children: React.ReactNode; | |
| +} | |
| + | |
| +export function Providers({ children }: ProvidersProps) { | |
| + return ( | |
| + <ThemeProvider | |
| + attribute="class" | |
| + defaultTheme="dark" | |
| + enableSystem | |
| + disableTransitionOnChange | |
| + > | |
| + <TooltipProvider delayDuration={300}>{children}</TooltipProvider> | |
| + </ThemeProvider> | |
| + ); | |
| +} | |
| diff --git a/components/Header.tsx b/components/Header.tsx | |
| new file mode 100644 | |
| index 0000000..3ab3b8b | |
| --- /dev/null | |
| +++ b/components/Header.tsx | |
| @@ -0,0 +1,85 @@ | |
| +'use client'; | |
| + | |
| +import { Globe2, Keyboard, Moon, Sun, PanelLeftClose, PanelLeft } from 'lucide-react'; | |
| +import { useTheme } from 'next-themes'; | |
| +import { Button } from '@/components/ui/button'; | |
| +import { | |
| + Tooltip, | |
| + TooltipContent, | |
| + TooltipTrigger, | |
| +} from '@/components/ui/tooltip'; | |
| +import { SearchBar } from '@/components/search/SearchBar'; | |
| +import { useGlobeStore } from '@/store'; | |
| + | |
| +interface HeaderProps { | |
| + onShowShortcuts: () => void; | |
| +} | |
| + | |
| +export function Header({ onShowShortcuts }: HeaderProps) { | |
| + const { theme, setTheme } = useTheme(); | |
| + const { isPanelOpen, togglePanel } = useGlobeStore(); | |
| + | |
| + const toggleTheme = () => { | |
| + setTheme(theme === 'dark' ? 'light' : 'dark'); | |
| + }; | |
| + | |
| + return ( | |
| + <header className="fixed top-0 left-0 right-0 z-40 h-14 bg-background/80 backdrop-blur-md border-b border-border"> | |
| + <div className="flex items-center justify-between h-full px-4"> | |
| + <div className="flex items-center gap-3"> | |
| + <Tooltip> | |
| + <TooltipTrigger asChild> | |
| + <Button | |
| + variant="ghost" | |
| + size="icon" | |
| + onClick={togglePanel} | |
| + className="mr-1" | |
| + > | |
| + {isPanelOpen ? ( | |
| + <PanelLeftClose className="h-5 w-5" /> | |
| + ) : ( | |
| + <PanelLeft className="h-5 w-5" /> | |
| + )} | |
| + </Button> | |
| + </TooltipTrigger> | |
| + <TooltipContent> | |
| + {isPanelOpen ? 'Hide panel' : 'Show panel'} | |
| + </TooltipContent> | |
| + </Tooltip> | |
| + | |
| + <div className="flex items-center gap-2"> | |
| + <Globe2 className="h-7 w-7 text-primary" /> | |
| + <span className="text-xl font-semibold tracking-tight"> | |
| + TerraView | |
| + </span> | |
| + </div> | |
| + </div> | |
| + | |
| + <div className="flex-1 max-w-md mx-4"> | |
| + <SearchBar /> | |
| + </div> | |
| + | |
| + <div className="flex items-center gap-2"> | |
| + <Tooltip> | |
| + <TooltipTrigger asChild> | |
| + <Button variant="ghost" size="icon" onClick={onShowShortcuts}> | |
| + <Keyboard className="h-5 w-5" /> | |
| + </Button> | |
| + </TooltipTrigger> | |
| + <TooltipContent>Keyboard shortcuts (Shift+?)</TooltipContent> | |
| + </Tooltip> | |
| + | |
| + <Tooltip> | |
| + <TooltipTrigger asChild> | |
| + <Button variant="ghost" size="icon" onClick={toggleTheme}> | |
| + <Sun className="h-5 w-5 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" /> | |
| + <Moon className="absolute h-5 w-5 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" /> | |
| + </Button> | |
| + </TooltipTrigger> | |
| + <TooltipContent>Toggle theme</TooltipContent> | |
| + </Tooltip> | |
| + </div> | |
| + </div> | |
| + </header> | |
| + ); | |
| +} | |
| diff --git a/components/LoadingScreen.tsx b/components/LoadingScreen.tsx | |
| new file mode 100644 | |
| index 0000000..a393fde | |
| --- /dev/null | |
| +++ b/components/LoadingScreen.tsx | |
| @@ -0,0 +1,23 @@ | |
| +'use client'; | |
| + | |
| +import { Globe2 } from 'lucide-react'; | |
| + | |
| +export function LoadingScreen() { | |
| + return ( | |
| + <div className="fixed inset-0 z-50 flex flex-col items-center justify-center bg-background"> | |
| + <div className="flex flex-col items-center gap-6"> | |
| + <div className="relative"> | |
| + <Globe2 className="h-16 w-16 text-primary animate-pulse-subtle" /> | |
| + <div className="absolute inset-0 rounded-full border-2 border-primary/30 animate-ping" /> | |
| + </div> | |
| + <div className="flex flex-col items-center gap-2"> | |
| + <h1 className="text-2xl font-semibold tracking-tight">TerraView</h1> | |
| + <p className="text-muted-foreground text-sm">Loading globe...</p> | |
| + </div> | |
| + <div className="w-48 h-1 bg-muted rounded-full overflow-hidden"> | |
| + <div className="h-full bg-primary rounded-full animate-pulse w-1/2" /> | |
| + </div> | |
| + </div> | |
| + </div> | |
| + ); | |
| +} | |
| diff --git a/components/globe/CameraControls.tsx b/components/globe/CameraControls.tsx | |
| new file mode 100644 | |
| index 0000000..a15216b | |
| --- /dev/null | |
| +++ b/components/globe/CameraControls.tsx | |
| @@ -0,0 +1,80 @@ | |
| +'use client'; | |
| + | |
| +import { | |
| + Home, | |
| + Plus, | |
| + Minus, | |
| + RotateCcw, | |
| + RotateCw, | |
| + ChevronUp, | |
| + ChevronDown, | |
| +} from 'lucide-react'; | |
| +import { Button } from '@/components/ui/button'; | |
| +import { | |
| + Tooltip, | |
| + TooltipContent, | |
| + TooltipTrigger, | |
| +} from '@/components/ui/tooltip'; | |
| +import { useGlobeStore } from '@/store'; | |
| + | |
| +export function CameraControls() { | |
| + const { globeRef } = useGlobeStore(); | |
| + | |
| + const controls = [ | |
| + { | |
| + icon: <Home className="h-4 w-4" />, | |
| + label: 'Home view (H)', | |
| + action: () => globeRef?.resetView(), | |
| + }, | |
| + { | |
| + icon: <Plus className="h-4 w-4" />, | |
| + label: 'Zoom in (+)', | |
| + action: () => globeRef?.zoomIn(), | |
| + }, | |
| + { | |
| + icon: <Minus className="h-4 w-4" />, | |
| + label: 'Zoom out (-)', | |
| + action: () => globeRef?.zoomOut(), | |
| + }, | |
| + { | |
| + icon: <ChevronUp className="h-4 w-4" />, | |
| + label: 'Tilt up', | |
| + action: () => globeRef?.tiltUp(), | |
| + }, | |
| + { | |
| + icon: <ChevronDown className="h-4 w-4" />, | |
| + label: 'Tilt down', | |
| + action: () => globeRef?.tiltDown(), | |
| + }, | |
| + { | |
| + icon: <RotateCcw className="h-4 w-4" />, | |
| + label: 'Rotate left', | |
| + action: () => globeRef?.rotateLeft(), | |
| + }, | |
| + { | |
| + icon: <RotateCw className="h-4 w-4" />, | |
| + label: 'Rotate right', | |
| + action: () => globeRef?.rotateRight(), | |
| + }, | |
| + ]; | |
| + | |
| + return ( | |
| + <div className="absolute right-4 top-4 flex flex-col gap-1 bg-background/80 backdrop-blur-sm rounded-lg border border-border p-1 shadow-lg"> | |
| + {controls.map((control, index) => ( | |
| + <Tooltip key={index}> | |
| + <TooltipTrigger asChild> | |
| + <Button | |
| + variant="ghost" | |
| + size="icon" | |
| + className="h-8 w-8" | |
| + onClick={control.action} | |
| + > | |
| + {control.icon} | |
| + </Button> | |
| + </TooltipTrigger> | |
| + <TooltipContent side="left">{control.label}</TooltipContent> | |
| + </Tooltip> | |
| + ))} | |
| + </div> | |
| + ); | |
| +} | |
| diff --git a/components/globe/CoordinateDisplay.tsx b/components/globe/CoordinateDisplay.tsx | |
| new file mode 100644 | |
| index 0000000..ebfe159 | |
| --- /dev/null | |
| +++ b/components/globe/CoordinateDisplay.tsx | |
| @@ -0,0 +1,47 @@ | |
| +'use client'; | |
| + | |
| +import { Navigation, Mountain } from 'lucide-react'; | |
| +import { useGlobeStore } from '@/store'; | |
| +import { | |
| + formatCoordinate, | |
| + formatAltitude, | |
| +} from '@/lib/formatting'; | |
| + | |
| +export function CoordinateDisplay() { | |
| + const { cursorPosition, cameraAltitude } = useGlobeStore(); | |
| + | |
| + return ( | |
| + <div className="absolute bottom-4 left-4 flex items-center gap-4 bg-background/80 backdrop-blur-sm rounded-lg border border-border px-4 py-2 shadow-lg"> | |
| + <div className="flex items-center gap-2"> | |
| + <Navigation className="h-4 w-4 text-muted-foreground" /> | |
| + {cursorPosition ? ( | |
| + <div className="text-xs font-mono"> | |
| + <span className="text-muted-foreground">Lat: </span> | |
| + <span> | |
| + {formatCoordinate(cursorPosition.latitude, 'lat')} | |
| + </span> | |
| + <span className="mx-2 text-muted-foreground">|</span> | |
| + <span className="text-muted-foreground">Lon: </span> | |
| + <span> | |
| + {formatCoordinate(cursorPosition.longitude, 'lon')} | |
| + </span> | |
| + </div> | |
| + ) : ( | |
| + <span className="text-xs text-muted-foreground"> | |
| + Hover over the globe | |
| + </span> | |
| + )} | |
| + </div> | |
| + | |
| + <div className="h-4 w-px bg-border" /> | |
| + | |
| + <div className="flex items-center gap-2"> | |
| + <Mountain className="h-4 w-4 text-muted-foreground" /> | |
| + <div className="text-xs font-mono"> | |
| + <span className="text-muted-foreground">Alt: </span> | |
| + <span>{formatAltitude(cameraAltitude)}</span> | |
| + </div> | |
| + </div> | |
| + </div> | |
| + ); | |
| +} | |
| diff --git a/components/globe/GlobeViewer.tsx b/components/globe/GlobeViewer.tsx | |
| new file mode 100644 | |
| index 0000000..6d781c2 | |
| --- /dev/null | |
| +++ b/components/globe/GlobeViewer.tsx | |
| @@ -0,0 +1,401 @@ | |
| +'use client'; | |
| + | |
| +import { useEffect, useRef, useCallback, useState } from 'react'; | |
| +import { | |
| + Viewer, | |
| + ScreenSpaceEventHandler, | |
| + ScreenSpaceEventType, | |
| + Cartesian3, | |
| + Cartographic, | |
| + Math as CesiumMath, | |
| + UrlTemplateImageryProvider, | |
| + Color, | |
| + Cartesian2, | |
| + Entity, | |
| + Ion, | |
| +} from 'cesium'; | |
| + | |
| +import { CameraControls } from '@/components/globe/CameraControls'; | |
| +import { CoordinateDisplay } from '@/components/globe/CoordinateDisplay'; | |
| +import { MeasurementOverlay } from '@/components/globe/MeasurementOverlay'; | |
| +import { | |
| + useGlobeStore, | |
| + useLayersStore, | |
| + useMeasureStore, | |
| + usePlacesStore, | |
| +} from '@/store'; | |
| +import { | |
| + getCesiumIonToken, | |
| + BASE_LAYER_CONFIGS, | |
| + HOME_VIEW, | |
| + CAMERA_SETTINGS, | |
| +} from '@/lib/cesium-config'; | |
| +import type { GlobeRef } from '@/types'; | |
| + | |
| +if (typeof window !== 'undefined') { | |
| + (window as Window & { CESIUM_BASE_URL?: string }).CESIUM_BASE_URL = | |
| + process.env.NEXT_PUBLIC_CESIUM_BASE_URL || | |
| + 'https://cesium.com/downloads/cesiumjs/releases/1.122/Build/Cesium'; | |
| + | |
| + const ionToken = getCesiumIonToken(); | |
| + if (ionToken) { | |
| + Ion.defaultAccessToken = ionToken; | |
| + } | |
| +} | |
| + | |
| +export function GlobeViewer() { | |
| + const containerRef = useRef<HTMLDivElement>(null); | |
| + const viewerRef = useRef<Viewer | null>(null); | |
| + const [isReady, setIsReady] = useState(false); | |
| + const entitiesRef = useRef<Map<string, Entity>>(new Map()); | |
| + | |
| + const { | |
| + setIsLoading, | |
| + setCursorPosition, | |
| + setCameraAltitude, | |
| + setGlobeRef, | |
| + isPanelOpen, | |
| + } = useGlobeStore(); | |
| + | |
| + const { baseLayer } = useLayersStore(); | |
| + const { points: measurePoints, isActive: isMeasuring, addPoint } = useMeasureStore(); | |
| + const { places } = usePlacesStore(); | |
| + | |
| + | |
| + const flyTo = useCallback( | |
| + (lat: number, lon: number, height = 50000, duration = CAMERA_SETTINGS.flyToDuration) => { | |
| + const viewer = viewerRef.current; | |
| + if (!viewer) return; | |
| + | |
| + viewer.camera.flyTo({ | |
| + destination: Cartesian3.fromDegrees(lon, lat, height), | |
| + duration, | |
| + }); | |
| + }, | |
| + [] | |
| + ); | |
| + | |
| + const zoomIn = useCallback(() => { | |
| + const viewer = viewerRef.current; | |
| + if (!viewer) return; | |
| + | |
| + const camera = viewer.camera; | |
| + const currentHeight = camera.positionCartographic.height; | |
| + const newHeight = currentHeight * (1 - CAMERA_SETTINGS.zoomFactor); | |
| + camera.zoomIn(currentHeight - newHeight); | |
| + }, []); | |
| + | |
| + const zoomOut = useCallback(() => { | |
| + const viewer = viewerRef.current; | |
| + if (!viewer) return; | |
| + | |
| + const camera = viewer.camera; | |
| + const currentHeight = camera.positionCartographic.height; | |
| + const newHeight = currentHeight * (1 + CAMERA_SETTINGS.zoomFactor); | |
| + camera.zoomOut(newHeight - currentHeight); | |
| + }, []); | |
| + | |
| + const tiltUp = useCallback(() => { | |
| + const viewer = viewerRef.current; | |
| + if (!viewer) return; | |
| + | |
| + viewer.camera.lookUp(CesiumMath.toRadians(CAMERA_SETTINGS.tiltIncrement)); | |
| + }, []); | |
| + | |
| + const tiltDown = useCallback(() => { | |
| + const viewer = viewerRef.current; | |
| + if (!viewer) return; | |
| + | |
| + viewer.camera.lookDown(CesiumMath.toRadians(CAMERA_SETTINGS.tiltIncrement)); | |
| + }, []); | |
| + | |
| + const rotateLeft = useCallback(() => { | |
| + const viewer = viewerRef.current; | |
| + if (!viewer) return; | |
| + | |
| + viewer.camera.rotateLeft(CesiumMath.toRadians(CAMERA_SETTINGS.rotateIncrement)); | |
| + }, []); | |
| + | |
| + const rotateRight = useCallback(() => { | |
| + const viewer = viewerRef.current; | |
| + if (!viewer) return; | |
| + | |
| + viewer.camera.rotateRight(CesiumMath.toRadians(CAMERA_SETTINGS.rotateIncrement)); | |
| + }, []); | |
| + | |
| + const resetView = useCallback(() => { | |
| + const viewer = viewerRef.current; | |
| + if (!viewer) return; | |
| + | |
| + viewer.camera.flyTo({ | |
| + destination: Cartesian3.fromDegrees( | |
| + HOME_VIEW.destination.longitude, | |
| + HOME_VIEW.destination.latitude, | |
| + HOME_VIEW.destination.height | |
| + ), | |
| + duration: CAMERA_SETTINGS.flyToDuration, | |
| + }); | |
| + }, []); | |
| + | |
| + const getCameraPosition = useCallback(() => { | |
| + const viewer = viewerRef.current; | |
| + if (!viewer) return null; | |
| + | |
| + const cartographic = viewer.camera.positionCartographic; | |
| + return { | |
| + latitude: CesiumMath.toDegrees(cartographic.latitude), | |
| + longitude: CesiumMath.toDegrees(cartographic.longitude), | |
| + height: cartographic.height, | |
| + heading: CesiumMath.toDegrees(viewer.camera.heading), | |
| + pitch: CesiumMath.toDegrees(viewer.camera.pitch), | |
| + roll: CesiumMath.toDegrees(viewer.camera.roll), | |
| + }; | |
| + }, []); | |
| + | |
| + useEffect(() => { | |
| + const globeRef: GlobeRef = { | |
| + flyTo, | |
| + zoomIn, | |
| + zoomOut, | |
| + tiltUp, | |
| + tiltDown, | |
| + rotateLeft, | |
| + rotateRight, | |
| + resetView, | |
| + getCameraPosition, | |
| + }; | |
| + setGlobeRef(globeRef); | |
| + | |
| + return () => { | |
| + setGlobeRef(null); | |
| + }; | |
| + }, [ | |
| + flyTo, | |
| + zoomIn, | |
| + zoomOut, | |
| + tiltUp, | |
| + tiltDown, | |
| + rotateLeft, | |
| + rotateRight, | |
| + resetView, | |
| + getCameraPosition, | |
| + setGlobeRef, | |
| + ]); | |
| + | |
| + // Initialize viewer | |
| + useEffect(() => { | |
| + if (!containerRef.current || viewerRef.current) return; | |
| + | |
| + const viewer = new Viewer(containerRef.current, { | |
| + timeline: false, | |
| + animation: false, | |
| + baseLayerPicker: false, | |
| + geocoder: false, | |
| + homeButton: false, | |
| + sceneModePicker: false, | |
| + navigationHelpButton: false, | |
| + fullscreenButton: false, | |
| + vrButton: false, | |
| + infoBox: false, | |
| + selectionIndicator: false, | |
| + }); | |
| + | |
| + // Set up imagery layer | |
| + const config = BASE_LAYER_CONFIGS[baseLayer]; | |
| + const imageryProvider = new UrlTemplateImageryProvider({ | |
| + url: config.url, | |
| + credit: config.attribution, | |
| + }); | |
| + viewer.imageryLayers.removeAll(); | |
| + viewer.imageryLayers.addImageryProvider(imageryProvider); | |
| + | |
| + viewer.scene.globe.enableLighting = false; | |
| + viewer.scene.screenSpaceCameraController.enableCollisionDetection = true; | |
| + | |
| + // Mouse move handler | |
| + const handler = new ScreenSpaceEventHandler(viewer.scene.canvas); | |
| + | |
| + handler.setInputAction((movement: { endPosition: Cartesian2 }) => { | |
| + const cartesian = viewer.camera.pickEllipsoid( | |
| + movement.endPosition, | |
| + viewer.scene.globe.ellipsoid | |
| + ); | |
| + | |
| + if (cartesian) { | |
| + const cartographic = Cartographic.fromCartesian(cartesian); | |
| + setCursorPosition({ | |
| + latitude: CesiumMath.toDegrees(cartographic.latitude), | |
| + longitude: CesiumMath.toDegrees(cartographic.longitude), | |
| + height: cartographic.height, | |
| + }); | |
| + } else { | |
| + setCursorPosition(null); | |
| + } | |
| + }, ScreenSpaceEventType.MOUSE_MOVE); | |
| + | |
| + // Click handler | |
| + handler.setInputAction((click: { position: Cartesian2 }) => { | |
| + const cartesian = viewer.camera.pickEllipsoid( | |
| + click.position, | |
| + viewer.scene.globe.ellipsoid | |
| + ); | |
| + | |
| + if (cartesian) { | |
| + const cartographic = Cartographic.fromCartesian(cartesian); | |
| + const latitude = CesiumMath.toDegrees(cartographic.latitude); | |
| + const longitude = CesiumMath.toDegrees(cartographic.longitude); | |
| + | |
| + const measureStore = useMeasureStore.getState(); | |
| + if (measureStore.isActive) { | |
| + measureStore.addPoint({ latitude, longitude }); | |
| + } else { | |
| + useGlobeStore.getState().setPendingPinLocation({ latitude, longitude }); | |
| + } | |
| + } | |
| + }, ScreenSpaceEventType.LEFT_CLICK); | |
| + | |
| + // Camera change handler | |
| + viewer.camera.changed.addEventListener(() => { | |
| + const height = viewer.camera.positionCartographic.height; | |
| + setCameraAltitude(height); | |
| + }); | |
| + | |
| + viewerRef.current = viewer; | |
| + setIsLoading(false); | |
| + setIsReady(true); | |
| + | |
| + return () => { | |
| + handler.destroy(); | |
| + if (viewerRef.current && !viewerRef.current.isDestroyed()) { | |
| + viewerRef.current.destroy(); | |
| + } | |
| + viewerRef.current = null; | |
| + }; | |
| + // eslint-disable-next-line react-hooks/exhaustive-deps | |
| + }, []); | |
| + | |
| + // Update base layer when it changes | |
| + useEffect(() => { | |
| + const viewer = viewerRef.current; | |
| + if (!viewer || !isReady) return; | |
| + | |
| + const config = BASE_LAYER_CONFIGS[baseLayer]; | |
| + const newProvider = new UrlTemplateImageryProvider({ | |
| + url: config.url, | |
| + credit: config.attribution, | |
| + }); | |
| + | |
| + viewer.imageryLayers.removeAll(); | |
| + viewer.imageryLayers.addImageryProvider(newProvider); | |
| + }, [baseLayer, isReady]); | |
| + | |
| + // Update place markers | |
| + useEffect(() => { | |
| + const viewer = viewerRef.current; | |
| + if (!viewer || !isReady) return; | |
| + | |
| + // Remove old place entities | |
| + entitiesRef.current.forEach((entity, id) => { | |
| + if (!places.find(p => p.id === id)) { | |
| + viewer.entities.remove(entity); | |
| + entitiesRef.current.delete(id); | |
| + } | |
| + }); | |
| + | |
| + // Add/update place entities | |
| + places.forEach((place) => { | |
| + let entity = entitiesRef.current.get(place.id); | |
| + | |
| + if (!entity) { | |
| + entity = viewer.entities.add({ | |
| + id: `place-${place.id}`, | |
| + position: Cartesian3.fromDegrees( | |
| + place.coordinates.longitude, | |
| + place.coordinates.latitude | |
| + ), | |
| + point: { | |
| + pixelSize: 12, | |
| + color: Color.fromCssColorString('#3b82f6'), | |
| + outlineColor: Color.WHITE, | |
| + outlineWidth: 2, | |
| + }, | |
| + name: place.name, | |
| + description: place.note, | |
| + }); | |
| + entitiesRef.current.set(place.id, entity); | |
| + } | |
| + }); | |
| + }, [places, isReady]); | |
| + | |
| + // Update measurement points and lines | |
| + useEffect(() => { | |
| + const viewer = viewerRef.current; | |
| + if (!viewer || !isReady) return; | |
| + | |
| + // Remove old measurement entities | |
| + const toRemove: Entity[] = []; | |
| + viewer.entities.values.forEach((entity) => { | |
| + if (entity.id?.toString().startsWith('measure-')) { | |
| + toRemove.push(entity); | |
| + } | |
| + }); | |
| + toRemove.forEach((entity) => viewer.entities.remove(entity)); | |
| + | |
| + // Add measurement point entities | |
| + measurePoints.forEach((point, index) => { | |
| + viewer.entities.add({ | |
| + id: `measure-point-${point.id}`, | |
| + position: Cartesian3.fromDegrees( | |
| + point.coordinates.longitude, | |
| + point.coordinates.latitude | |
| + ), | |
| + point: { | |
| + pixelSize: 10, | |
| + color: Color.fromCssColorString('#ef4444'), | |
| + outlineColor: Color.WHITE, | |
| + outlineWidth: 2, | |
| + }, | |
| + }); | |
| + }); | |
| + | |
| + // Add measurement line | |
| + if (measurePoints.length >= 2) { | |
| + const positions = measurePoints.map((point) => | |
| + Cartesian3.fromDegrees( | |
| + point.coordinates.longitude, | |
| + point.coordinates.latitude | |
| + ) | |
| + ); | |
| + | |
| + viewer.entities.add({ | |
| + id: 'measure-line', | |
| + polyline: { | |
| + positions: positions, | |
| + width: 3, | |
| + material: Color.fromCssColorString('#ef4444'), | |
| + clampToGround: true, | |
| + }, | |
| + }); | |
| + } | |
| + }, [measurePoints, isReady]); | |
| + | |
| + return ( | |
| + <div className="fixed inset-0 pt-14"> | |
| + <div | |
| + className={`absolute inset-0 transition-all duration-300 ${ | |
| + isPanelOpen ? 'left-80' : 'left-0' | |
| + }`} | |
| + > | |
| + <div ref={containerRef} className="w-full h-full" /> | |
| + | |
| + {isReady && ( | |
| + <> | |
| + <CoordinateDisplay /> | |
| + <CameraControls /> | |
| + {isMeasuring && <MeasurementOverlay />} | |
| + </> | |
| + )} | |
| + </div> | |
| + </div> | |
| + ); | |
| +} | |
| diff --git a/components/globe/GlobeWrapper.tsx b/components/globe/GlobeWrapper.tsx | |
| new file mode 100644 | |
| index 0000000..391eaca | |
| --- /dev/null | |
| +++ b/components/globe/GlobeWrapper.tsx | |
| @@ -0,0 +1,20 @@ | |
| +'use client'; | |
| + | |
| +import dynamic from 'next/dynamic'; | |
| +import { LoadingScreen } from '@/components/LoadingScreen'; | |
| + | |
| +const GlobeViewer = dynamic( | |
| + () => import('@/components/globe/GlobeViewer').then((mod) => mod.GlobeViewer), | |
| + { | |
| + ssr: false, | |
| + loading: () => <LoadingScreen />, | |
| + } | |
| +); | |
| + | |
| +export function GlobeWrapper() { | |
| + return ( | |
| + <div className="w-full h-full"> | |
| + <GlobeViewer /> | |
| + </div> | |
| + ); | |
| +} | |
| diff --git a/components/globe/MeasurementOverlay.tsx b/components/globe/MeasurementOverlay.tsx | |
| new file mode 100644 | |
| index 0000000..5c9496b | |
| --- /dev/null | |
| +++ b/components/globe/MeasurementOverlay.tsx | |
| @@ -0,0 +1,36 @@ | |
| +'use client'; | |
| + | |
| +import { Ruler } from 'lucide-react'; | |
| +import { useMeasureStore } from '@/store'; | |
| +import { formatDistance } from '@/lib/formatting'; | |
| + | |
| +export function MeasurementOverlay() { | |
| + const { points, totalDistance } = useMeasureStore(); | |
| + | |
| + return ( | |
| + <div className="absolute top-4 left-1/2 -translate-x-1/2 bg-red-500/90 text-white rounded-lg px-4 py-2 shadow-lg flex items-center gap-3"> | |
| + <div className="flex items-center gap-2"> | |
| + <Ruler className="h-4 w-4" /> | |
| + <span className="text-sm font-medium">Measuring Mode</span> | |
| + </div> | |
| + | |
| + {points.length > 0 && ( | |
| + <> | |
| + <div className="h-4 w-px bg-white/30" /> | |
| + <div className="text-sm"> | |
| + <span className="opacity-80">{points.length} point{points.length !== 1 ? 's' : ''}</span> | |
| + {totalDistance > 0 && ( | |
| + <> | |
| + <span className="mx-2 opacity-50">•</span> | |
| + <span className="font-medium">{formatDistance(totalDistance)}</span> | |
| + </> | |
| + )} | |
| + </div> | |
| + </> | |
| + )} | |
| + | |
| + <div className="h-4 w-px bg-white/30" /> | |
| + <span className="text-xs opacity-80">Click to add points</span> | |
| + </div> | |
| + ); | |
| +} | |
| diff --git a/components/modals/KeyboardShortcuts.tsx b/components/modals/KeyboardShortcuts.tsx | |
| new file mode 100644 | |
| index 0000000..c8e6245 | |
| --- /dev/null | |
| +++ b/components/modals/KeyboardShortcuts.tsx | |
| @@ -0,0 +1,72 @@ | |
| +'use client'; | |
| + | |
| +import { Keyboard } from 'lucide-react'; | |
| +import { | |
| + Dialog, | |
| + DialogContent, | |
| + DialogHeader, | |
| + DialogTitle, | |
| + DialogDescription, | |
| +} from '@/components/ui/dialog'; | |
| +import { KEYBOARD_SHORTCUTS } from '@/hooks'; | |
| + | |
| +interface KeyboardShortcutsProps { | |
| + isOpen: boolean; | |
| + onClose: () => void; | |
| +} | |
| + | |
| +export function KeyboardShortcuts({ isOpen, onClose }: KeyboardShortcutsProps) { | |
| + const formatKey = (shortcut: (typeof KEYBOARD_SHORTCUTS)[0]) => { | |
| + const parts: string[] = []; | |
| + if (shortcut.ctrl) parts.push('Ctrl'); | |
| + if (shortcut.shift) parts.push('Shift'); | |
| + if (shortcut.alt) parts.push('Alt'); | |
| + parts.push(shortcut.key); | |
| + return parts; | |
| + }; | |
| + | |
| + return ( | |
| + <Dialog open={isOpen} onOpenChange={(open) => !open && onClose()}> | |
| + <DialogContent className="sm:max-w-md"> | |
| + <DialogHeader> | |
| + <DialogTitle className="flex items-center gap-2"> | |
| + <Keyboard className="h-5 w-5" /> | |
| + Keyboard Shortcuts | |
| + </DialogTitle> | |
| + <DialogDescription> | |
| + Use these shortcuts to navigate TerraView faster. | |
| + </DialogDescription> | |
| + </DialogHeader> | |
| + | |
| + <div className="py-4"> | |
| + <div className="space-y-2"> | |
| + {KEYBOARD_SHORTCUTS.map((shortcut, index) => ( | |
| + <div | |
| + key={index} | |
| + className="flex items-center justify-between py-2 px-3 rounded-lg bg-muted/50" | |
| + > | |
| + <span className="text-sm">{shortcut.description}</span> | |
| + <div className="flex gap-1"> | |
| + {formatKey(shortcut).map((key, keyIndex) => ( | |
| + <kbd | |
| + key={keyIndex} | |
| + className="px-2 py-1 text-xs font-mono bg-background border rounded shadow-sm" | |
| + > | |
| + {key} | |
| + </kbd> | |
| + ))} | |
| + </div> | |
| + </div> | |
| + ))} | |
| + </div> | |
| + </div> | |
| + | |
| + <div className="pt-2 border-t"> | |
| + <p className="text-xs text-muted-foreground text-center"> | |
| + Press <kbd className="px-1 py-0.5 text-xs font-mono bg-muted border rounded">Esc</kbd> to close this dialog | |
| + </p> | |
| + </div> | |
| + </DialogContent> | |
| + </Dialog> | |
| + ); | |
| +} | |
| diff --git a/components/modals/PinModal.tsx b/components/modals/PinModal.tsx | |
| new file mode 100644 | |
| index 0000000..1dffdf4 | |
| --- /dev/null | |
| +++ b/components/modals/PinModal.tsx | |
| @@ -0,0 +1,165 @@ | |
| +'use client'; | |
| + | |
| +import { useState, useEffect } from 'react'; | |
| +import { MapPin, Copy } from 'lucide-react'; | |
| +import { | |
| + Dialog, | |
| + DialogContent, | |
| + DialogHeader, | |
| + DialogTitle, | |
| + DialogDescription, | |
| + DialogFooter, | |
| +} from '@/components/ui/dialog'; | |
| +import { Button } from '@/components/ui/button'; | |
| +import { Input } from '@/components/ui/input'; | |
| +import { Textarea } from '@/components/ui/textarea'; | |
| +import { Label } from '@/components/ui/label'; | |
| +import { toast } from '@/components/ui/use-toast'; | |
| +import { usePlacesStore, useGlobeStore } from '@/store'; | |
| +import { formatCoordinatesFull, formatCoordinatesShort } from '@/lib/formatting'; | |
| +import type { SavedPlace } from '@/types'; | |
| + | |
| +interface PinModalProps { | |
| + isOpen: boolean; | |
| + onClose: () => void; | |
| + editingPlace?: SavedPlace | null; | |
| +} | |
| + | |
| +export function PinModal({ isOpen, onClose, editingPlace }: PinModalProps) { | |
| + const [name, setName] = useState(''); | |
| + const [note, setNote] = useState(''); | |
| + | |
| + const { addPlace, updatePlace } = usePlacesStore(); | |
| + const { pendingPinLocation, setPendingPinLocation } = useGlobeStore(); | |
| + | |
| + const location = editingPlace?.coordinates || pendingPinLocation; | |
| + const isEditing = Boolean(editingPlace); | |
| + | |
| + useEffect(() => { | |
| + if (isOpen) { | |
| + if (editingPlace) { | |
| + setName(editingPlace.name); | |
| + setNote(editingPlace.note); | |
| + } else { | |
| + setName(''); | |
| + setNote(''); | |
| + } | |
| + } | |
| + }, [isOpen, editingPlace]); | |
| + | |
| + const handleSave = () => { | |
| + if (!name.trim()) { | |
| + toast({ | |
| + title: 'Name required', | |
| + description: 'Please enter a name for this place.', | |
| + variant: 'destructive', | |
| + }); | |
| + return; | |
| + } | |
| + | |
| + if (isEditing && editingPlace) { | |
| + updatePlace(editingPlace.id, { | |
| + name: name.trim(), | |
| + note: note.trim(), | |
| + }); | |
| + toast({ | |
| + title: 'Place updated', | |
| + description: `"${name}" has been updated.`, | |
| + variant: 'success', | |
| + }); | |
| + } else if (location) { | |
| + addPlace(name.trim(), note.trim(), location); | |
| + toast({ | |
| + title: 'Place saved', | |
| + description: `"${name}" has been added to your places.`, | |
| + variant: 'success', | |
| + }); | |
| + setPendingPinLocation(null); | |
| + } | |
| + | |
| + onClose(); | |
| + }; | |
| + | |
| + const handleCopyCoordinates = () => { | |
| + if (location) { | |
| + const coords = formatCoordinatesShort(location); | |
| + navigator.clipboard.writeText(coords); | |
| + toast({ | |
| + title: 'Copied', | |
| + description: 'Coordinates copied to clipboard.', | |
| + }); | |
| + } | |
| + }; | |
| + | |
| + const handleClose = () => { | |
| + if (!isEditing) { | |
| + setPendingPinLocation(null); | |
| + } | |
| + onClose(); | |
| + }; | |
| + | |
| + if (!location) return null; | |
| + | |
| + return ( | |
| + <Dialog open={isOpen} onOpenChange={(open) => !open && handleClose()}> | |
| + <DialogContent className="sm:max-w-md"> | |
| + <DialogHeader> | |
| + <DialogTitle className="flex items-center gap-2"> | |
| + <MapPin className="h-5 w-5 text-primary" /> | |
| + {isEditing ? 'Edit Place' : 'Save Place'} | |
| + </DialogTitle> | |
| + <DialogDescription> | |
| + {isEditing | |
| + ? 'Update the details for this saved place.' | |
| + : 'Save this location to your places list.'} | |
| + </DialogDescription> | |
| + </DialogHeader> | |
| + | |
| + <div className="space-y-4 py-4"> | |
| + <div className="flex items-center gap-2 p-3 rounded-lg bg-muted"> | |
| + <div className="flex-1"> | |
| + <p className="text-xs text-muted-foreground mb-1">Coordinates</p> | |
| + <p className="text-sm font-mono"> | |
| + {formatCoordinatesFull(location)} | |
| + </p> | |
| + </div> | |
| + <Button variant="ghost" size="icon" onClick={handleCopyCoordinates}> | |
| + <Copy className="h-4 w-4" /> | |
| + </Button> | |
| + </div> | |
| + | |
| + <div className="space-y-2"> | |
| + <Label htmlFor="name">Name</Label> | |
| + <Input | |
| + id="name" | |
| + placeholder="Enter a name for this place" | |
| + value={name} | |
| + onChange={(e) => setName(e.target.value)} | |
| + autoFocus | |
| + /> | |
| + </div> | |
| + | |
| + <div className="space-y-2"> | |
| + <Label htmlFor="note">Note (optional)</Label> | |
| + <Textarea | |
| + id="note" | |
| + placeholder="Add a note about this place..." | |
| + value={note} | |
| + onChange={(e) => setNote(e.target.value)} | |
| + rows={3} | |
| + /> | |
| + </div> | |
| + </div> | |
| + | |
| + <DialogFooter> | |
| + <Button variant="outline" onClick={handleClose}> | |
| + Cancel | |
| + </Button> | |
| + <Button onClick={handleSave}> | |
| + {isEditing ? 'Update' : 'Save Place'} | |
| + </Button> | |
| + </DialogFooter> | |
| + </DialogContent> | |
| + </Dialog> | |
| + ); | |
| +} | |
| diff --git a/components/panels/LayersPanel.tsx b/components/panels/LayersPanel.tsx | |
| new file mode 100644 | |
| index 0000000..c7545b8 | |
| --- /dev/null | |
| +++ b/components/panels/LayersPanel.tsx | |
| @@ -0,0 +1,139 @@ | |
| +'use client'; | |
| + | |
| +import { Map, Satellite, Mountain, Globe, Tag, Route } from 'lucide-react'; | |
| +import { ScrollArea } from '@/components/ui/scroll-area'; | |
| +import { Switch } from '@/components/ui/switch'; | |
| +import { Label } from '@/components/ui/label'; | |
| +import { useLayersStore } from '@/store'; | |
| +import { cn } from '@/lib/utils'; | |
| +import type { BaseLayerType } from '@/types'; | |
| + | |
| +const BASE_LAYERS: { | |
| + id: BaseLayerType; | |
| + name: string; | |
| + description: string; | |
| + icon: React.ReactNode; | |
| +}[] = [ | |
| + { | |
| + id: 'osm', | |
| + name: 'OpenStreetMap', | |
| + description: 'Street map with roads and labels', | |
| + icon: <Map className="h-5 w-5" />, | |
| + }, | |
| + { | |
| + id: 'arcgis', | |
| + name: 'Satellite', | |
| + description: 'High-resolution satellite imagery', | |
| + icon: <Satellite className="h-5 w-5" />, | |
| + }, | |
| + { | |
| + id: 'stamen', | |
| + name: 'Terrain', | |
| + description: 'Terrain with shaded relief', | |
| + icon: <Mountain className="h-5 w-5" />, | |
| + }, | |
| +]; | |
| + | |
| +const OVERLAY_LAYERS = [ | |
| + { | |
| + id: 'borders' as const, | |
| + name: 'Country Borders', | |
| + icon: <Globe className="h-4 w-4" />, | |
| + }, | |
| + { | |
| + id: 'labels' as const, | |
| + name: 'Place Labels', | |
| + icon: <Tag className="h-4 w-4" />, | |
| + }, | |
| + { | |
| + id: 'roads' as const, | |
| + name: 'Major Roads', | |
| + icon: <Route className="h-4 w-4" />, | |
| + }, | |
| +]; | |
| + | |
| +export function LayersPanel() { | |
| + const { baseLayer, setBaseLayer, overlays, toggleOverlay } = useLayersStore(); | |
| + | |
| + return ( | |
| + <ScrollArea className="h-full"> | |
| + <div className="p-4 space-y-6"> | |
| + <div className="space-y-3"> | |
| + <h3 className="text-sm font-semibold text-muted-foreground uppercase tracking-wider"> | |
| + Base Layer | |
| + </h3> | |
| + <div className="space-y-2"> | |
| + {BASE_LAYERS.map((layer) => ( | |
| + <button | |
| + key={layer.id} | |
| + onClick={() => setBaseLayer(layer.id)} | |
| + className={cn( | |
| + 'w-full flex items-center gap-3 p-3 rounded-lg border transition-all', | |
| + 'hover:bg-accent/50', | |
| + baseLayer === layer.id | |
| + ? 'border-primary bg-primary/10' | |
| + : 'border-border' | |
| + )} | |
| + > | |
| + <div | |
| + className={cn( | |
| + 'p-2 rounded-md', | |
| + baseLayer === layer.id | |
| + ? 'bg-primary text-primary-foreground' | |
| + : 'bg-muted text-muted-foreground' | |
| + )} | |
| + > | |
| + {layer.icon} | |
| + </div> | |
| + <div className="flex-1 text-left"> | |
| + <p className="text-sm font-medium">{layer.name}</p> | |
| + <p className="text-xs text-muted-foreground"> | |
| + {layer.description} | |
| + </p> | |
| + </div> | |
| + {baseLayer === layer.id && ( | |
| + <div className="w-2 h-2 rounded-full bg-primary" /> | |
| + )} | |
| + </button> | |
| + ))} | |
| + </div> | |
| + </div> | |
| + | |
| + <div className="space-y-3"> | |
| + <h3 className="text-sm font-semibold text-muted-foreground uppercase tracking-wider"> | |
| + Overlays | |
| + </h3> | |
| + <div className="space-y-3"> | |
| + {OVERLAY_LAYERS.map((layer) => ( | |
| + <div | |
| + key={layer.id} | |
| + className="flex items-center justify-between p-3 rounded-lg bg-muted/30" | |
| + > | |
| + <div className="flex items-center gap-3"> | |
| + <div className="text-muted-foreground">{layer.icon}</div> | |
| + <Label | |
| + htmlFor={layer.id} | |
| + className="text-sm font-medium cursor-pointer" | |
| + > | |
| + {layer.name} | |
| + </Label> | |
| + </div> | |
| + <Switch | |
| + id={layer.id} | |
| + checked={overlays[layer.id]} | |
| + onCheckedChange={() => toggleOverlay(layer.id)} | |
| + /> | |
| + </div> | |
| + ))} | |
| + </div> | |
| + </div> | |
| + | |
| + <div className="pt-4 border-t border-border"> | |
| + <p className="text-xs text-muted-foreground"> | |
| + Layer changes are saved automatically and will persist across sessions. | |
| + </p> | |
| + </div> | |
| + </div> | |
| + </ScrollArea> | |
| + ); | |
| +} | |
| diff --git a/components/panels/MeasurePanel.tsx b/components/panels/MeasurePanel.tsx | |
| new file mode 100644 | |
| index 0000000..55c108b | |
| --- /dev/null | |
| +++ b/components/panels/MeasurePanel.tsx | |
| @@ -0,0 +1,132 @@ | |
| +'use client'; | |
| + | |
| +import { Ruler, Trash2, Play, Square, Undo, MapPin } from 'lucide-react'; | |
| +import { ScrollArea } from '@/components/ui/scroll-area'; | |
| +import { Button } from '@/components/ui/button'; | |
| +import { useMeasureStore } from '@/store'; | |
| +import { formatDistance, formatCoordinatesShort } from '@/lib/formatting'; | |
| + | |
| +export function MeasurePanel() { | |
| + const { | |
| + points, | |
| + isActive, | |
| + totalDistance, | |
| + startMeasuring, | |
| + stopMeasuring, | |
| + clearMeasurement, | |
| + removeLastPoint, | |
| + } = useMeasureStore(); | |
| + | |
| + return ( | |
| + <div className="flex flex-col h-full"> | |
| + <div className="p-4 border-b border-border"> | |
| + <h3 className="text-sm font-semibold text-muted-foreground uppercase tracking-wider"> | |
| + Distance Measurement | |
| + </h3> | |
| + <p className="text-xs text-muted-foreground mt-1"> | |
| + {isActive | |
| + ? 'Click on the globe to add measurement points' | |
| + : 'Start measuring to begin'} | |
| + </p> | |
| + </div> | |
| + | |
| + <div className="p-4 space-y-4"> | |
| + <div className="flex gap-2"> | |
| + {isActive ? ( | |
| + <Button | |
| + onClick={stopMeasuring} | |
| + variant="secondary" | |
| + className="flex-1" | |
| + > | |
| + <Square className="h-4 w-4 mr-2" /> | |
| + Stop Measuring | |
| + </Button> | |
| + ) : ( | |
| + <Button onClick={startMeasuring} className="flex-1"> | |
| + <Play className="h-4 w-4 mr-2" /> | |
| + Start Measuring | |
| + </Button> | |
| + )} | |
| + </div> | |
| + | |
| + {points.length > 0 && ( | |
| + <div className="flex gap-2"> | |
| + <Button | |
| + variant="outline" | |
| + size="sm" | |
| + onClick={removeLastPoint} | |
| + disabled={points.length === 0} | |
| + className="flex-1" | |
| + > | |
| + <Undo className="h-4 w-4 mr-2" /> | |
| + Undo | |
| + </Button> | |
| + <Button | |
| + variant="outline" | |
| + size="sm" | |
| + onClick={clearMeasurement} | |
| + className="flex-1" | |
| + > | |
| + <Trash2 className="h-4 w-4 mr-2" /> | |
| + Clear | |
| + </Button> | |
| + </div> | |
| + )} | |
| + | |
| + {totalDistance > 0 && ( | |
| + <div className="p-4 rounded-lg bg-primary/10 border border-primary/20"> | |
| + <div className="flex items-center gap-2 mb-2"> | |
| + <Ruler className="h-5 w-5 text-primary" /> | |
| + <span className="text-sm font-medium">Total Distance</span> | |
| + </div> | |
| + <p className="text-2xl font-bold text-primary"> | |
| + {formatDistance(totalDistance)} | |
| + </p> | |
| + </div> | |
| + )} | |
| + </div> | |
| + | |
| + <ScrollArea className="flex-1"> | |
| + {points.length === 0 ? ( | |
| + <div className="flex flex-col items-center justify-center h-40 p-6 text-center"> | |
| + <Ruler className="h-10 w-10 text-muted-foreground/50 mb-3" /> | |
| + <p className="text-xs text-muted-foreground"> | |
| + {isActive | |
| + ? 'Click on the globe to add your first point' | |
| + : 'Start measuring to add points'} | |
| + </p> | |
| + </div> | |
| + ) : ( | |
| + <div className="p-4 space-y-2"> | |
| + <h4 className="text-xs font-semibold text-muted-foreground uppercase"> | |
| + Measurement Points ({points.length}) | |
| + </h4> | |
| + {points.map((point, index) => ( | |
| + <div | |
| + key={point.id} | |
| + className="flex items-center gap-3 p-2 rounded-md bg-muted/30" | |
| + > | |
| + <div className="flex items-center justify-center w-6 h-6 rounded-full bg-primary text-primary-foreground text-xs font-bold"> | |
| + {index + 1} | |
| + </div> | |
| + <div className="flex-1"> | |
| + <p className="text-xs font-mono"> | |
| + {formatCoordinatesShort(point.coordinates)} | |
| + </p> | |
| + </div> | |
| + <MapPin className="h-3 w-3 text-muted-foreground" /> | |
| + </div> | |
| + ))} | |
| + </div> | |
| + )} | |
| + </ScrollArea> | |
| + | |
| + <div className="p-4 border-t border-border"> | |
| + <p className="text-xs text-muted-foreground"> | |
| + Distances are calculated using the Haversine formula (great-circle | |
| + distance). | |
| + </p> | |
| + </div> | |
| + </div> | |
| + ); | |
| +} | |
| diff --git a/components/panels/PlacesPanel.tsx b/components/panels/PlacesPanel.tsx | |
| new file mode 100644 | |
| index 0000000..52acc18 | |
| --- /dev/null | |
| +++ b/components/panels/PlacesPanel.tsx | |
| @@ -0,0 +1,245 @@ | |
| +'use client'; | |
| + | |
| +import { useRef } from 'react'; | |
| +import { | |
| + MapPin, | |
| + Navigation, | |
| + Trash2, | |
| + Edit2, | |
| + Download, | |
| + Upload, | |
| + MapPinOff, | |
| +} from 'lucide-react'; | |
| +import { ScrollArea } from '@/components/ui/scroll-area'; | |
| +import { Button } from '@/components/ui/button'; | |
| +import { | |
| + DropdownMenu, | |
| + DropdownMenuContent, | |
| + DropdownMenuItem, | |
| + DropdownMenuTrigger, | |
| +} from '@/components/ui/dropdown-menu'; | |
| +import { | |
| + Tooltip, | |
| + TooltipContent, | |
| + TooltipTrigger, | |
| +} from '@/components/ui/tooltip'; | |
| +import { toast } from '@/components/ui/use-toast'; | |
| +import { usePlacesStore, useGlobeStore } from '@/store'; | |
| +import { exportPlaces, downloadJson } from '@/lib/storage'; | |
| +import { formatCoordinatesShort, formatDate } from '@/lib/formatting'; | |
| +import { cn } from '@/lib/utils'; | |
| + | |
| +interface PlacesPanelProps { | |
| + onEditPlace?: (placeId: string) => void; | |
| +} | |
| + | |
| +export function PlacesPanel({ onEditPlace }: PlacesPanelProps) { | |
| + const { places, deletePlace, importPlacesFromJson } = usePlacesStore(); | |
| + const { globeRef } = useGlobeStore(); | |
| + const fileInputRef = useRef<HTMLInputElement>(null); | |
| + | |
| + const handleFlyTo = (latitude: number, longitude: number) => { | |
| + if (globeRef) { | |
| + globeRef.flyTo(latitude, longitude, 10000); | |
| + } | |
| + }; | |
| + | |
| + const handleDelete = (id: string, name: string) => { | |
| + deletePlace(id); | |
| + toast({ | |
| + title: 'Place deleted', | |
| + description: `"${name}" has been removed from your saved places.`, | |
| + }); | |
| + }; | |
| + | |
| + const handleExport = () => { | |
| + if (places.length === 0) { | |
| + toast({ | |
| + title: 'Nothing to export', | |
| + description: 'You have no saved places to export.', | |
| + variant: 'destructive', | |
| + }); | |
| + return; | |
| + } | |
| + | |
| + const json = exportPlaces(places); | |
| + downloadJson(json, `terraview-places-${Date.now()}.json`); | |
| + toast({ | |
| + title: 'Exported successfully', | |
| + description: `${places.length} places exported to JSON file.`, | |
| + variant: 'success', | |
| + }); | |
| + }; | |
| + | |
| + const handleImportClick = () => { | |
| + fileInputRef.current?.click(); | |
| + }; | |
| + | |
| + const handleImport = (event: React.ChangeEvent<HTMLInputElement>) => { | |
| + const file = event.target.files?.[0]; | |
| + if (!file) return; | |
| + | |
| + const reader = new FileReader(); | |
| + reader.onload = (e) => { | |
| + const content = e.target?.result as string; | |
| + const success = importPlacesFromJson(content); | |
| + | |
| + if (success) { | |
| + toast({ | |
| + title: 'Imported successfully', | |
| + description: 'Your places have been imported.', | |
| + variant: 'success', | |
| + }); | |
| + } else { | |
| + toast({ | |
| + title: 'Import failed', | |
| + description: 'Invalid file format. Please use a valid TerraView export file.', | |
| + variant: 'destructive', | |
| + }); | |
| + } | |
| + }; | |
| + reader.readAsText(file); | |
| + | |
| + if (fileInputRef.current) { | |
| + fileInputRef.current.value = ''; | |
| + } | |
| + }; | |
| + | |
| + return ( | |
| + <div className="flex flex-col h-full"> | |
| + <div className="p-4 border-b border-border"> | |
| + <div className="flex items-center justify-between"> | |
| + <h3 className="text-sm font-semibold text-muted-foreground uppercase tracking-wider"> | |
| + Saved Places ({places.length}) | |
| + </h3> | |
| + <div className="flex gap-1"> | |
| + <Tooltip> | |
| + <TooltipTrigger asChild> | |
| + <Button variant="ghost" size="icon" onClick={handleImportClick}> | |
| + <Upload className="h-4 w-4" /> | |
| + </Button> | |
| + </TooltipTrigger> | |
| + <TooltipContent>Import places</TooltipContent> | |
| + </Tooltip> | |
| + <Tooltip> | |
| + <TooltipTrigger asChild> | |
| + <Button variant="ghost" size="icon" onClick={handleExport}> | |
| + <Download className="h-4 w-4" /> | |
| + </Button> | |
| + </TooltipTrigger> | |
| + <TooltipContent>Export places</TooltipContent> | |
| + </Tooltip> | |
| + </div> | |
| + </div> | |
| + <p className="text-xs text-muted-foreground mt-1"> | |
| + Click on the globe to drop a pin | |
| + </p> | |
| + <input | |
| + ref={fileInputRef} | |
| + type="file" | |
| + accept=".json" | |
| + onChange={handleImport} | |
| + className="hidden" | |
| + /> | |
| + </div> | |
| + | |
| + <ScrollArea className="flex-1"> | |
| + {places.length === 0 ? ( | |
| + <div className="flex flex-col items-center justify-center h-64 p-6 text-center"> | |
| + <MapPinOff className="h-12 w-12 text-muted-foreground/50 mb-4" /> | |
| + <h4 className="text-sm font-medium mb-1">No saved places yet</h4> | |
| + <p className="text-xs text-muted-foreground"> | |
| + Click anywhere on the globe to drop a pin and save your favorite | |
| + locations. | |
| + </p> | |
| + </div> | |
| + ) : ( | |
| + <div className="p-2 space-y-1"> | |
| + {places.map((place) => ( | |
| + <div | |
| + key={place.id} | |
| + className={cn( | |
| + 'group flex items-start gap-3 p-3 rounded-lg', | |
| + 'hover:bg-accent/50 transition-colors cursor-pointer' | |
| + )} | |
| + onClick={() => | |
| + handleFlyTo( | |
| + place.coordinates.latitude, | |
| + place.coordinates.longitude | |
| + ) | |
| + } | |
| + > | |
| + <div className="p-1.5 rounded-md bg-primary/10 text-primary shrink-0"> | |
| + <MapPin className="h-4 w-4" /> | |
| + </div> | |
| + <div className="flex-1 min-w-0"> | |
| + <p className="text-sm font-medium truncate">{place.name}</p> | |
| + {place.note && ( | |
| + <p className="text-xs text-muted-foreground truncate"> | |
| + {place.note} | |
| + </p> | |
| + )} | |
| + <p className="text-xs text-muted-foreground/70 mt-1"> | |
| + {formatCoordinatesShort(place.coordinates)} | |
| + </p> | |
| + <p className="text-xs text-muted-foreground/50"> | |
| + {formatDate(place.createdAt)} | |
| + </p> | |
| + </div> | |
| + <div className="flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity"> | |
| + <Tooltip> | |
| + <TooltipTrigger asChild> | |
| + <Button | |
| + variant="ghost" | |
| + size="icon" | |
| + className="h-7 w-7" | |
| + onClick={(e) => { | |
| + e.stopPropagation(); | |
| + handleFlyTo( | |
| + place.coordinates.latitude, | |
| + place.coordinates.longitude | |
| + ); | |
| + }} | |
| + > | |
| + <Navigation className="h-3.5 w-3.5" /> | |
| + </Button> | |
| + </TooltipTrigger> | |
| + <TooltipContent>Fly to location</TooltipContent> | |
| + </Tooltip> | |
| + | |
| + <DropdownMenu> | |
| + <DropdownMenuTrigger asChild> | |
| + <Button | |
| + variant="ghost" | |
| + size="icon" | |
| + className="h-7 w-7" | |
| + onClick={(e) => e.stopPropagation()} | |
| + > | |
| + <Edit2 className="h-3.5 w-3.5" /> | |
| + </Button> | |
| + </DropdownMenuTrigger> | |
| + <DropdownMenuContent align="end"> | |
| + <DropdownMenuItem | |
| + onClick={() => onEditPlace?.(place.id)} | |
| + > | |
| + <Edit2 className="h-4 w-4 mr-2" /> | |
| + Edit | |
| + </DropdownMenuItem> | |
| + <DropdownMenuItem | |
| + className="text-destructive" | |
| + onClick={() => handleDelete(place.id, place.name)} | |
| + > | |
| + <Trash2 className="h-4 w-4 mr-2" /> | |
| + Delete | |
| + </DropdownMenuItem> | |
| + </DropdownMenuContent> | |
| + </DropdownMenu> | |
| + </div> | |
| + </div> | |
| + ))} | |
| + </div> | |
| + )} | |
| + </ScrollArea> | |
| + </div> | |
| + ); | |
| +} | |
| diff --git a/components/panels/SidePanel.tsx b/components/panels/SidePanel.tsx | |
| new file mode 100644 | |
| index 0000000..201bfde | |
| --- /dev/null | |
| +++ b/components/panels/SidePanel.tsx | |
| @@ -0,0 +1,60 @@ | |
| +'use client'; | |
| + | |
| +import { Layers, MapPin, Ruler } from 'lucide-react'; | |
| +import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; | |
| +import { LayersPanel } from '@/components/panels/LayersPanel'; | |
| +import { PlacesPanel } from '@/components/panels/PlacesPanel'; | |
| +import { MeasurePanel } from '@/components/panels/MeasurePanel'; | |
| +import { useGlobeStore } from '@/store'; | |
| +import { cn } from '@/lib/utils'; | |
| +import type { PanelTab } from '@/types'; | |
| + | |
| +interface SidePanelProps { | |
| + onEditPlace?: (placeId: string) => void; | |
| +} | |
| + | |
| +export function SidePanel({ onEditPlace }: SidePanelProps) { | |
| + const { activeTab, setActiveTab, isPanelOpen } = useGlobeStore(); | |
| + | |
| + return ( | |
| + <div | |
| + className={cn( | |
| + 'fixed left-0 top-14 bottom-0 z-30 w-80 bg-background/95 backdrop-blur-sm border-r border-border transition-transform duration-300 ease-in-out', | |
| + isPanelOpen ? 'translate-x-0' : '-translate-x-full' | |
| + )} | |
| + > | |
| + <Tabs | |
| + value={activeTab} | |
| + onValueChange={(value) => setActiveTab(value as PanelTab)} | |
| + className="flex flex-col h-full" | |
| + > | |
| + <TabsList className="grid w-full grid-cols-3 rounded-none border-b bg-muted/50"> | |
| + <TabsTrigger value="layers" className="gap-2 rounded-none"> | |
| + <Layers className="h-4 w-4" /> | |
| + <span className="hidden sm:inline">Layers</span> | |
| + </TabsTrigger> | |
| + <TabsTrigger value="places" className="gap-2 rounded-none"> | |
| + <MapPin className="h-4 w-4" /> | |
| + <span className="hidden sm:inline">Places</span> | |
| + </TabsTrigger> | |
| + <TabsTrigger value="measure" className="gap-2 rounded-none"> | |
| + <Ruler className="h-4 w-4" /> | |
| + <span className="hidden sm:inline">Measure</span> | |
| + </TabsTrigger> | |
| + </TabsList> | |
| + | |
| + <div className="flex-1 overflow-hidden"> | |
| + <TabsContent value="layers" className="h-full m-0"> | |
| + <LayersPanel /> | |
| + </TabsContent> | |
| + <TabsContent value="places" className="h-full m-0"> | |
| + <PlacesPanel onEditPlace={onEditPlace} /> | |
| + </TabsContent> | |
| + <TabsContent value="measure" className="h-full m-0"> | |
| + <MeasurePanel /> | |
| + </TabsContent> | |
| + </div> | |
| + </Tabs> | |
| + </div> | |
| + ); | |
| +} | |
| diff --git a/components/search/SearchBar.tsx b/components/search/SearchBar.tsx | |
| new file mode 100644 | |
| index 0000000..0fce59e | |
| --- /dev/null | |
| +++ b/components/search/SearchBar.tsx | |
| @@ -0,0 +1,180 @@ | |
| +'use client'; | |
| + | |
| +import { useState, useEffect, useRef, useCallback } from 'react'; | |
| +import { Search, Loader2, X } from 'lucide-react'; | |
| +import { Input } from '@/components/ui/input'; | |
| +import { Button } from '@/components/ui/button'; | |
| +import { SearchResults } from '@/components/search/SearchResults'; | |
| +import { GeocodingClient } from '@/lib/geocoding'; | |
| +import { useDebounce } from '@/hooks'; | |
| +import { useGlobeStore } from '@/store'; | |
| +import type { GeocodingResult } from '@/types'; | |
| + | |
| +const geocodingClient = new GeocodingClient(); | |
| + | |
| +export function SearchBar() { | |
| + const [query, setQuery] = useState(''); | |
| + const [results, setResults] = useState<GeocodingResult[]>([]); | |
| + const [isLoading, setIsLoading] = useState(false); | |
| + const [isOpen, setIsOpen] = useState(false); | |
| + const [selectedIndex, setSelectedIndex] = useState(-1); | |
| + const [error, setError] = useState<string | null>(null); | |
| + | |
| + const inputRef = useRef<HTMLInputElement>(null); | |
| + const containerRef = useRef<HTMLDivElement>(null); | |
| + | |
| + const debouncedQuery = useDebounce(query, 400); | |
| + const { globeRef } = useGlobeStore(); | |
| + | |
| + useEffect(() => { | |
| + const handleSearch = async () => { | |
| + if (!debouncedQuery.trim()) { | |
| + setResults([]); | |
| + setIsOpen(false); | |
| + return; | |
| + } | |
| + | |
| + setIsLoading(true); | |
| + setError(null); | |
| + | |
| + try { | |
| + const searchResults = await geocodingClient.search(debouncedQuery); | |
| + setResults(searchResults); | |
| + setIsOpen(true); | |
| + setSelectedIndex(-1); | |
| + } catch (err) { | |
| + if (err instanceof Error && err.name !== 'AbortError') { | |
| + setError('Search failed. Please try again.'); | |
| + setResults([]); | |
| + } | |
| + } finally { | |
| + setIsLoading(false); | |
| + } | |
| + }; | |
| + | |
| + handleSearch(); | |
| + }, [debouncedQuery]); | |
| + | |
| + useEffect(() => { | |
| + const handleClickOutside = (event: MouseEvent) => { | |
| + if ( | |
| + containerRef.current && | |
| + !containerRef.current.contains(event.target as Node) | |
| + ) { | |
| + setIsOpen(false); | |
| + } | |
| + }; | |
| + | |
| + document.addEventListener('mousedown', handleClickOutside); | |
| + return () => document.removeEventListener('mousedown', handleClickOutside); | |
| + }, []); | |
| + | |
| + const handleSelect = useCallback( | |
| + (result: GeocodingResult) => { | |
| + if (globeRef) { | |
| + globeRef.flyTo( | |
| + result.coordinates.latitude, | |
| + result.coordinates.longitude, | |
| + 50000 | |
| + ); | |
| + } | |
| + setQuery(result.name); | |
| + setIsOpen(false); | |
| + }, | |
| + [globeRef] | |
| + ); | |
| + | |
| + const handleKeyDown = (event: React.KeyboardEvent) => { | |
| + if (!isOpen || results.length === 0) { | |
| + if (event.key === 'Escape') { | |
| + inputRef.current?.blur(); | |
| + } | |
| + return; | |
| + } | |
| + | |
| + switch (event.key) { | |
| + case 'ArrowDown': | |
| + event.preventDefault(); | |
| + setSelectedIndex((prev) => | |
| + prev < results.length - 1 ? prev + 1 : prev | |
| + ); | |
| + break; | |
| + case 'ArrowUp': | |
| + event.preventDefault(); | |
| + setSelectedIndex((prev) => (prev > 0 ? prev - 1 : prev)); | |
| + break; | |
| + case 'Enter': | |
| + event.preventDefault(); | |
| + if (selectedIndex >= 0 && selectedIndex < results.length) { | |
| + handleSelect(results[selectedIndex]); | |
| + } | |
| + break; | |
| + case 'Escape': | |
| + setIsOpen(false); | |
| + inputRef.current?.blur(); | |
| + break; | |
| + } | |
| + }; | |
| + | |
| + const handleClear = () => { | |
| + setQuery(''); | |
| + setResults([]); | |
| + setIsOpen(false); | |
| + inputRef.current?.focus(); | |
| + }; | |
| + | |
| + const focusInput = () => { | |
| + inputRef.current?.focus(); | |
| + }; | |
| + | |
| + useEffect(() => { | |
| + (window as Window & { focusSearchInput?: () => void }).focusSearchInput = | |
| + focusInput; | |
| + return () => { | |
| + delete (window as Window & { focusSearchInput?: () => void }) | |
| + .focusSearchInput; | |
| + }; | |
| + }, []); | |
| + | |
| + return ( | |
| + <div ref={containerRef} className="relative w-full"> | |
| + <div className="relative"> | |
| + <Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" /> | |
| + <Input | |
| + ref={inputRef} | |
| + type="text" | |
| + placeholder="Search places..." | |
| + value={query} | |
| + onChange={(e) => setQuery(e.target.value)} | |
| + onKeyDown={handleKeyDown} | |
| + onFocus={() => results.length > 0 && setIsOpen(true)} | |
| + className="pl-9 pr-9 bg-muted/50 border-muted" | |
| + /> | |
| + {isLoading && ( | |
| + <Loader2 className="absolute right-3 top-1/2 -translate-y-1/2 h-4 w-4 animate-spin text-muted-foreground" /> | |
| + )} | |
| + {!isLoading && query && ( | |
| + <Button | |
| + variant="ghost" | |
| + size="icon" | |
| + className="absolute right-1 top-1/2 -translate-y-1/2 h-7 w-7" | |
| + onClick={handleClear} | |
| + > | |
| + <X className="h-3 w-3" /> | |
| + </Button> | |
| + )} | |
| + </div> | |
| + | |
| + {isOpen && ( | |
| + <SearchResults | |
| + results={results} | |
| + selectedIndex={selectedIndex} | |
| + onSelect={handleSelect} | |
| + isLoading={isLoading} | |
| + error={error} | |
| + query={debouncedQuery} | |
| + /> | |
| + )} | |
| + </div> | |
| + ); | |
| +} | |
| diff --git a/components/search/SearchResults.tsx b/components/search/SearchResults.tsx | |
| new file mode 100644 | |
| index 0000000..f921241 | |
| --- /dev/null | |
| +++ b/components/search/SearchResults.tsx | |
| @@ -0,0 +1,89 @@ | |
| +'use client'; | |
| + | |
| +import { MapPin, Loader2, AlertCircle, Search } from 'lucide-react'; | |
| +import { ScrollArea } from '@/components/ui/scroll-area'; | |
| +import { cn } from '@/lib/utils'; | |
| +import type { GeocodingResult } from '@/types'; | |
| + | |
| +interface SearchResultsProps { | |
| + results: GeocodingResult[]; | |
| + selectedIndex: number; | |
| + onSelect: (result: GeocodingResult) => void; | |
| + isLoading: boolean; | |
| + error: string | null; | |
| + query: string; | |
| +} | |
| + | |
| +export function SearchResults({ | |
| + results, | |
| + selectedIndex, | |
| + onSelect, | |
| + isLoading, | |
| + error, | |
| + query, | |
| +}: SearchResultsProps) { | |
| + if (isLoading) { | |
| + return ( | |
| + <div className="absolute top-full left-0 right-0 mt-1 bg-popover border rounded-md shadow-lg p-4"> | |
| + <div className="flex items-center justify-center gap-2 text-muted-foreground"> | |
| + <Loader2 className="h-4 w-4 animate-spin" /> | |
| + <span className="text-sm">Searching...</span> | |
| + </div> | |
| + </div> | |
| + ); | |
| + } | |
| + | |
| + if (error) { | |
| + return ( | |
| + <div className="absolute top-full left-0 right-0 mt-1 bg-popover border rounded-md shadow-lg p-4"> | |
| + <div className="flex items-center justify-center gap-2 text-destructive"> | |
| + <AlertCircle className="h-4 w-4" /> | |
| + <span className="text-sm">{error}</span> | |
| + </div> | |
| + </div> | |
| + ); | |
| + } | |
| + | |
| + if (results.length === 0 && query.trim()) { | |
| + return ( | |
| + <div className="absolute top-full left-0 right-0 mt-1 bg-popover border rounded-md shadow-lg p-4"> | |
| + <div className="flex flex-col items-center justify-center gap-2 text-muted-foreground"> | |
| + <Search className="h-8 w-8 opacity-50" /> | |
| + <span className="text-sm">No results found for "{query}"</span> | |
| + </div> | |
| + </div> | |
| + ); | |
| + } | |
| + | |
| + if (results.length === 0) { | |
| + return null; | |
| + } | |
| + | |
| + return ( | |
| + <div className="absolute top-full left-0 right-0 mt-1 bg-popover border rounded-md shadow-lg overflow-hidden z-50"> | |
| + <ScrollArea className="max-h-72"> | |
| + <div className="p-1"> | |
| + {results.map((result, index) => ( | |
| + <button | |
| + key={result.id} | |
| + className={cn( | |
| + 'w-full flex items-start gap-3 p-2 rounded-sm text-left transition-colors', | |
| + 'hover:bg-accent hover:text-accent-foreground', | |
| + selectedIndex === index && 'bg-accent text-accent-foreground' | |
| + )} | |
| + onClick={() => onSelect(result)} | |
| + > | |
| + <MapPin className="h-4 w-4 mt-0.5 shrink-0 text-muted-foreground" /> | |
| + <div className="flex-1 min-w-0"> | |
| + <p className="text-sm font-medium truncate">{result.name}</p> | |
| + <p className="text-xs text-muted-foreground truncate"> | |
| + {result.displayName} | |
| + </p> | |
| + </div> | |
| + </button> | |
| + ))} | |
| + </div> | |
| + </ScrollArea> | |
| + </div> | |
| + ); | |
| +} | |
| diff --git a/components/ui/button.tsx b/components/ui/button.tsx | |
| new file mode 100644 | |
| index 0000000..b4d045e | |
| --- /dev/null | |
| +++ b/components/ui/button.tsx | |
| @@ -0,0 +1,55 @@ | |
| +import * as React from 'react'; | |
| +import { Slot } from '@radix-ui/react-slot'; | |
| +import { cva, type VariantProps } from 'class-variance-authority'; | |
| +import { cn } from '@/lib/utils'; | |
| + | |
| +const buttonVariants = cva( | |
| + 'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50', | |
| + { | |
| + variants: { | |
| + variant: { | |
| + default: 'bg-primary text-primary-foreground hover:bg-primary/90', | |
| + destructive: | |
| + 'bg-destructive text-destructive-foreground hover:bg-destructive/90', | |
| + outline: | |
| + 'border border-input bg-background hover:bg-accent hover:text-accent-foreground', | |
| + secondary: | |
| + 'bg-secondary text-secondary-foreground hover:bg-secondary/80', | |
| + ghost: 'hover:bg-accent hover:text-accent-foreground', | |
| + link: 'text-primary underline-offset-4 hover:underline', | |
| + }, | |
| + size: { | |
| + default: 'h-10 px-4 py-2', | |
| + sm: 'h-9 rounded-md px-3', | |
| + lg: 'h-11 rounded-md px-8', | |
| + icon: 'h-10 w-10', | |
| + }, | |
| + }, | |
| + defaultVariants: { | |
| + variant: 'default', | |
| + size: 'default', | |
| + }, | |
| + } | |
| +); | |
| + | |
| +export interface ButtonProps | |
| + extends React.ButtonHTMLAttributes<HTMLButtonElement>, | |
| + VariantProps<typeof buttonVariants> { | |
| + asChild?: boolean; | |
| +} | |
| + | |
| +const Button = React.forwardRef<HTMLButtonElement, ButtonProps>( | |
| + ({ className, variant, size, asChild = false, ...props }, ref) => { | |
| + const Comp = asChild ? Slot : 'button'; | |
| + return ( | |
| + <Comp | |
| + className={cn(buttonVariants({ variant, size, className }))} | |
| + ref={ref} | |
| + {...props} | |
| + /> | |
| + ); | |
| + } | |
| +); | |
| +Button.displayName = 'Button'; | |
| + | |
| +export { Button, buttonVariants }; | |
| diff --git a/components/ui/dialog.tsx b/components/ui/dialog.tsx | |
| new file mode 100644 | |
| index 0000000..29110c3 | |
| --- /dev/null | |
| +++ b/components/ui/dialog.tsx | |
| @@ -0,0 +1,121 @@ | |
| +'use client'; | |
| + | |
| +import * as React from 'react'; | |
| +import * as DialogPrimitive from '@radix-ui/react-dialog'; | |
| +import { X } from 'lucide-react'; | |
| +import { cn } from '@/lib/utils'; | |
| + | |
| +const Dialog = DialogPrimitive.Root; | |
| + | |
| +const DialogTrigger = DialogPrimitive.Trigger; | |
| + | |
| +const DialogPortal = DialogPrimitive.Portal; | |
| + | |
| +const DialogClose = DialogPrimitive.Close; | |
| + | |
| +const DialogOverlay = React.forwardRef< | |
| + React.ElementRef<typeof DialogPrimitive.Overlay>, | |
| + React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay> | |
| +>(({ className, ...props }, ref) => ( | |
| + <DialogPrimitive.Overlay | |
| + ref={ref} | |
| + className={cn( | |
| + 'fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0', | |
| + className | |
| + )} | |
| + {...props} | |
| + /> | |
| +)); | |
| +DialogOverlay.displayName = DialogPrimitive.Overlay.displayName; | |
| + | |
| +const DialogContent = React.forwardRef< | |
| + React.ElementRef<typeof DialogPrimitive.Content>, | |
| + React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> | |
| +>(({ className, children, ...props }, ref) => ( | |
| + <DialogPortal> | |
| + <DialogOverlay /> | |
| + <DialogPrimitive.Content | |
| + ref={ref} | |
| + className={cn( | |
| + 'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 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-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg', | |
| + className | |
| + )} | |
| + {...props} | |
| + > | |
| + {children} | |
| + <DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground"> | |
| + <X className="h-4 w-4" /> | |
| + <span className="sr-only">Close</span> | |
| + </DialogPrimitive.Close> | |
| + </DialogPrimitive.Content> | |
| + </DialogPortal> | |
| +)); | |
| +DialogContent.displayName = DialogPrimitive.Content.displayName; | |
| + | |
| +const DialogHeader = ({ | |
| + className, | |
| + ...props | |
| +}: React.HTMLAttributes<HTMLDivElement>) => ( | |
| + <div | |
| + className={cn( | |
| + 'flex flex-col space-y-1.5 text-center sm:text-left', | |
| + className | |
| + )} | |
| + {...props} | |
| + /> | |
| +); | |
| +DialogHeader.displayName = 'DialogHeader'; | |
| + | |
| +const DialogFooter = ({ | |
| + className, | |
| + ...props | |
| +}: React.HTMLAttributes<HTMLDivElement>) => ( | |
| + <div | |
| + className={cn( | |
| + 'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2', | |
| + className | |
| + )} | |
| + {...props} | |
| + /> | |
| +); | |
| +DialogFooter.displayName = 'DialogFooter'; | |
| + | |
| +const DialogTitle = React.forwardRef< | |
| + React.ElementRef<typeof DialogPrimitive.Title>, | |
| + React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title> | |
| +>(({ className, ...props }, ref) => ( | |
| + <DialogPrimitive.Title | |
| + ref={ref} | |
| + className={cn( | |
| + 'text-lg font-semibold leading-none tracking-tight', | |
| + className | |
| + )} | |
| + {...props} | |
| + /> | |
| +)); | |
| +DialogTitle.displayName = DialogPrimitive.Title.displayName; | |
| + | |
| +const DialogDescription = React.forwardRef< | |
| + React.ElementRef<typeof DialogPrimitive.Description>, | |
| + React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description> | |
| +>(({ className, ...props }, ref) => ( | |
| + <DialogPrimitive.Description | |
| + ref={ref} | |
| + className={cn('text-sm text-muted-foreground', className)} | |
| + {...props} | |
| + /> | |
| +)); | |
| +DialogDescription.displayName = DialogPrimitive.Description.displayName; | |
| + | |
| +export { | |
| + Dialog, | |
| + DialogPortal, | |
| + DialogOverlay, | |
| + DialogClose, | |
| + DialogTrigger, | |
| + DialogContent, | |
| + DialogHeader, | |
| + DialogFooter, | |
| + DialogTitle, | |
| + DialogDescription, | |
| +}; | |
| diff --git a/components/ui/dropdown-menu.tsx b/components/ui/dropdown-menu.tsx | |
| new file mode 100644 | |
| index 0000000..3d4f3a8 | |
| --- /dev/null | |
| +++ b/components/ui/dropdown-menu.tsx | |
| @@ -0,0 +1,199 @@ | |
| +'use client'; | |
| + | |
| +import * as React from 'react'; | |
| +import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu'; | |
| +import { Check, ChevronRight, Circle } from 'lucide-react'; | |
| +import { cn } from '@/lib/utils'; | |
| + | |
| +const DropdownMenu = DropdownMenuPrimitive.Root; | |
| + | |
| +const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger; | |
| + | |
| +const DropdownMenuGroup = DropdownMenuPrimitive.Group; | |
| + | |
| +const DropdownMenuPortal = DropdownMenuPrimitive.Portal; | |
| + | |
| +const DropdownMenuSub = DropdownMenuPrimitive.Sub; | |
| + | |
| +const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup; | |
| + | |
| +const DropdownMenuSubTrigger = React.forwardRef< | |
| + React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>, | |
| + React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & { | |
| + inset?: boolean; | |
| + } | |
| +>(({ className, inset, children, ...props }, ref) => ( | |
| + <DropdownMenuPrimitive.SubTrigger | |
| + ref={ref} | |
| + className={cn( | |
| + 'flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent', | |
| + inset && 'pl-8', | |
| + className | |
| + )} | |
| + {...props} | |
| + > | |
| + {children} | |
| + <ChevronRight className="ml-auto h-4 w-4" /> | |
| + </DropdownMenuPrimitive.SubTrigger> | |
| +)); | |
| +DropdownMenuSubTrigger.displayName = | |
| + DropdownMenuPrimitive.SubTrigger.displayName; | |
| + | |
| +const DropdownMenuSubContent = React.forwardRef< | |
| + React.ElementRef<typeof DropdownMenuPrimitive.SubContent>, | |
| + React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent> | |
| +>(({ className, ...props }, ref) => ( | |
| + <DropdownMenuPrimitive.SubContent | |
| + ref={ref} | |
| + className={cn( | |
| + 'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg 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', | |
| + className | |
| + )} | |
| + {...props} | |
| + /> | |
| +)); | |
| +DropdownMenuSubContent.displayName = | |
| + DropdownMenuPrimitive.SubContent.displayName; | |
| + | |
| +const DropdownMenuContent = React.forwardRef< | |
| + React.ElementRef<typeof DropdownMenuPrimitive.Content>, | |
| + React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content> | |
| +>(({ className, sideOffset = 4, ...props }, ref) => ( | |
| + <DropdownMenuPrimitive.Portal> | |
| + <DropdownMenuPrimitive.Content | |
| + ref={ref} | |
| + sideOffset={sideOffset} | |
| + className={cn( | |
| + 'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground 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', | |
| + className | |
| + )} | |
| + {...props} | |
| + /> | |
| + </DropdownMenuPrimitive.Portal> | |
| +)); | |
| +DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName; | |
| + | |
| +const DropdownMenuItem = React.forwardRef< | |
| + React.ElementRef<typeof DropdownMenuPrimitive.Item>, | |
| + React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & { | |
| + inset?: boolean; | |
| + } | |
| +>(({ className, inset, ...props }, ref) => ( | |
| + <DropdownMenuPrimitive.Item | |
| + ref={ref} | |
| + className={cn( | |
| + 'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50', | |
| + inset && 'pl-8', | |
| + className | |
| + )} | |
| + {...props} | |
| + /> | |
| +)); | |
| +DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName; | |
| + | |
| +const DropdownMenuCheckboxItem = React.forwardRef< | |
| + React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>, | |
| + React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem> | |
| +>(({ className, children, checked, ...props }, ref) => ( | |
| + <DropdownMenuPrimitive.CheckboxItem | |
| + ref={ref} | |
| + className={cn( | |
| + 'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50', | |
| + className | |
| + )} | |
| + checked={checked} | |
| + {...props} | |
| + > | |
| + <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center"> | |
| + <DropdownMenuPrimitive.ItemIndicator> | |
| + <Check className="h-4 w-4" /> | |
| + </DropdownMenuPrimitive.ItemIndicator> | |
| + </span> | |
| + {children} | |
| + </DropdownMenuPrimitive.CheckboxItem> | |
| +)); | |
| +DropdownMenuCheckboxItem.displayName = | |
| + DropdownMenuPrimitive.CheckboxItem.displayName; | |
| + | |
| +const DropdownMenuRadioItem = React.forwardRef< | |
| + React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>, | |
| + React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem> | |
| +>(({ className, children, ...props }, ref) => ( | |
| + <DropdownMenuPrimitive.RadioItem | |
| + ref={ref} | |
| + className={cn( | |
| + 'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50', | |
| + className | |
| + )} | |
| + {...props} | |
| + > | |
| + <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center"> | |
| + <DropdownMenuPrimitive.ItemIndicator> | |
| + <Circle className="h-2 w-2 fill-current" /> | |
| + </DropdownMenuPrimitive.ItemIndicator> | |
| + </span> | |
| + {children} | |
| + </DropdownMenuPrimitive.RadioItem> | |
| +)); | |
| +DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName; | |
| + | |
| +const DropdownMenuLabel = React.forwardRef< | |
| + React.ElementRef<typeof DropdownMenuPrimitive.Label>, | |
| + React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & { | |
| + inset?: boolean; | |
| + } | |
| +>(({ className, inset, ...props }, ref) => ( | |
| + <DropdownMenuPrimitive.Label | |
| + ref={ref} | |
| + className={cn( | |
| + 'px-2 py-1.5 text-sm font-semibold', | |
| + inset && 'pl-8', | |
| + className | |
| + )} | |
| + {...props} | |
| + /> | |
| +)); | |
| +DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName; | |
| + | |
| +const DropdownMenuSeparator = React.forwardRef< | |
| + React.ElementRef<typeof DropdownMenuPrimitive.Separator>, | |
| + React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator> | |
| +>(({ className, ...props }, ref) => ( | |
| + <DropdownMenuPrimitive.Separator | |
| + ref={ref} | |
| + className={cn('-mx-1 my-1 h-px bg-muted', className)} | |
| + {...props} | |
| + /> | |
| +)); | |
| +DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName; | |
| + | |
| +const DropdownMenuShortcut = ({ | |
| + className, | |
| + ...props | |
| +}: React.HTMLAttributes<HTMLSpanElement>) => { | |
| + return ( | |
| + <span | |
| + className={cn('ml-auto text-xs tracking-widest opacity-60', className)} | |
| + {...props} | |
| + /> | |
| + ); | |
| +}; | |
| +DropdownMenuShortcut.displayName = 'DropdownMenuShortcut'; | |
| + | |
| +export { | |
| + DropdownMenu, | |
| + DropdownMenuTrigger, | |
| + DropdownMenuContent, | |
| + DropdownMenuItem, | |
| + DropdownMenuCheckboxItem, | |
| + DropdownMenuRadioItem, | |
| + DropdownMenuLabel, | |
| + DropdownMenuSeparator, | |
| + DropdownMenuShortcut, | |
| + DropdownMenuGroup, | |
| + DropdownMenuPortal, | |
| + DropdownMenuSub, | |
| + DropdownMenuSubContent, | |
| + DropdownMenuSubTrigger, | |
| + DropdownMenuRadioGroup, | |
| +}; | |
| diff --git a/components/ui/input.tsx b/components/ui/input.tsx | |
| new file mode 100644 | |
| index 0000000..b651d6b | |
| --- /dev/null | |
| +++ b/components/ui/input.tsx | |
| @@ -0,0 +1,24 @@ | |
| +import * as React from 'react'; | |
| +import { cn } from '@/lib/utils'; | |
| + | |
| +export interface InputProps | |
| + extends React.InputHTMLAttributes<HTMLInputElement> {} | |
| + | |
| +const Input = React.forwardRef<HTMLInputElement, InputProps>( | |
| + ({ className, type, ...props }, ref) => { | |
| + return ( | |
| + <input | |
| + type={type} | |
| + className={cn( | |
| + 'flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50', | |
| + className | |
| + )} | |
| + ref={ref} | |
| + {...props} | |
| + /> | |
| + ); | |
| + } | |
| +); | |
| +Input.displayName = 'Input'; | |
| + | |
| +export { Input }; | |
| diff --git a/components/ui/label.tsx b/components/ui/label.tsx | |
| new file mode 100644 | |
| index 0000000..b4b4d82 | |
| --- /dev/null | |
| +++ b/components/ui/label.tsx | |
| @@ -0,0 +1,23 @@ | |
| +import * as React from 'react'; | |
| +import * as LabelPrimitive from '@radix-ui/react-label'; | |
| +import { cva, type VariantProps } from 'class-variance-authority'; | |
| +import { cn } from '@/lib/utils'; | |
| + | |
| +const labelVariants = cva( | |
| + 'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70' | |
| +); | |
| + | |
| +const Label = React.forwardRef< | |
| + React.ElementRef<typeof LabelPrimitive.Root>, | |
| + React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> & | |
| + VariantProps<typeof labelVariants> | |
| +>(({ className, ...props }, ref) => ( | |
| + <LabelPrimitive.Root | |
| + ref={ref} | |
| + className={cn(labelVariants(), className)} | |
| + {...props} | |
| + /> | |
| +)); | |
| +Label.displayName = LabelPrimitive.Root.displayName; | |
| + | |
| +export { Label }; | |
| diff --git a/components/ui/scroll-area.tsx b/components/ui/scroll-area.tsx | |
| new file mode 100644 | |
| index 0000000..d8baa0d | |
| --- /dev/null | |
| +++ b/components/ui/scroll-area.tsx | |
| @@ -0,0 +1,47 @@ | |
| +'use client'; | |
| + | |
| +import * as React from 'react'; | |
| +import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area'; | |
| +import { cn } from '@/lib/utils'; | |
| + | |
| +const ScrollArea = React.forwardRef< | |
| + React.ElementRef<typeof ScrollAreaPrimitive.Root>, | |
| + React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root> | |
| +>(({ className, children, ...props }, ref) => ( | |
| + <ScrollAreaPrimitive.Root | |
| + ref={ref} | |
| + className={cn('relative overflow-hidden', className)} | |
| + {...props} | |
| + > | |
| + <ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit]"> | |
| + {children} | |
| + </ScrollAreaPrimitive.Viewport> | |
| + <ScrollBar /> | |
| + <ScrollAreaPrimitive.Corner /> | |
| + </ScrollAreaPrimitive.Root> | |
| +)); | |
| +ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName; | |
| + | |
| +const ScrollBar = React.forwardRef< | |
| + React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>, | |
| + React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar> | |
| +>(({ className, orientation = 'vertical', ...props }, ref) => ( | |
| + <ScrollAreaPrimitive.ScrollAreaScrollbar | |
| + ref={ref} | |
| + orientation={orientation} | |
| + className={cn( | |
| + 'flex touch-none select-none transition-colors', | |
| + orientation === 'vertical' && | |
| + 'h-full w-2.5 border-l border-l-transparent p-[1px]', | |
| + orientation === 'horizontal' && | |
| + 'h-2.5 flex-col border-t border-t-transparent p-[1px]', | |
| + className | |
| + )} | |
| + {...props} | |
| + > | |
| + <ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-border" /> | |
| + </ScrollAreaPrimitive.ScrollAreaScrollbar> | |
| +)); | |
| +ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName; | |
| + | |
| +export { ScrollArea, ScrollBar }; | |
| diff --git a/components/ui/switch.tsx b/components/ui/switch.tsx | |
| new file mode 100644 | |
| index 0000000..eee816b | |
| --- /dev/null | |
| +++ b/components/ui/switch.tsx | |
| @@ -0,0 +1,28 @@ | |
| +'use client'; | |
| + | |
| +import * as React from 'react'; | |
| +import * as SwitchPrimitives from '@radix-ui/react-switch'; | |
| +import { cn } from '@/lib/utils'; | |
| + | |
| +const Switch = React.forwardRef< | |
| + React.ElementRef<typeof SwitchPrimitives.Root>, | |
| + React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root> | |
| +>(({ className, ...props }, ref) => ( | |
| + <SwitchPrimitives.Root | |
| + className={cn( | |
| + 'peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input', | |
| + className | |
| + )} | |
| + {...props} | |
| + ref={ref} | |
| + > | |
| + <SwitchPrimitives.Thumb | |
| + className={cn( | |
| + 'pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0' | |
| + )} | |
| + /> | |
| + </SwitchPrimitives.Root> | |
| +)); | |
| +Switch.displayName = SwitchPrimitives.Root.displayName; | |
| + | |
| +export { Switch }; | |
| diff --git a/components/ui/tabs.tsx b/components/ui/tabs.tsx | |
| new file mode 100644 | |
| index 0000000..87f3fa3 | |
| --- /dev/null | |
| +++ b/components/ui/tabs.tsx | |
| @@ -0,0 +1,54 @@ | |
| +'use client'; | |
| + | |
| +import * as React from 'react'; | |
| +import * as TabsPrimitive from '@radix-ui/react-tabs'; | |
| +import { cn } from '@/lib/utils'; | |
| + | |
| +const Tabs = TabsPrimitive.Root; | |
| + | |
| +const TabsList = React.forwardRef< | |
| + React.ElementRef<typeof TabsPrimitive.List>, | |
| + React.ComponentPropsWithoutRef<typeof TabsPrimitive.List> | |
| +>(({ className, ...props }, ref) => ( | |
| + <TabsPrimitive.List | |
| + ref={ref} | |
| + className={cn( | |
| + 'inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground', | |
| + className | |
| + )} | |
| + {...props} | |
| + /> | |
| +)); | |
| +TabsList.displayName = TabsPrimitive.List.displayName; | |
| + | |
| +const TabsTrigger = React.forwardRef< | |
| + React.ElementRef<typeof TabsPrimitive.Trigger>, | |
| + React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger> | |
| +>(({ className, ...props }, ref) => ( | |
| + <TabsPrimitive.Trigger | |
| + ref={ref} | |
| + className={cn( | |
| + 'inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm', | |
| + className | |
| + )} | |
| + {...props} | |
| + /> | |
| +)); | |
| +TabsTrigger.displayName = TabsPrimitive.Trigger.displayName; | |
| + | |
| +const TabsContent = React.forwardRef< | |
| + React.ElementRef<typeof TabsPrimitive.Content>, | |
| + React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content> | |
| +>(({ className, ...props }, ref) => ( | |
| + <TabsPrimitive.Content | |
| + ref={ref} | |
| + className={cn( | |
| + 'mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2', | |
| + className | |
| + )} | |
| + {...props} | |
| + /> | |
| +)); | |
| +TabsContent.displayName = TabsPrimitive.Content.displayName; | |
| + | |
| +export { Tabs, TabsList, TabsTrigger, TabsContent }; | |
| diff --git a/components/ui/textarea.tsx b/components/ui/textarea.tsx | |
| new file mode 100644 | |
| index 0000000..9404b13 | |
| --- /dev/null | |
| +++ b/components/ui/textarea.tsx | |
| @@ -0,0 +1,23 @@ | |
| +import * as React from 'react'; | |
| +import { cn } from '@/lib/utils'; | |
| + | |
| +export interface TextareaProps | |
| + extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {} | |
| + | |
| +const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>( | |
| + ({ className, ...props }, ref) => { | |
| + return ( | |
| + <textarea | |
| + className={cn( | |
| + 'flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50', | |
| + className | |
| + )} | |
| + ref={ref} | |
| + {...props} | |
| + /> | |
| + ); | |
| + } | |
| +); | |
| +Textarea.displayName = 'Textarea'; | |
| + | |
| +export { Textarea }; | |
| diff --git a/components/ui/toast.tsx b/components/ui/toast.tsx | |
| new file mode 100644 | |
| index 0000000..2a13f8c | |
| --- /dev/null | |
| +++ b/components/ui/toast.tsx | |
| @@ -0,0 +1,129 @@ | |
| +'use client'; | |
| + | |
| +import * as React from 'react'; | |
| +import * as ToastPrimitives from '@radix-ui/react-toast'; | |
| +import { cva, type VariantProps } from 'class-variance-authority'; | |
| +import { X } from 'lucide-react'; | |
| +import { cn } from '@/lib/utils'; | |
| + | |
| +const ToastProvider = ToastPrimitives.Provider; | |
| + | |
| +const ToastViewport = React.forwardRef< | |
| + React.ElementRef<typeof ToastPrimitives.Viewport>, | |
| + React.ComponentPropsWithoutRef<typeof ToastPrimitives.Viewport> | |
| +>(({ className, ...props }, ref) => ( | |
| + <ToastPrimitives.Viewport | |
| + ref={ref} | |
| + className={cn( | |
| + 'fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]', | |
| + className | |
| + )} | |
| + {...props} | |
| + /> | |
| +)); | |
| +ToastViewport.displayName = ToastPrimitives.Viewport.displayName; | |
| + | |
| +const toastVariants = cva( | |
| + 'group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-6 pr-8 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full', | |
| + { | |
| + variants: { | |
| + variant: { | |
| + default: 'border bg-background text-foreground', | |
| + destructive: | |
| + 'destructive group border-destructive bg-destructive text-destructive-foreground', | |
| + success: 'border-green-500/50 bg-green-500/10 text-green-500', | |
| + }, | |
| + }, | |
| + defaultVariants: { | |
| + variant: 'default', | |
| + }, | |
| + } | |
| +); | |
| + | |
| +const Toast = React.forwardRef< | |
| + React.ElementRef<typeof ToastPrimitives.Root>, | |
| + React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> & | |
| + VariantProps<typeof toastVariants> | |
| +>(({ className, variant, ...props }, ref) => { | |
| + return ( | |
| + <ToastPrimitives.Root | |
| + ref={ref} | |
| + className={cn(toastVariants({ variant }), className)} | |
| + {...props} | |
| + /> | |
| + ); | |
| +}); | |
| +Toast.displayName = ToastPrimitives.Root.displayName; | |
| + | |
| +const ToastAction = React.forwardRef< | |
| + React.ElementRef<typeof ToastPrimitives.Action>, | |
| + React.ComponentPropsWithoutRef<typeof ToastPrimitives.Action> | |
| +>(({ className, ...props }, ref) => ( | |
| + <ToastPrimitives.Action | |
| + ref={ref} | |
| + className={cn( | |
| + 'inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium ring-offset-background transition-colors hover:bg-secondary focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive', | |
| + className | |
| + )} | |
| + {...props} | |
| + /> | |
| +)); | |
| +ToastAction.displayName = ToastPrimitives.Action.displayName; | |
| + | |
| +const ToastClose = React.forwardRef< | |
| + React.ElementRef<typeof ToastPrimitives.Close>, | |
| + React.ComponentPropsWithoutRef<typeof ToastPrimitives.Close> | |
| +>(({ className, ...props }, ref) => ( | |
| + <ToastPrimitives.Close | |
| + ref={ref} | |
| + className={cn( | |
| + 'absolute right-2 top-2 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-2 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600', | |
| + className | |
| + )} | |
| + toast-close="" | |
| + {...props} | |
| + > | |
| + <X className="h-4 w-4" /> | |
| + </ToastPrimitives.Close> | |
| +)); | |
| +ToastClose.displayName = ToastPrimitives.Close.displayName; | |
| + | |
| +const ToastTitle = React.forwardRef< | |
| + React.ElementRef<typeof ToastPrimitives.Title>, | |
| + React.ComponentPropsWithoutRef<typeof ToastPrimitives.Title> | |
| +>(({ className, ...props }, ref) => ( | |
| + <ToastPrimitives.Title | |
| + ref={ref} | |
| + className={cn('text-sm font-semibold', className)} | |
| + {...props} | |
| + /> | |
| +)); | |
| +ToastTitle.displayName = ToastPrimitives.Title.displayName; | |
| + | |
| +const ToastDescription = React.forwardRef< | |
| + React.ElementRef<typeof ToastPrimitives.Description>, | |
| + React.ComponentPropsWithoutRef<typeof ToastPrimitives.Description> | |
| +>(({ className, ...props }, ref) => ( | |
| + <ToastPrimitives.Description | |
| + ref={ref} | |
| + className={cn('text-sm opacity-90', className)} | |
| + {...props} | |
| + /> | |
| +)); | |
| +ToastDescription.displayName = ToastPrimitives.Description.displayName; | |
| + | |
| +type ToastProps = React.ComponentPropsWithoutRef<typeof Toast>; | |
| + | |
| +type ToastActionElement = React.ReactElement<typeof ToastAction>; | |
| + | |
| +export { | |
| + type ToastProps, | |
| + type ToastActionElement, | |
| + ToastProvider, | |
| + ToastViewport, | |
| + Toast, | |
| + ToastTitle, | |
| + ToastDescription, | |
| + ToastClose, | |
| + ToastAction, | |
| +}; | |
| diff --git a/components/ui/toaster.tsx b/components/ui/toaster.tsx | |
| new file mode 100644 | |
| index 0000000..beb7f25 | |
| --- /dev/null | |
| +++ b/components/ui/toaster.tsx | |
| @@ -0,0 +1,35 @@ | |
| +'use client'; | |
| + | |
| +import { | |
| + Toast, | |
| + ToastClose, | |
| + ToastDescription, | |
| + ToastProvider, | |
| + ToastTitle, | |
| + ToastViewport, | |
| +} from '@/components/ui/toast'; | |
| +import { useToast } from '@/components/ui/use-toast'; | |
| + | |
| +export function Toaster() { | |
| + const { toasts } = useToast(); | |
| + | |
| + return ( | |
| + <ToastProvider> | |
| + {toasts.map(function ({ id, title, description, action, ...props }) { | |
| + return ( | |
| + <Toast key={id} {...props}> | |
| + <div className="grid gap-1"> | |
| + {title && <ToastTitle>{title}</ToastTitle>} | |
| + {description && ( | |
| + <ToastDescription>{description}</ToastDescription> | |
| + )} | |
| + </div> | |
| + {action} | |
| + <ToastClose /> | |
| + </Toast> | |
| + ); | |
| + })} | |
| + <ToastViewport /> | |
| + </ToastProvider> | |
| + ); | |
| +} | |
| diff --git a/components/ui/tooltip.tsx b/components/ui/tooltip.tsx | |
| new file mode 100644 | |
| index 0000000..560f500 | |
| --- /dev/null | |
| +++ b/components/ui/tooltip.tsx | |
| @@ -0,0 +1,29 @@ | |
| +'use client'; | |
| + | |
| +import * as React from 'react'; | |
| +import * as TooltipPrimitive from '@radix-ui/react-tooltip'; | |
| +import { cn } from '@/lib/utils'; | |
| + | |
| +const TooltipProvider = TooltipPrimitive.Provider; | |
| + | |
| +const Tooltip = TooltipPrimitive.Root; | |
| + | |
| +const TooltipTrigger = TooltipPrimitive.Trigger; | |
| + | |
| +const TooltipContent = React.forwardRef< | |
| + React.ElementRef<typeof TooltipPrimitive.Content>, | |
| + React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content> | |
| +>(({ className, sideOffset = 4, ...props }, ref) => ( | |
| + <TooltipPrimitive.Content | |
| + ref={ref} | |
| + sideOffset={sideOffset} | |
| + className={cn( | |
| + 'z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-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', | |
| + className | |
| + )} | |
| + {...props} | |
| + /> | |
| +)); | |
| +TooltipContent.displayName = TooltipPrimitive.Content.displayName; | |
| + | |
| +export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }; | |
| diff --git a/components/ui/use-toast.ts b/components/ui/use-toast.ts | |
| new file mode 100644 | |
| index 0000000..5412b5e | |
| --- /dev/null | |
| +++ b/components/ui/use-toast.ts | |
| @@ -0,0 +1,187 @@ | |
| +'use client'; | |
| + | |
| +import * as React from 'react'; | |
| +import type { ToastActionElement, ToastProps } from '@/components/ui/toast'; | |
| + | |
| +const TOAST_LIMIT = 3; | |
| +const TOAST_REMOVE_DELAY = 5000; | |
| + | |
| +type ToasterToast = ToastProps & { | |
| + id: string; | |
| + title?: React.ReactNode; | |
| + description?: React.ReactNode; | |
| + action?: ToastActionElement; | |
| +}; | |
| + | |
| +const actionTypes = { | |
| + ADD_TOAST: 'ADD_TOAST', | |
| + UPDATE_TOAST: 'UPDATE_TOAST', | |
| + DISMISS_TOAST: 'DISMISS_TOAST', | |
| + REMOVE_TOAST: 'REMOVE_TOAST', | |
| +} as const; | |
| + | |
| +let count = 0; | |
| + | |
| +function genId() { | |
| + count = (count + 1) % Number.MAX_SAFE_INTEGER; | |
| + return count.toString(); | |
| +} | |
| + | |
| +type ActionType = typeof actionTypes; | |
| + | |
| +type Action = | |
| + | { | |
| + type: ActionType['ADD_TOAST']; | |
| + toast: ToasterToast; | |
| + } | |
| + | { | |
| + type: ActionType['UPDATE_TOAST']; | |
| + toast: Partial<ToasterToast>; | |
| + } | |
| + | { | |
| + type: ActionType['DISMISS_TOAST']; | |
| + toastId?: ToasterToast['id']; | |
| + } | |
| + | { | |
| + type: ActionType['REMOVE_TOAST']; | |
| + toastId?: ToasterToast['id']; | |
| + }; | |
| + | |
| +interface State { | |
| + toasts: ToasterToast[]; | |
| +} | |
| + | |
| +const toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>(); | |
| + | |
| +const addToRemoveQueue = (toastId: string) => { | |
| + if (toastTimeouts.has(toastId)) { | |
| + return; | |
| + } | |
| + | |
| + const timeout = setTimeout(() => { | |
| + toastTimeouts.delete(toastId); | |
| + dispatch({ | |
| + type: 'REMOVE_TOAST', | |
| + toastId: toastId, | |
| + }); | |
| + }, TOAST_REMOVE_DELAY); | |
| + | |
| + toastTimeouts.set(toastId, timeout); | |
| +}; | |
| + | |
| +export const reducer = (state: State, action: Action): State => { | |
| + switch (action.type) { | |
| + case 'ADD_TOAST': | |
| + return { | |
| + ...state, | |
| + toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT), | |
| + }; | |
| + | |
| + case 'UPDATE_TOAST': | |
| + return { | |
| + ...state, | |
| + toasts: state.toasts.map((t) => | |
| + t.id === action.toast.id ? { ...t, ...action.toast } : t | |
| + ), | |
| + }; | |
| + | |
| + case 'DISMISS_TOAST': { | |
| + const { toastId } = action; | |
| + | |
| + if (toastId) { | |
| + addToRemoveQueue(toastId); | |
| + } else { | |
| + state.toasts.forEach((toast) => { | |
| + addToRemoveQueue(toast.id); | |
| + }); | |
| + } | |
| + | |
| + return { | |
| + ...state, | |
| + toasts: state.toasts.map((t) => | |
| + t.id === toastId || toastId === undefined | |
| + ? { | |
| + ...t, | |
| + open: false, | |
| + } | |
| + : t | |
| + ), | |
| + }; | |
| + } | |
| + case 'REMOVE_TOAST': | |
| + if (action.toastId === undefined) { | |
| + return { | |
| + ...state, | |
| + toasts: [], | |
| + }; | |
| + } | |
| + return { | |
| + ...state, | |
| + toasts: state.toasts.filter((t) => t.id !== action.toastId), | |
| + }; | |
| + } | |
| +}; | |
| + | |
| +const listeners: Array<(state: State) => void> = []; | |
| + | |
| +let memoryState: State = { toasts: [] }; | |
| + | |
| +function dispatch(action: Action) { | |
| + memoryState = reducer(memoryState, action); | |
| + listeners.forEach((listener) => { | |
| + listener(memoryState); | |
| + }); | |
| +} | |
| + | |
| +type Toast = Omit<ToasterToast, 'id'>; | |
| + | |
| +function toast({ ...props }: Toast) { | |
| + const id = genId(); | |
| + | |
| + const update = (props: ToasterToast) => | |
| + dispatch({ | |
| + type: 'UPDATE_TOAST', | |
| + toast: { ...props, id }, | |
| + }); | |
| + const dismiss = () => dispatch({ type: 'DISMISS_TOAST', toastId: id }); | |
| + | |
| + dispatch({ | |
| + type: 'ADD_TOAST', | |
| + toast: { | |
| + ...props, | |
| + id, | |
| + open: true, | |
| + onOpenChange: (open) => { | |
| + if (!open) dismiss(); | |
| + }, | |
| + }, | |
| + }); | |
| + | |
| + return { | |
| + id: id, | |
| + dismiss, | |
| + update, | |
| + }; | |
| +} | |
| + | |
| +function useToast() { | |
| + const [state, setState] = React.useState<State>(memoryState); | |
| + | |
| + React.useEffect(() => { | |
| + listeners.push(setState); | |
| + return () => { | |
| + const index = listeners.indexOf(setState); | |
| + if (index > -1) { | |
| + listeners.splice(index, 1); | |
| + } | |
| + }; | |
| + }, [state]); | |
| + | |
| + return { | |
| + ...state, | |
| + toast, | |
| + dismiss: (toastId?: string) => dispatch({ type: 'DISMISS_TOAST', toastId }), | |
| + }; | |
| +} | |
| + | |
| +export { useToast, toast }; | |
| diff --git a/hooks/index.ts b/hooks/index.ts | |
| new file mode 100644 | |
| index 0000000..79b55ec | |
| --- /dev/null | |
| +++ b/hooks/index.ts | |
| @@ -0,0 +1,3 @@ | |
| +export { useDebounce, useDebouncedCallback } from './useDebounce'; | |
| +export { useKeyboardShortcuts, KEYBOARD_SHORTCUTS } from './useKeyboardShortcuts'; | |
| +export type { KeyboardShortcut } from './useKeyboardShortcuts'; | |
| diff --git a/hooks/useDebounce.ts b/hooks/useDebounce.ts | |
| new file mode 100644 | |
| index 0000000..919f8ac | |
| --- /dev/null | |
| +++ b/hooks/useDebounce.ts | |
| @@ -0,0 +1,42 @@ | |
| +import { useState, useEffect } from 'react'; | |
| + | |
| +export function useDebounce<T>(value: T, delay: number): T { | |
| + const [debouncedValue, setDebouncedValue] = useState<T>(value); | |
| + | |
| + useEffect(() => { | |
| + const handler = setTimeout(() => { | |
| + setDebouncedValue(value); | |
| + }, delay); | |
| + | |
| + return () => { | |
| + clearTimeout(handler); | |
| + }; | |
| + }, [value, delay]); | |
| + | |
| + return debouncedValue; | |
| +} | |
| + | |
| +export function useDebouncedCallback<T extends (...args: Parameters<T>) => ReturnType<T>>( | |
| + callback: T, | |
| + delay: number | |
| +): T { | |
| + const [timeoutId, setTimeoutId] = useState<NodeJS.Timeout | null>(null); | |
| + | |
| + useEffect(() => { | |
| + return () => { | |
| + if (timeoutId) { | |
| + clearTimeout(timeoutId); | |
| + } | |
| + }; | |
| + }, [timeoutId]); | |
| + | |
| + return ((...args: Parameters<T>) => { | |
| + if (timeoutId) { | |
| + clearTimeout(timeoutId); | |
| + } | |
| + const newTimeoutId = setTimeout(() => { | |
| + callback(...args); | |
| + }, delay); | |
| + setTimeoutId(newTimeoutId); | |
| + }) as T; | |
| +} | |
| diff --git a/hooks/useKeyboardShortcuts.ts b/hooks/useKeyboardShortcuts.ts | |
| new file mode 100644 | |
| index 0000000..f95e77f | |
| --- /dev/null | |
| +++ b/hooks/useKeyboardShortcuts.ts | |
| @@ -0,0 +1,89 @@ | |
| +import { useEffect, useCallback } from 'react'; | |
| + | |
| +export interface KeyboardShortcut { | |
| + key: string; | |
| + description: string; | |
| + ctrl?: boolean; | |
| + shift?: boolean; | |
| + alt?: boolean; | |
| +} | |
| + | |
| +export const KEYBOARD_SHORTCUTS: KeyboardShortcut[] = [ | |
| + { key: '/', description: 'Focus search' }, | |
| + { key: 'Escape', description: 'Close modal / Cancel' }, | |
| + { key: 'l', description: 'Toggle layers panel' }, | |
| + { key: 'p', description: 'Toggle places panel' }, | |
| + { key: 'm', description: 'Toggle measure mode' }, | |
| + { key: 'h', description: 'Go to home view' }, | |
| + { key: '+', description: 'Zoom in' }, | |
| + { key: '-', description: 'Zoom out' }, | |
| + { key: '?', shift: true, description: 'Show keyboard shortcuts' }, | |
| +]; | |
| + | |
| +interface ShortcutHandlers { | |
| + onFocusSearch?: () => void; | |
| + onEscape?: () => void; | |
| + onToggleLayers?: () => void; | |
| + onTogglePlaces?: () => void; | |
| + onToggleMeasure?: () => void; | |
| + onHome?: () => void; | |
| + onZoomIn?: () => void; | |
| + onZoomOut?: () => void; | |
| + onShowShortcuts?: () => void; | |
| +} | |
| + | |
| +export function useKeyboardShortcuts(handlers: ShortcutHandlers): void { | |
| + const handleKeyDown = useCallback( | |
| + (event: KeyboardEvent) => { | |
| + const target = event.target as HTMLElement; | |
| + const isInputFocused = | |
| + target.tagName === 'INPUT' || | |
| + target.tagName === 'TEXTAREA' || | |
| + target.isContentEditable; | |
| + | |
| + if (event.key === 'Escape') { | |
| + handlers.onEscape?.(); | |
| + return; | |
| + } | |
| + | |
| + if (isInputFocused) return; | |
| + | |
| + switch (event.key) { | |
| + case '/': | |
| + event.preventDefault(); | |
| + handlers.onFocusSearch?.(); | |
| + break; | |
| + case 'l': | |
| + handlers.onToggleLayers?.(); | |
| + break; | |
| + case 'p': | |
| + handlers.onTogglePlaces?.(); | |
| + break; | |
| + case 'm': | |
| + handlers.onToggleMeasure?.(); | |
| + break; | |
| + case 'h': | |
| + handlers.onHome?.(); | |
| + break; | |
| + case '+': | |
| + case '=': | |
| + handlers.onZoomIn?.(); | |
| + break; | |
| + case '-': | |
| + handlers.onZoomOut?.(); | |
| + break; | |
| + case '?': | |
| + if (event.shiftKey) { | |
| + handlers.onShowShortcuts?.(); | |
| + } | |
| + break; | |
| + } | |
| + }, | |
| + [handlers] | |
| + ); | |
| + | |
| + useEffect(() => { | |
| + window.addEventListener('keydown', handleKeyDown); | |
| + return () => window.removeEventListener('keydown', handleKeyDown); | |
| + }, [handleKeyDown]); | |
| +} | |
| diff --git a/lib/cesium-config.ts b/lib/cesium-config.ts | |
| new file mode 100644 | |
| index 0000000..4602557 | |
| --- /dev/null | |
| +++ b/lib/cesium-config.ts | |
| @@ -0,0 +1,78 @@ | |
| +import type { BaseLayerType } from '@/types'; | |
| + | |
| +export function initializeCesium(): void { | |
| + if (typeof window === 'undefined') return; | |
| + | |
| + const cesiumBaseUrl = | |
| + process.env.NEXT_PUBLIC_CESIUM_BASE_URL || | |
| + 'https://cesium.com/downloads/cesiumjs/releases/1.122/Build/Cesium'; | |
| + | |
| + (window as Window & { CESIUM_BASE_URL?: string }).CESIUM_BASE_URL = cesiumBaseUrl; | |
| +} | |
| + | |
| +export function getCesiumIonToken(): string | undefined { | |
| + return process.env.NEXT_PUBLIC_CESIUM_ION_TOKEN || undefined; | |
| +} | |
| + | |
| +export function hasCesiumIonToken(): boolean { | |
| + const token = getCesiumIonToken(); | |
| + return Boolean(token && token.trim().length > 0); | |
| +} | |
| + | |
| +export const BASE_LAYER_CONFIGS: Record< | |
| + BaseLayerType, | |
| + { | |
| + name: string; | |
| + description: string; | |
| + url: string; | |
| + attribution?: string; | |
| + } | |
| +> = { | |
| + osm: { | |
| + name: 'OpenStreetMap', | |
| + description: 'Standard street map', | |
| + url: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', | |
| + attribution: | |
| + '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors', | |
| + }, | |
| + arcgis: { | |
| + name: 'ArcGIS Satellite', | |
| + description: 'Satellite imagery', | |
| + url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', | |
| + attribution: | |
| + 'Tiles © Esri — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community', | |
| + }, | |
| + stamen: { | |
| + name: 'Stamen Terrain', | |
| + description: 'Terrain visualization', | |
| + url: 'https://tiles.stadiamaps.com/tiles/stamen_terrain/{z}/{x}/{y}.png', | |
| + attribution: | |
| + '© <a href="https://stadiamaps.com/">Stadia Maps</a> © <a href="https://stamen.com">Stamen Design</a>', | |
| + }, | |
| +}; | |
| + | |
| +export const DEFAULT_CAMERA_POSITION = { | |
| + longitude: 0, | |
| + latitude: 20, | |
| + height: 20000000, | |
| +}; | |
| + | |
| +export const HOME_VIEW = { | |
| + destination: { | |
| + longitude: 0, | |
| + latitude: 20, | |
| + height: 20000000, | |
| + }, | |
| + orientation: { | |
| + heading: 0, | |
| + pitch: -90, | |
| + roll: 0, | |
| + }, | |
| +}; | |
| + | |
| +export const CAMERA_SETTINGS = { | |
| + zoomFactor: 0.5, | |
| + tiltIncrement: 5, | |
| + rotateIncrement: 10, | |
| + flyToDuration: 2, | |
| +}; | |
| diff --git a/lib/formatting.ts b/lib/formatting.ts | |
| new file mode 100644 | |
| index 0000000..e4f1fd8 | |
| --- /dev/null | |
| +++ b/lib/formatting.ts | |
| @@ -0,0 +1,78 @@ | |
| +import type { Coordinates } from '@/types'; | |
| + | |
| +export function formatCoordinate(value: number, type: 'lat' | 'lon'): string { | |
| + const absolute = Math.abs(value); | |
| + const degrees = Math.floor(absolute); | |
| + const minutesDecimal = (absolute - degrees) * 60; | |
| + const minutes = Math.floor(minutesDecimal); | |
| + const seconds = ((minutesDecimal - minutes) * 60).toFixed(2); | |
| + | |
| + const direction = | |
| + type === 'lat' ? (value >= 0 ? 'N' : 'S') : value >= 0 ? 'E' : 'W'; | |
| + | |
| + return `${degrees}° ${minutes}' ${seconds}" ${direction}`; | |
| +} | |
| + | |
| +export function formatCoordinatesShort(coords: Coordinates): string { | |
| + return `${coords.latitude.toFixed(6)}, ${coords.longitude.toFixed(6)}`; | |
| +} | |
| + | |
| +export function formatCoordinatesFull(coords: Coordinates): string { | |
| + return `${formatCoordinate(coords.latitude, 'lat')}, ${formatCoordinate(coords.longitude, 'lon')}`; | |
| +} | |
| + | |
| +export function formatAltitude(meters: number): string { | |
| + if (meters < 1000) { | |
| + return `${Math.round(meters)} m`; | |
| + } else if (meters < 100000) { | |
| + return `${(meters / 1000).toFixed(1)} km`; | |
| + } else if (meters < 1000000) { | |
| + return `${Math.round(meters / 1000)} km`; | |
| + } else { | |
| + return `${(meters / 1000000).toFixed(2)} Mm`; | |
| + } | |
| +} | |
| + | |
| +export function formatDistance(meters: number): string { | |
| + if (meters < 1000) { | |
| + return `${Math.round(meters)} m`; | |
| + } else if (meters < 10000) { | |
| + return `${(meters / 1000).toFixed(2)} km`; | |
| + } else if (meters < 100000) { | |
| + return `${(meters / 1000).toFixed(1)} km`; | |
| + } else { | |
| + return `${Math.round(meters / 1000).toLocaleString()} km`; | |
| + } | |
| +} | |
| + | |
| +export function calculateHaversineDistance( | |
| + point1: Coordinates, | |
| + point2: Coordinates | |
| +): number { | |
| + const R = 6371000; | |
| + const lat1Rad = (point1.latitude * Math.PI) / 180; | |
| + const lat2Rad = (point2.latitude * Math.PI) / 180; | |
| + const deltaLat = ((point2.latitude - point1.latitude) * Math.PI) / 180; | |
| + const deltaLon = ((point2.longitude - point1.longitude) * Math.PI) / 180; | |
| + | |
| + const a = | |
| + Math.sin(deltaLat / 2) * Math.sin(deltaLat / 2) + | |
| + Math.cos(lat1Rad) * | |
| + Math.cos(lat2Rad) * | |
| + Math.sin(deltaLon / 2) * | |
| + Math.sin(deltaLon / 2); | |
| + const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); | |
| + | |
| + return R * c; | |
| +} | |
| + | |
| +export function formatDate(dateString: string): string { | |
| + const date = new Date(dateString); | |
| + return date.toLocaleDateString(undefined, { | |
| + year: 'numeric', | |
| + month: 'short', | |
| + day: 'numeric', | |
| + hour: '2-digit', | |
| + minute: '2-digit', | |
| + }); | |
| +} | |
| diff --git a/lib/geocoding.ts b/lib/geocoding.ts | |
| new file mode 100644 | |
| index 0000000..4dcd3f3 | |
| --- /dev/null | |
| +++ b/lib/geocoding.ts | |
| @@ -0,0 +1,143 @@ | |
| +import type { GeocodingResult } from '@/types'; | |
| + | |
| +const NOMINATIM_BASE_URL = 'https://nominatim.openstreetmap.org'; | |
| +const USER_AGENT = 'TerraView/1.0 (Educational Project)'; | |
| +const MIN_REQUEST_INTERVAL = 1000; | |
| + | |
| +let lastRequestTime = 0; | |
| + | |
| +interface NominatimResult { | |
| + place_id: number; | |
| + licence: string; | |
| + osm_type: string; | |
| + osm_id: number; | |
| + lat: string; | |
| + lon: string; | |
| + class: string; | |
| + type: string; | |
| + place_rank: number; | |
| + importance: number; | |
| + addresstype: string; | |
| + name: string; | |
| + display_name: string; | |
| + boundingbox: string[]; | |
| +} | |
| + | |
| +async function enforceRateLimit(): Promise<void> { | |
| + const now = Date.now(); | |
| + const timeSinceLastRequest = now - lastRequestTime; | |
| + | |
| + if (timeSinceLastRequest < MIN_REQUEST_INTERVAL) { | |
| + await new Promise((resolve) => | |
| + setTimeout(resolve, MIN_REQUEST_INTERVAL - timeSinceLastRequest) | |
| + ); | |
| + } | |
| + | |
| + lastRequestTime = Date.now(); | |
| +} | |
| + | |
| +export async function searchPlaces( | |
| + query: string, | |
| + signal?: AbortSignal | |
| +): Promise<GeocodingResult[]> { | |
| + if (!query.trim()) { | |
| + return []; | |
| + } | |
| + | |
| + await enforceRateLimit(); | |
| + | |
| + const params = new URLSearchParams({ | |
| + q: query, | |
| + format: 'json', | |
| + addressdetails: '1', | |
| + limit: '8', | |
| + }); | |
| + | |
| + const response = await fetch(`${NOMINATIM_BASE_URL}/search?${params}`, { | |
| + headers: { | |
| + 'User-Agent': USER_AGENT, | |
| + Accept: 'application/json', | |
| + }, | |
| + signal, | |
| + }); | |
| + | |
| + if (!response.ok) { | |
| + throw new Error(`Geocoding failed: ${response.status} ${response.statusText}`); | |
| + } | |
| + | |
| + const results: NominatimResult[] = await response.json(); | |
| + | |
| + return results.map((result) => ({ | |
| + id: String(result.place_id), | |
| + name: result.name || result.display_name.split(',')[0], | |
| + displayName: result.display_name, | |
| + coordinates: { | |
| + latitude: parseFloat(result.lat), | |
| + longitude: parseFloat(result.lon), | |
| + }, | |
| + type: result.type, | |
| + importance: result.importance, | |
| + })); | |
| +} | |
| + | |
| +export async function reverseGeocode( | |
| + latitude: number, | |
| + longitude: number, | |
| + signal?: AbortSignal | |
| +): Promise<string | null> { | |
| + await enforceRateLimit(); | |
| + | |
| + const params = new URLSearchParams({ | |
| + lat: String(latitude), | |
| + lon: String(longitude), | |
| + format: 'json', | |
| + zoom: '18', | |
| + }); | |
| + | |
| + try { | |
| + const response = await fetch(`${NOMINATIM_BASE_URL}/reverse?${params}`, { | |
| + headers: { | |
| + 'User-Agent': USER_AGENT, | |
| + Accept: 'application/json', | |
| + }, | |
| + signal, | |
| + }); | |
| + | |
| + if (!response.ok) { | |
| + return null; | |
| + } | |
| + | |
| + const result = await response.json(); | |
| + return result.display_name || null; | |
| + } catch { | |
| + return null; | |
| + } | |
| +} | |
| + | |
| +export class GeocodingClient { | |
| + private abortController: AbortController | null = null; | |
| + | |
| + async search(query: string): Promise<GeocodingResult[]> { | |
| + if (this.abortController) { | |
| + this.abortController.abort(); | |
| + } | |
| + | |
| + this.abortController = new AbortController(); | |
| + | |
| + try { | |
| + return await searchPlaces(query, this.abortController.signal); | |
| + } catch (error) { | |
| + if (error instanceof Error && error.name === 'AbortError') { | |
| + return []; | |
| + } | |
| + throw error; | |
| + } | |
| + } | |
| + | |
| + abort(): void { | |
| + if (this.abortController) { | |
| + this.abortController.abort(); | |
| + this.abortController = null; | |
| + } | |
| + } | |
| +} | |
| diff --git a/lib/storage.ts b/lib/storage.ts | |
| new file mode 100644 | |
| index 0000000..4405d44 | |
| --- /dev/null | |
| +++ b/lib/storage.ts | |
| @@ -0,0 +1,102 @@ | |
| +import type { SavedPlace, LayerState, ThemeMode } from '@/types'; | |
| +import { SavedPlacesArraySchema, LayerStateSchema } from '@/types'; | |
| + | |
| +const STORAGE_KEYS = { | |
| + PLACES: 'terraview-places', | |
| + LAYERS: 'terraview-layers', | |
| + THEME: 'terraview-theme', | |
| +} as const; | |
| + | |
| +function safeGetItem(key: string): string | null { | |
| + if (typeof window === 'undefined') return null; | |
| + try { | |
| + return localStorage.getItem(key); | |
| + } catch { | |
| + console.warn(`Failed to read from localStorage: ${key}`); | |
| + return null; | |
| + } | |
| +} | |
| + | |
| +function safeSetItem(key: string, value: string): boolean { | |
| + if (typeof window === 'undefined') return false; | |
| + try { | |
| + localStorage.setItem(key, value); | |
| + return true; | |
| + } catch { | |
| + console.warn(`Failed to write to localStorage: ${key}`); | |
| + return false; | |
| + } | |
| +} | |
| + | |
| +export function loadPlaces(): SavedPlace[] { | |
| + const data = safeGetItem(STORAGE_KEYS.PLACES); | |
| + if (!data) return []; | |
| + | |
| + try { | |
| + const parsed = JSON.parse(data); | |
| + const result = SavedPlacesArraySchema.safeParse(parsed); | |
| + return result.success ? result.data : []; | |
| + } catch { | |
| + return []; | |
| + } | |
| +} | |
| + | |
| +export function savePlaces(places: SavedPlace[]): boolean { | |
| + return safeSetItem(STORAGE_KEYS.PLACES, JSON.stringify(places)); | |
| +} | |
| + | |
| +export function loadLayers(): LayerState | null { | |
| + const data = safeGetItem(STORAGE_KEYS.LAYERS); | |
| + if (!data) return null; | |
| + | |
| + try { | |
| + const parsed = JSON.parse(data); | |
| + const result = LayerStateSchema.safeParse(parsed); | |
| + return result.success ? result.data : null; | |
| + } catch { | |
| + return null; | |
| + } | |
| +} | |
| + | |
| +export function saveLayers(layers: LayerState): boolean { | |
| + return safeSetItem(STORAGE_KEYS.LAYERS, JSON.stringify(layers)); | |
| +} | |
| + | |
| +export function loadTheme(): ThemeMode | null { | |
| + const data = safeGetItem(STORAGE_KEYS.THEME); | |
| + if (!data) return null; | |
| + if (data === 'light' || data === 'dark' || data === 'system') { | |
| + return data; | |
| + } | |
| + return null; | |
| +} | |
| + | |
| +export function saveTheme(theme: ThemeMode): boolean { | |
| + return safeSetItem(STORAGE_KEYS.THEME, theme); | |
| +} | |
| + | |
| +export function exportPlaces(places: SavedPlace[]): string { | |
| + return JSON.stringify(places, null, 2); | |
| +} | |
| + | |
| +export function importPlaces(jsonString: string): SavedPlace[] | null { | |
| + try { | |
| + const parsed = JSON.parse(jsonString); | |
| + const result = SavedPlacesArraySchema.safeParse(parsed); | |
| + return result.success ? result.data : null; | |
| + } catch { | |
| + return null; | |
| + } | |
| +} | |
| + | |
| +export function downloadJson(data: string, filename: string): void { | |
| + const blob = new Blob([data], { type: 'application/json' }); | |
| + const url = URL.createObjectURL(blob); | |
| + const link = document.createElement('a'); | |
| + link.href = url; | |
| + link.download = filename; | |
| + document.body.appendChild(link); | |
| + link.click(); | |
| + document.body.removeChild(link); | |
| + URL.revokeObjectURL(url); | |
| +} | |
| diff --git a/lib/utils.ts b/lib/utils.ts | |
| new file mode 100644 | |
| index 0000000..b14c5b3 | |
| --- /dev/null | |
| +++ b/lib/utils.ts | |
| @@ -0,0 +1,35 @@ | |
| +import { type ClassValue, clsx } from 'clsx'; | |
| +import { twMerge } from 'tailwind-merge'; | |
| + | |
| +export function cn(...inputs: ClassValue[]) { | |
| + return twMerge(clsx(inputs)); | |
| +} | |
| + | |
| +export function generateId(): string { | |
| + return `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`; | |
| +} | |
| + | |
| +export function throttle<T extends (...args: Parameters<T>) => ReturnType<T>>( | |
| + func: T, | |
| + limit: number | |
| +): (...args: Parameters<T>) => void { | |
| + let inThrottle = false; | |
| + return function (this: unknown, ...args: Parameters<T>) { | |
| + if (!inThrottle) { | |
| + func.apply(this, args); | |
| + inThrottle = true; | |
| + setTimeout(() => (inThrottle = false), limit); | |
| + } | |
| + }; | |
| +} | |
| + | |
| +export function debounce<T extends (...args: Parameters<T>) => ReturnType<T>>( | |
| + func: T, | |
| + wait: number | |
| +): (...args: Parameters<T>) => void { | |
| + let timeout: NodeJS.Timeout | null = null; | |
| + return function (this: unknown, ...args: Parameters<T>) { | |
| + if (timeout) clearTimeout(timeout); | |
| + timeout = setTimeout(() => func.apply(this, args), wait); | |
| + }; | |
| +} | |
| diff --git a/next.config.js b/next.config.js | |
| new file mode 100644 | |
| index 0000000..f2a5359 | |
| --- /dev/null | |
| +++ b/next.config.js | |
| @@ -0,0 +1,37 @@ | |
| +/** @type {import('next').NextConfig} */ | |
| +const nextConfig = { | |
| + reactStrictMode: true, | |
| + | |
| + transpilePackages: ['cesium'], | |
| + | |
| + webpack: (config, { isServer, webpack }) => { | |
| + if (!isServer) { | |
| + config.plugins.push( | |
| + new webpack.DefinePlugin({ | |
| + CESIUM_BASE_URL: JSON.stringify( | |
| + 'https://cesium.com/downloads/cesiumjs/releases/1.122/Build/Cesium' | |
| + ), | |
| + }) | |
| + ); | |
| + | |
| + config.resolve.fallback = { | |
| + ...config.resolve.fallback, | |
| + fs: false, | |
| + net: false, | |
| + tls: false, | |
| + http: false, | |
| + https: false, | |
| + zlib: false, | |
| + url: false, | |
| + }; | |
| + } | |
| + | |
| + return config; | |
| + }, | |
| + | |
| + experimental: { | |
| + optimizePackageImports: ['lucide-react', '@radix-ui/react-icons'], | |
| + }, | |
| +}; | |
| + | |
| +module.exports = nextConfig; | |
| diff --git a/package-lock.json b/package-lock.json | |
| new file mode 100644 | |
| index 0000000..43006b9 | |
| --- /dev/null | |
| +++ b/package-lock.json | |
| @@ -0,0 +1,7567 @@ | |
| +{ | |
| + "name": "terraview", | |
| + "version": "1.0.0", | |
| + "lockfileVersion": 3, | |
| + "requires": true, | |
| + "packages": { | |
| + "": { | |
| + "name": "terraview", | |
| + "version": "1.0.0", | |
| + "dependencies": { | |
| + "@radix-ui/react-dialog": "^1.1.2", | |
| + "@radix-ui/react-dropdown-menu": "^2.1.2", | |
| + "@radix-ui/react-label": "^2.1.0", | |
| + "@radix-ui/react-scroll-area": "^1.2.0", | |
| + "@radix-ui/react-slot": "^1.1.0", | |
| + "@radix-ui/react-switch": "^1.1.1", | |
| + "@radix-ui/react-tabs": "^1.1.1", | |
| + "@radix-ui/react-toast": "^1.2.2", | |
| + "@radix-ui/react-tooltip": "^1.1.3", | |
| + "cesium": "^1.122.0", | |
| + "class-variance-authority": "^0.7.0", | |
| + "clsx": "^2.1.1", | |
| + "lucide-react": "^0.454.0", | |
| + "next": "14.2.15", | |
| + "next-themes": "^0.3.0", | |
| + "react": "18.2.0", | |
| + "react-dom": "18.2.0", | |
| + "tailwind-merge": "^2.5.4", | |
| + "tailwindcss-animate": "^1.0.7", | |
| + "zod": "^3.23.8", | |
| + "zustand": "^5.0.1" | |
| + }, | |
| + "devDependencies": { | |
| + "@types/node": "^22.8.1", | |
| + "@types/react": "^18.2.0", | |
| + "@types/react-dom": "^18.2.0", | |
| + "autoprefixer": "^10.4.20", | |
| + "eslint": "^8.57.1", | |
| + "eslint-config-next": "14.2.15", | |
| + "postcss": "^8.4.47", | |
| + "tailwindcss": "^3.4.14", | |
| + "typescript": "^5.6.3" | |
| + } | |
| + }, | |
| + "node_modules/@alloc/quick-lru": { | |
| + "version": "5.2.0", | |
| + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", | |
| + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=10" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/sindresorhus" | |
| + } | |
| + }, | |
| + "node_modules/@cesium/engine": { | |
| + "version": "22.3.0", | |
| + "resolved": "https://registry.npmjs.org/@cesium/engine/-/engine-22.3.0.tgz", | |
| + "integrity": "sha512-oDl+nWX/qfHYQ0lEdGxLqZoKEtTMghvJDzZKTycYfiIuDYDh8Kh0Oy45wr3mSJse3PuTj1e6hDmbw8vbycCOxw==", | |
| + "license": "Apache-2.0", | |
| + "dependencies": { | |
| + "@cesium/wasm-splats": "^0.1.0-alpha.2", | |
| + "@spz-loader/core": "0.3.0", | |
| + "@tweenjs/tween.js": "^25.0.0", | |
| + "@zip.js/zip.js": "^2.8.1", | |
| + "autolinker": "^4.0.0", | |
| + "bitmap-sdf": "^1.0.3", | |
| + "dompurify": "^3.3.0", | |
| + "draco3d": "^1.5.1", | |
| + "earcut": "^3.0.0", | |
| + "grapheme-splitter": "^1.0.4", | |
| + "jsep": "^1.3.8", | |
| + "kdbush": "^4.0.1", | |
| + "ktx-parse": "^1.0.0", | |
| + "lerc": "^2.0.0", | |
| + "mersenne-twister": "^1.1.0", | |
| + "meshoptimizer": "^1.0.1", | |
| + "pako": "^2.0.4", | |
| + "protobufjs": "^8.0.0", | |
| + "rbush": "^4.0.1", | |
| + "topojson-client": "^3.1.0", | |
| + "urijs": "^1.19.7" | |
| + }, | |
| + "engines": { | |
| + "node": ">=20.19.0" | |
| + } | |
| + }, | |
| + "node_modules/@cesium/wasm-splats": { | |
| + "version": "0.1.0-alpha.2", | |
| + "resolved": "https://registry.npmjs.org/@cesium/wasm-splats/-/wasm-splats-0.1.0-alpha.2.tgz", | |
| + "integrity": "sha512-t9pMkknv31hhIbLpMa8yPvmqfpvs5UkUjgqlQv9SeO8VerCXOYnyP8/486BDaFrztM0A7FMbRjsXtNeKvqQghA==", | |
| + "license": "Apache-2.0" | |
| + }, | |
| + "node_modules/@cesium/widgets": { | |
| + "version": "14.3.0", | |
| + "resolved": "https://registry.npmjs.org/@cesium/widgets/-/widgets-14.3.0.tgz", | |
| + "integrity": "sha512-1bS+Nv/uXwP0/NV0o4XeUA5nLCWttjTmKwl+pHnbZXp0ZwDmClb0xVDruDyVtLrUuRhsk84JZ4rXI/IT7HXOvA==", | |
| + "license": "Apache-2.0", | |
| + "dependencies": { | |
| + "@cesium/engine": "^22.3.0", | |
| + "nosleep.js": "^0.12.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">=20.19.0" | |
| + } | |
| + }, | |
| + "node_modules/@emnapi/core": { | |
| + "version": "1.8.1", | |
| + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.8.1.tgz", | |
| + "integrity": "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "optional": true, | |
| + "dependencies": { | |
| + "@emnapi/wasi-threads": "1.1.0", | |
| + "tslib": "^2.4.0" | |
| + } | |
| + }, | |
| + "node_modules/@emnapi/runtime": { | |
| + "version": "1.8.1", | |
| + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", | |
| + "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "optional": true, | |
| + "dependencies": { | |
| + "tslib": "^2.4.0" | |
| + } | |
| + }, | |
| + "node_modules/@emnapi/wasi-threads": { | |
| + "version": "1.1.0", | |
| + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", | |
| + "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "optional": true, | |
| + "dependencies": { | |
| + "tslib": "^2.4.0" | |
| + } | |
| + }, | |
| + "node_modules/@eslint-community/eslint-utils": { | |
| + "version": "4.9.1", | |
| + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", | |
| + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "eslint-visitor-keys": "^3.4.3" | |
| + }, | |
| + "engines": { | |
| + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" | |
| + }, | |
| + "funding": { | |
| + "url": "https://opencollective.com/eslint" | |
| + }, | |
| + "peerDependencies": { | |
| + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" | |
| + } | |
| + }, | |
| + "node_modules/@eslint-community/regexpp": { | |
| + "version": "4.12.2", | |
| + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", | |
| + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" | |
| + } | |
| + }, | |
| + "node_modules/@eslint/eslintrc": { | |
| + "version": "2.1.4", | |
| + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", | |
| + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "ajv": "^6.12.4", | |
| + "debug": "^4.3.2", | |
| + "espree": "^9.6.0", | |
| + "globals": "^13.19.0", | |
| + "ignore": "^5.2.0", | |
| + "import-fresh": "^3.2.1", | |
| + "js-yaml": "^4.1.0", | |
| + "minimatch": "^3.1.2", | |
| + "strip-json-comments": "^3.1.1" | |
| + }, | |
| + "engines": { | |
| + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" | |
| + }, | |
| + "funding": { | |
| + "url": "https://opencollective.com/eslint" | |
| + } | |
| + }, | |
| + "node_modules/@eslint/js": { | |
| + "version": "8.57.1", | |
| + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", | |
| + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" | |
| + } | |
| + }, | |
| + "node_modules/@floating-ui/core": { | |
| + "version": "1.7.4", | |
| + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.4.tgz", | |
| + "integrity": "sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@floating-ui/utils": "^0.2.10" | |
| + } | |
| + }, | |
| + "node_modules/@floating-ui/dom": { | |
| + "version": "1.7.5", | |
| + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.5.tgz", | |
| + "integrity": "sha512-N0bD2kIPInNHUHehXhMke1rBGs1dwqvC9O9KYMyyjK7iXt7GAhnro7UlcuYcGdS/yYOlq0MAVgrow8IbWJwyqg==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@floating-ui/core": "^1.7.4", | |
| + "@floating-ui/utils": "^0.2.10" | |
| + } | |
| + }, | |
| + "node_modules/@floating-ui/react-dom": { | |
| + "version": "2.1.7", | |
| + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.7.tgz", | |
| + "integrity": "sha512-0tLRojf/1Go2JgEVm+3Frg9A3IW8bJgKgdO0BN5RkF//ufuz2joZM63Npau2ff3J6lUVYgDSNzNkR+aH3IVfjg==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@floating-ui/dom": "^1.7.5" | |
| + }, | |
| + "peerDependencies": { | |
| + "react": ">=16.8.0", | |
| + "react-dom": ">=16.8.0" | |
| + } | |
| + }, | |
| + "node_modules/@floating-ui/utils": { | |
| + "version": "0.2.10", | |
| + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", | |
| + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/@humanwhocodes/config-array": { | |
| + "version": "0.13.0", | |
| + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", | |
| + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", | |
| + "deprecated": "Use @eslint/config-array instead", | |
| + "dev": true, | |
| + "license": "Apache-2.0", | |
| + "dependencies": { | |
| + "@humanwhocodes/object-schema": "^2.0.3", | |
| + "debug": "^4.3.1", | |
| + "minimatch": "^3.0.5" | |
| + }, | |
| + "engines": { | |
| + "node": ">=10.10.0" | |
| + } | |
| + }, | |
| + "node_modules/@humanwhocodes/module-importer": { | |
| + "version": "1.0.1", | |
| + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", | |
| + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", | |
| + "dev": true, | |
| + "license": "Apache-2.0", | |
| + "engines": { | |
| + "node": ">=12.22" | |
| + }, | |
| + "funding": { | |
| + "type": "github", | |
| + "url": "https://github.com/sponsors/nzakas" | |
| + } | |
| + }, | |
| + "node_modules/@humanwhocodes/object-schema": { | |
| + "version": "2.0.3", | |
| + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", | |
| + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", | |
| + "deprecated": "Use @eslint/object-schema instead", | |
| + "dev": true, | |
| + "license": "BSD-3-Clause" | |
| + }, | |
| + "node_modules/@isaacs/cliui": { | |
| + "version": "8.0.2", | |
| + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", | |
| + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", | |
| + "dev": true, | |
| + "license": "ISC", | |
| + "dependencies": { | |
| + "string-width": "^5.1.2", | |
| + "string-width-cjs": "npm:string-width@^4.2.0", | |
| + "strip-ansi": "^7.0.1", | |
| + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", | |
| + "wrap-ansi": "^8.1.0", | |
| + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">=12" | |
| + } | |
| + }, | |
| + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { | |
| + "version": "6.2.2", | |
| + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", | |
| + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=12" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/chalk/ansi-regex?sponsor=1" | |
| + } | |
| + }, | |
| + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { | |
| + "version": "7.1.2", | |
| + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", | |
| + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "ansi-regex": "^6.0.1" | |
| + }, | |
| + "engines": { | |
| + "node": ">=12" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/chalk/strip-ansi?sponsor=1" | |
| + } | |
| + }, | |
| + "node_modules/@jridgewell/gen-mapping": { | |
| + "version": "0.3.13", | |
| + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", | |
| + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@jridgewell/sourcemap-codec": "^1.5.0", | |
| + "@jridgewell/trace-mapping": "^0.3.24" | |
| + } | |
| + }, | |
| + "node_modules/@jridgewell/resolve-uri": { | |
| + "version": "3.1.2", | |
| + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", | |
| + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=6.0.0" | |
| + } | |
| + }, | |
| + "node_modules/@jridgewell/sourcemap-codec": { | |
| + "version": "1.5.5", | |
| + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", | |
| + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/@jridgewell/trace-mapping": { | |
| + "version": "0.3.31", | |
| + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", | |
| + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@jridgewell/resolve-uri": "^3.1.0", | |
| + "@jridgewell/sourcemap-codec": "^1.4.14" | |
| + } | |
| + }, | |
| + "node_modules/@napi-rs/wasm-runtime": { | |
| + "version": "0.2.12", | |
| + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", | |
| + "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "optional": true, | |
| + "dependencies": { | |
| + "@emnapi/core": "^1.4.3", | |
| + "@emnapi/runtime": "^1.4.3", | |
| + "@tybys/wasm-util": "^0.10.0" | |
| + } | |
| + }, | |
| + "node_modules/@next/env": { | |
| + "version": "14.2.15", | |
| + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.15.tgz", | |
| + "integrity": "sha512-S1qaj25Wru2dUpcIZMjxeMVSwkt8BK4dmWHHiBuRstcIyOsMapqT4A4jSB6onvqeygkSSmOkyny9VVx8JIGamQ==", | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/@next/eslint-plugin-next": { | |
| + "version": "14.2.15", | |
| + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-14.2.15.tgz", | |
| + "integrity": "sha512-pKU0iqKRBlFB/ocOI1Ip2CkKePZpYpnw5bEItEkuZ/Nr9FQP1+p7VDWr4VfOdff4i9bFmrOaeaU1bFEyAcxiMQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "glob": "10.3.10" | |
| + } | |
| + }, | |
| + "node_modules/@next/swc-darwin-arm64": { | |
| + "version": "14.2.15", | |
| + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.15.tgz", | |
| + "integrity": "sha512-Rvh7KU9hOUBnZ9TJ28n2Oa7dD9cvDBKua9IKx7cfQQ0GoYUwg9ig31O2oMwH3wm+pE3IkAQ67ZobPfEgurPZIA==", | |
| + "cpu": [ | |
| + "arm64" | |
| + ], | |
| + "license": "MIT", | |
| + "optional": true, | |
| + "os": [ | |
| + "darwin" | |
| + ], | |
| + "engines": { | |
| + "node": ">= 10" | |
| + } | |
| + }, | |
| + "node_modules/@next/swc-darwin-x64": { | |
| + "version": "14.2.15", | |
| + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.15.tgz", | |
| + "integrity": "sha512-5TGyjFcf8ampZP3e+FyCax5zFVHi+Oe7sZyaKOngsqyaNEpOgkKB3sqmymkZfowy3ufGA/tUgDPPxpQx931lHg==", | |
| + "cpu": [ | |
| + "x64" | |
| + ], | |
| + "license": "MIT", | |
| + "optional": true, | |
| + "os": [ | |
| + "darwin" | |
| + ], | |
| + "engines": { | |
| + "node": ">= 10" | |
| + } | |
| + }, | |
| + "node_modules/@next/swc-linux-arm64-gnu": { | |
| + "version": "14.2.15", | |
| + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.15.tgz", | |
| + "integrity": "sha512-3Bwv4oc08ONiQ3FiOLKT72Q+ndEMyLNsc/D3qnLMbtUYTQAmkx9E/JRu0DBpHxNddBmNT5hxz1mYBphJ3mfrrw==", | |
| + "cpu": [ | |
| + "arm64" | |
| + ], | |
| + "license": "MIT", | |
| + "optional": true, | |
| + "os": [ | |
| + "linux" | |
| + ], | |
| + "engines": { | |
| + "node": ">= 10" | |
| + } | |
| + }, | |
| + "node_modules/@next/swc-linux-arm64-musl": { | |
| + "version": "14.2.15", | |
| + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.15.tgz", | |
| + "integrity": "sha512-k5xf/tg1FBv/M4CMd8S+JL3uV9BnnRmoe7F+GWC3DxkTCD9aewFRH1s5rJ1zkzDa+Do4zyN8qD0N8c84Hu96FQ==", | |
| + "cpu": [ | |
| + "arm64" | |
| + ], | |
| + "license": "MIT", | |
| + "optional": true, | |
| + "os": [ | |
| + "linux" | |
| + ], | |
| + "engines": { | |
| + "node": ">= 10" | |
| + } | |
| + }, | |
| + "node_modules/@next/swc-linux-x64-gnu": { | |
| + "version": "14.2.15", | |
| + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.15.tgz", | |
| + "integrity": "sha512-kE6q38hbrRbKEkkVn62reLXhThLRh6/TvgSP56GkFNhU22TbIrQDEMrO7j0IcQHcew2wfykq8lZyHFabz0oBrA==", | |
| + "cpu": [ | |
| + "x64" | |
| + ], | |
| + "license": "MIT", | |
| + "optional": true, | |
| + "os": [ | |
| + "linux" | |
| + ], | |
| + "engines": { | |
| + "node": ">= 10" | |
| + } | |
| + }, | |
| + "node_modules/@next/swc-linux-x64-musl": { | |
| + "version": "14.2.15", | |
| + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.15.tgz", | |
| + "integrity": "sha512-PZ5YE9ouy/IdO7QVJeIcyLn/Rc4ml9M2G4y3kCM9MNf1YKvFY4heg3pVa/jQbMro+tP6yc4G2o9LjAz1zxD7tQ==", | |
| + "cpu": [ | |
| + "x64" | |
| + ], | |
| + "license": "MIT", | |
| + "optional": true, | |
| + "os": [ | |
| + "linux" | |
| + ], | |
| + "engines": { | |
| + "node": ">= 10" | |
| + } | |
| + }, | |
| + "node_modules/@next/swc-win32-arm64-msvc": { | |
| + "version": "14.2.15", | |
| + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.15.tgz", | |
| + "integrity": "sha512-2raR16703kBvYEQD9HNLyb0/394yfqzmIeyp2nDzcPV4yPjqNUG3ohX6jX00WryXz6s1FXpVhsCo3i+g4RUX+g==", | |
| + "cpu": [ | |
| + "arm64" | |
| + ], | |
| + "license": "MIT", | |
| + "optional": true, | |
| + "os": [ | |
| + "win32" | |
| + ], | |
| + "engines": { | |
| + "node": ">= 10" | |
| + } | |
| + }, | |
| + "node_modules/@next/swc-win32-ia32-msvc": { | |
| + "version": "14.2.15", | |
| + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.15.tgz", | |
| + "integrity": "sha512-fyTE8cklgkyR1p03kJa5zXEaZ9El+kDNM5A+66+8evQS5e/6v0Gk28LqA0Jet8gKSOyP+OTm/tJHzMlGdQerdQ==", | |
| + "cpu": [ | |
| + "ia32" | |
| + ], | |
| + "license": "MIT", | |
| + "optional": true, | |
| + "os": [ | |
| + "win32" | |
| + ], | |
| + "engines": { | |
| + "node": ">= 10" | |
| + } | |
| + }, | |
| + "node_modules/@next/swc-win32-x64-msvc": { | |
| + "version": "14.2.15", | |
| + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.15.tgz", | |
| + "integrity": "sha512-SzqGbsLsP9OwKNUG9nekShTwhj6JSB9ZLMWQ8g1gG6hdE5gQLncbnbymrwy2yVmH9nikSLYRYxYMFu78Ggp7/g==", | |
| + "cpu": [ | |
| + "x64" | |
| + ], | |
| + "license": "MIT", | |
| + "optional": true, | |
| + "os": [ | |
| + "win32" | |
| + ], | |
| + "engines": { | |
| + "node": ">= 10" | |
| + } | |
| + }, | |
| + "node_modules/@nodelib/fs.scandir": { | |
| + "version": "2.1.5", | |
| + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", | |
| + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@nodelib/fs.stat": "2.0.5", | |
| + "run-parallel": "^1.1.9" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 8" | |
| + } | |
| + }, | |
| + "node_modules/@nodelib/fs.stat": { | |
| + "version": "2.0.5", | |
| + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", | |
| + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">= 8" | |
| + } | |
| + }, | |
| + "node_modules/@nodelib/fs.walk": { | |
| + "version": "1.2.8", | |
| + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", | |
| + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@nodelib/fs.scandir": "2.1.5", | |
| + "fastq": "^1.6.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 8" | |
| + } | |
| + }, | |
| + "node_modules/@nolyfill/is-core-module": { | |
| + "version": "1.0.39", | |
| + "resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz", | |
| + "integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=12.4.0" | |
| + } | |
| + }, | |
| + "node_modules/@pkgjs/parseargs": { | |
| + "version": "0.11.0", | |
| + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", | |
| + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "optional": true, | |
| + "engines": { | |
| + "node": ">=14" | |
| + } | |
| + }, | |
| + "node_modules/@protobufjs/aspromise": { | |
| + "version": "1.1.2", | |
| + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", | |
| + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", | |
| + "license": "BSD-3-Clause" | |
| + }, | |
| + "node_modules/@protobufjs/base64": { | |
| + "version": "1.1.2", | |
| + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", | |
| + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", | |
| + "license": "BSD-3-Clause" | |
| + }, | |
| + "node_modules/@protobufjs/codegen": { | |
| + "version": "2.0.4", | |
| + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", | |
| + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", | |
| + "license": "BSD-3-Clause" | |
| + }, | |
| + "node_modules/@protobufjs/eventemitter": { | |
| + "version": "1.1.0", | |
| + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", | |
| + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", | |
| + "license": "BSD-3-Clause" | |
| + }, | |
| + "node_modules/@protobufjs/fetch": { | |
| + "version": "1.1.0", | |
| + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", | |
| + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", | |
| + "license": "BSD-3-Clause", | |
| + "dependencies": { | |
| + "@protobufjs/aspromise": "^1.1.1", | |
| + "@protobufjs/inquire": "^1.1.0" | |
| + } | |
| + }, | |
| + "node_modules/@protobufjs/float": { | |
| + "version": "1.0.2", | |
| + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", | |
| + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", | |
| + "license": "BSD-3-Clause" | |
| + }, | |
| + "node_modules/@protobufjs/inquire": { | |
| + "version": "1.1.0", | |
| + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", | |
| + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", | |
| + "license": "BSD-3-Clause" | |
| + }, | |
| + "node_modules/@protobufjs/path": { | |
| + "version": "1.1.2", | |
| + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", | |
| + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", | |
| + "license": "BSD-3-Clause" | |
| + }, | |
| + "node_modules/@protobufjs/pool": { | |
| + "version": "1.1.0", | |
| + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", | |
| + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", | |
| + "license": "BSD-3-Clause" | |
| + }, | |
| + "node_modules/@protobufjs/utf8": { | |
| + "version": "1.1.0", | |
| + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", | |
| + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", | |
| + "license": "BSD-3-Clause" | |
| + }, | |
| + "node_modules/@radix-ui/number": { | |
| + "version": "1.1.1", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", | |
| + "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==", | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/@radix-ui/primitive": { | |
| + "version": "1.1.3", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", | |
| + "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/@radix-ui/react-arrow": { | |
| + "version": "1.1.7", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", | |
| + "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@radix-ui/react-primitive": "2.1.3" | |
| + }, | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "@types/react-dom": "*", | |
| + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", | |
| + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + }, | |
| + "@types/react-dom": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/@radix-ui/react-collection": { | |
| + "version": "1.1.7", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", | |
| + "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@radix-ui/react-compose-refs": "1.1.2", | |
| + "@radix-ui/react-context": "1.1.2", | |
| + "@radix-ui/react-primitive": "2.1.3", | |
| + "@radix-ui/react-slot": "1.2.3" | |
| + }, | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "@types/react-dom": "*", | |
| + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", | |
| + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + }, | |
| + "@types/react-dom": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-slot": { | |
| + "version": "1.2.3", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", | |
| + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@radix-ui/react-compose-refs": "1.1.2" | |
| + }, | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/@radix-ui/react-compose-refs": { | |
| + "version": "1.1.2", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", | |
| + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", | |
| + "license": "MIT", | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/@radix-ui/react-context": { | |
| + "version": "1.1.2", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", | |
| + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", | |
| + "license": "MIT", | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/@radix-ui/react-dialog": { | |
| + "version": "1.1.15", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz", | |
| + "integrity": "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@radix-ui/primitive": "1.1.3", | |
| + "@radix-ui/react-compose-refs": "1.1.2", | |
| + "@radix-ui/react-context": "1.1.2", | |
| + "@radix-ui/react-dismissable-layer": "1.1.11", | |
| + "@radix-ui/react-focus-guards": "1.1.3", | |
| + "@radix-ui/react-focus-scope": "1.1.7", | |
| + "@radix-ui/react-id": "1.1.1", | |
| + "@radix-ui/react-portal": "1.1.9", | |
| + "@radix-ui/react-presence": "1.1.5", | |
| + "@radix-ui/react-primitive": "2.1.3", | |
| + "@radix-ui/react-slot": "1.2.3", | |
| + "@radix-ui/react-use-controllable-state": "1.2.2", | |
| + "aria-hidden": "^1.2.4", | |
| + "react-remove-scroll": "^2.6.3" | |
| + }, | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "@types/react-dom": "*", | |
| + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", | |
| + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + }, | |
| + "@types/react-dom": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-slot": { | |
| + "version": "1.2.3", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", | |
| + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@radix-ui/react-compose-refs": "1.1.2" | |
| + }, | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/@radix-ui/react-direction": { | |
| + "version": "1.1.1", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", | |
| + "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", | |
| + "license": "MIT", | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/@radix-ui/react-dismissable-layer": { | |
| + "version": "1.1.11", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz", | |
| + "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@radix-ui/primitive": "1.1.3", | |
| + "@radix-ui/react-compose-refs": "1.1.2", | |
| + "@radix-ui/react-primitive": "2.1.3", | |
| + "@radix-ui/react-use-callback-ref": "1.1.1", | |
| + "@radix-ui/react-use-escape-keydown": "1.1.1" | |
| + }, | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "@types/react-dom": "*", | |
| + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", | |
| + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + }, | |
| + "@types/react-dom": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/@radix-ui/react-dropdown-menu": { | |
| + "version": "2.1.16", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.16.tgz", | |
| + "integrity": "sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@radix-ui/primitive": "1.1.3", | |
| + "@radix-ui/react-compose-refs": "1.1.2", | |
| + "@radix-ui/react-context": "1.1.2", | |
| + "@radix-ui/react-id": "1.1.1", | |
| + "@radix-ui/react-menu": "2.1.16", | |
| + "@radix-ui/react-primitive": "2.1.3", | |
| + "@radix-ui/react-use-controllable-state": "1.2.2" | |
| + }, | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "@types/react-dom": "*", | |
| + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", | |
| + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + }, | |
| + "@types/react-dom": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/@radix-ui/react-focus-guards": { | |
| + "version": "1.1.3", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz", | |
| + "integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==", | |
| + "license": "MIT", | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/@radix-ui/react-focus-scope": { | |
| + "version": "1.1.7", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", | |
| + "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@radix-ui/react-compose-refs": "1.1.2", | |
| + "@radix-ui/react-primitive": "2.1.3", | |
| + "@radix-ui/react-use-callback-ref": "1.1.1" | |
| + }, | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "@types/react-dom": "*", | |
| + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", | |
| + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + }, | |
| + "@types/react-dom": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/@radix-ui/react-id": { | |
| + "version": "1.1.1", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", | |
| + "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@radix-ui/react-use-layout-effect": "1.1.1" | |
| + }, | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/@radix-ui/react-label": { | |
| + "version": "2.1.8", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.8.tgz", | |
| + "integrity": "sha512-FmXs37I6hSBVDlO4y764TNz1rLgKwjJMQ0EGte6F3Cb3f4bIuHB/iLa/8I9VKkmOy+gNHq8rql3j686ACVV21A==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@radix-ui/react-primitive": "2.1.4" | |
| + }, | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "@types/react-dom": "*", | |
| + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", | |
| + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + }, | |
| + "@types/react-dom": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/@radix-ui/react-label/node_modules/@radix-ui/react-primitive": { | |
| + "version": "2.1.4", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", | |
| + "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@radix-ui/react-slot": "1.2.4" | |
| + }, | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "@types/react-dom": "*", | |
| + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", | |
| + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + }, | |
| + "@types/react-dom": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/@radix-ui/react-menu": { | |
| + "version": "2.1.16", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.16.tgz", | |
| + "integrity": "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@radix-ui/primitive": "1.1.3", | |
| + "@radix-ui/react-collection": "1.1.7", | |
| + "@radix-ui/react-compose-refs": "1.1.2", | |
| + "@radix-ui/react-context": "1.1.2", | |
| + "@radix-ui/react-direction": "1.1.1", | |
| + "@radix-ui/react-dismissable-layer": "1.1.11", | |
| + "@radix-ui/react-focus-guards": "1.1.3", | |
| + "@radix-ui/react-focus-scope": "1.1.7", | |
| + "@radix-ui/react-id": "1.1.1", | |
| + "@radix-ui/react-popper": "1.2.8", | |
| + "@radix-ui/react-portal": "1.1.9", | |
| + "@radix-ui/react-presence": "1.1.5", | |
| + "@radix-ui/react-primitive": "2.1.3", | |
| + "@radix-ui/react-roving-focus": "1.1.11", | |
| + "@radix-ui/react-slot": "1.2.3", | |
| + "@radix-ui/react-use-callback-ref": "1.1.1", | |
| + "aria-hidden": "^1.2.4", | |
| + "react-remove-scroll": "^2.6.3" | |
| + }, | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "@types/react-dom": "*", | |
| + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", | |
| + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + }, | |
| + "@types/react-dom": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-slot": { | |
| + "version": "1.2.3", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", | |
| + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@radix-ui/react-compose-refs": "1.1.2" | |
| + }, | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/@radix-ui/react-popper": { | |
| + "version": "1.2.8", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz", | |
| + "integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@floating-ui/react-dom": "^2.0.0", | |
| + "@radix-ui/react-arrow": "1.1.7", | |
| + "@radix-ui/react-compose-refs": "1.1.2", | |
| + "@radix-ui/react-context": "1.1.2", | |
| + "@radix-ui/react-primitive": "2.1.3", | |
| + "@radix-ui/react-use-callback-ref": "1.1.1", | |
| + "@radix-ui/react-use-layout-effect": "1.1.1", | |
| + "@radix-ui/react-use-rect": "1.1.1", | |
| + "@radix-ui/react-use-size": "1.1.1", | |
| + "@radix-ui/rect": "1.1.1" | |
| + }, | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "@types/react-dom": "*", | |
| + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", | |
| + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + }, | |
| + "@types/react-dom": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/@radix-ui/react-portal": { | |
| + "version": "1.1.9", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", | |
| + "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@radix-ui/react-primitive": "2.1.3", | |
| + "@radix-ui/react-use-layout-effect": "1.1.1" | |
| + }, | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "@types/react-dom": "*", | |
| + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", | |
| + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + }, | |
| + "@types/react-dom": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/@radix-ui/react-presence": { | |
| + "version": "1.1.5", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", | |
| + "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@radix-ui/react-compose-refs": "1.1.2", | |
| + "@radix-ui/react-use-layout-effect": "1.1.1" | |
| + }, | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "@types/react-dom": "*", | |
| + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", | |
| + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + }, | |
| + "@types/react-dom": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/@radix-ui/react-primitive": { | |
| + "version": "2.1.3", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", | |
| + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@radix-ui/react-slot": "1.2.3" | |
| + }, | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "@types/react-dom": "*", | |
| + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", | |
| + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + }, | |
| + "@types/react-dom": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/@radix-ui/react-primitive/node_modules/@radix-ui/react-slot": { | |
| + "version": "1.2.3", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", | |
| + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@radix-ui/react-compose-refs": "1.1.2" | |
| + }, | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/@radix-ui/react-roving-focus": { | |
| + "version": "1.1.11", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz", | |
| + "integrity": "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@radix-ui/primitive": "1.1.3", | |
| + "@radix-ui/react-collection": "1.1.7", | |
| + "@radix-ui/react-compose-refs": "1.1.2", | |
| + "@radix-ui/react-context": "1.1.2", | |
| + "@radix-ui/react-direction": "1.1.1", | |
| + "@radix-ui/react-id": "1.1.1", | |
| + "@radix-ui/react-primitive": "2.1.3", | |
| + "@radix-ui/react-use-callback-ref": "1.1.1", | |
| + "@radix-ui/react-use-controllable-state": "1.2.2" | |
| + }, | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "@types/react-dom": "*", | |
| + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", | |
| + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + }, | |
| + "@types/react-dom": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/@radix-ui/react-scroll-area": { | |
| + "version": "1.2.10", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.10.tgz", | |
| + "integrity": "sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@radix-ui/number": "1.1.1", | |
| + "@radix-ui/primitive": "1.1.3", | |
| + "@radix-ui/react-compose-refs": "1.1.2", | |
| + "@radix-ui/react-context": "1.1.2", | |
| + "@radix-ui/react-direction": "1.1.1", | |
| + "@radix-ui/react-presence": "1.1.5", | |
| + "@radix-ui/react-primitive": "2.1.3", | |
| + "@radix-ui/react-use-callback-ref": "1.1.1", | |
| + "@radix-ui/react-use-layout-effect": "1.1.1" | |
| + }, | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "@types/react-dom": "*", | |
| + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", | |
| + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + }, | |
| + "@types/react-dom": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/@radix-ui/react-slot": { | |
| + "version": "1.2.4", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.4.tgz", | |
| + "integrity": "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@radix-ui/react-compose-refs": "1.1.2" | |
| + }, | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/@radix-ui/react-switch": { | |
| + "version": "1.2.6", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.2.6.tgz", | |
| + "integrity": "sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@radix-ui/primitive": "1.1.3", | |
| + "@radix-ui/react-compose-refs": "1.1.2", | |
| + "@radix-ui/react-context": "1.1.2", | |
| + "@radix-ui/react-primitive": "2.1.3", | |
| + "@radix-ui/react-use-controllable-state": "1.2.2", | |
| + "@radix-ui/react-use-previous": "1.1.1", | |
| + "@radix-ui/react-use-size": "1.1.1" | |
| + }, | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "@types/react-dom": "*", | |
| + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", | |
| + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + }, | |
| + "@types/react-dom": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/@radix-ui/react-tabs": { | |
| + "version": "1.1.13", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.13.tgz", | |
| + "integrity": "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@radix-ui/primitive": "1.1.3", | |
| + "@radix-ui/react-context": "1.1.2", | |
| + "@radix-ui/react-direction": "1.1.1", | |
| + "@radix-ui/react-id": "1.1.1", | |
| + "@radix-ui/react-presence": "1.1.5", | |
| + "@radix-ui/react-primitive": "2.1.3", | |
| + "@radix-ui/react-roving-focus": "1.1.11", | |
| + "@radix-ui/react-use-controllable-state": "1.2.2" | |
| + }, | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "@types/react-dom": "*", | |
| + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", | |
| + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + }, | |
| + "@types/react-dom": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/@radix-ui/react-toast": { | |
| + "version": "1.2.15", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.2.15.tgz", | |
| + "integrity": "sha512-3OSz3TacUWy4WtOXV38DggwxoqJK4+eDkNMl5Z/MJZaoUPaP4/9lf81xXMe1I2ReTAptverZUpbPY4wWwWyL5g==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@radix-ui/primitive": "1.1.3", | |
| + "@radix-ui/react-collection": "1.1.7", | |
| + "@radix-ui/react-compose-refs": "1.1.2", | |
| + "@radix-ui/react-context": "1.1.2", | |
| + "@radix-ui/react-dismissable-layer": "1.1.11", | |
| + "@radix-ui/react-portal": "1.1.9", | |
| + "@radix-ui/react-presence": "1.1.5", | |
| + "@radix-ui/react-primitive": "2.1.3", | |
| + "@radix-ui/react-use-callback-ref": "1.1.1", | |
| + "@radix-ui/react-use-controllable-state": "1.2.2", | |
| + "@radix-ui/react-use-layout-effect": "1.1.1", | |
| + "@radix-ui/react-visually-hidden": "1.2.3" | |
| + }, | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "@types/react-dom": "*", | |
| + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", | |
| + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + }, | |
| + "@types/react-dom": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/@radix-ui/react-tooltip": { | |
| + "version": "1.2.8", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.8.tgz", | |
| + "integrity": "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@radix-ui/primitive": "1.1.3", | |
| + "@radix-ui/react-compose-refs": "1.1.2", | |
| + "@radix-ui/react-context": "1.1.2", | |
| + "@radix-ui/react-dismissable-layer": "1.1.11", | |
| + "@radix-ui/react-id": "1.1.1", | |
| + "@radix-ui/react-popper": "1.2.8", | |
| + "@radix-ui/react-portal": "1.1.9", | |
| + "@radix-ui/react-presence": "1.1.5", | |
| + "@radix-ui/react-primitive": "2.1.3", | |
| + "@radix-ui/react-slot": "1.2.3", | |
| + "@radix-ui/react-use-controllable-state": "1.2.2", | |
| + "@radix-ui/react-visually-hidden": "1.2.3" | |
| + }, | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "@types/react-dom": "*", | |
| + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", | |
| + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + }, | |
| + "@types/react-dom": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-slot": { | |
| + "version": "1.2.3", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", | |
| + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@radix-ui/react-compose-refs": "1.1.2" | |
| + }, | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/@radix-ui/react-use-callback-ref": { | |
| + "version": "1.1.1", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", | |
| + "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", | |
| + "license": "MIT", | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/@radix-ui/react-use-controllable-state": { | |
| + "version": "1.2.2", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", | |
| + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@radix-ui/react-use-effect-event": "0.0.2", | |
| + "@radix-ui/react-use-layout-effect": "1.1.1" | |
| + }, | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/@radix-ui/react-use-effect-event": { | |
| + "version": "0.0.2", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", | |
| + "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@radix-ui/react-use-layout-effect": "1.1.1" | |
| + }, | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/@radix-ui/react-use-escape-keydown": { | |
| + "version": "1.1.1", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz", | |
| + "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@radix-ui/react-use-callback-ref": "1.1.1" | |
| + }, | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/@radix-ui/react-use-layout-effect": { | |
| + "version": "1.1.1", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", | |
| + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", | |
| + "license": "MIT", | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/@radix-ui/react-use-previous": { | |
| + "version": "1.1.1", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz", | |
| + "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==", | |
| + "license": "MIT", | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/@radix-ui/react-use-rect": { | |
| + "version": "1.1.1", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz", | |
| + "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@radix-ui/rect": "1.1.1" | |
| + }, | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/@radix-ui/react-use-size": { | |
| + "version": "1.1.1", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz", | |
| + "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@radix-ui/react-use-layout-effect": "1.1.1" | |
| + }, | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/@radix-ui/react-visually-hidden": { | |
| + "version": "1.2.3", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", | |
| + "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@radix-ui/react-primitive": "2.1.3" | |
| + }, | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "@types/react-dom": "*", | |
| + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", | |
| + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + }, | |
| + "@types/react-dom": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/@radix-ui/rect": { | |
| + "version": "1.1.1", | |
| + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz", | |
| + "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/@rtsao/scc": { | |
| + "version": "1.1.0", | |
| + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", | |
| + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", | |
| + "dev": true, | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/@rushstack/eslint-patch": { | |
| + "version": "1.15.0", | |
| + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.15.0.tgz", | |
| + "integrity": "sha512-ojSshQPKwVvSMR8yT2L/QtUkV5SXi/IfDiJ4/8d6UbTPjiHVmxZzUAzGD8Tzks1b9+qQkZa0isUOvYObedITaw==", | |
| + "dev": true, | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/@spz-loader/core": { | |
| + "version": "0.3.0", | |
| + "resolved": "https://registry.npmjs.org/@spz-loader/core/-/core-0.3.0.tgz", | |
| + "integrity": "sha512-sbStwMHb/MIE29st7rRuMYWqhX1UmLSFzdpyGtUZUXLkFNIuYKblzjQdtiet8bau8sUf21uL1DQ451zuySGmcA==", | |
| + "license": "Apache-2.0", | |
| + "engines": { | |
| + "node": ">=16", | |
| + "pnpm": ">=8" | |
| + } | |
| + }, | |
| + "node_modules/@swc/counter": { | |
| + "version": "0.1.3", | |
| + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", | |
| + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", | |
| + "license": "Apache-2.0" | |
| + }, | |
| + "node_modules/@swc/helpers": { | |
| + "version": "0.5.5", | |
| + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.5.tgz", | |
| + "integrity": "sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==", | |
| + "license": "Apache-2.0", | |
| + "dependencies": { | |
| + "@swc/counter": "^0.1.3", | |
| + "tslib": "^2.4.0" | |
| + } | |
| + }, | |
| + "node_modules/@tweenjs/tween.js": { | |
| + "version": "25.0.0", | |
| + "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-25.0.0.tgz", | |
| + "integrity": "sha512-XKLA6syeBUaPzx4j3qwMqzzq+V4uo72BnlbOjmuljLrRqdsd3qnzvZZoxvMHZ23ndsRS4aufU6JOZYpCbU6T1A==", | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/@tybys/wasm-util": { | |
| + "version": "0.10.1", | |
| + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", | |
| + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "optional": true, | |
| + "dependencies": { | |
| + "tslib": "^2.4.0" | |
| + } | |
| + }, | |
| + "node_modules/@types/json5": { | |
| + "version": "0.0.29", | |
| + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", | |
| + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", | |
| + "dev": true, | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/@types/node": { | |
| + "version": "22.19.8", | |
| + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.8.tgz", | |
| + "integrity": "sha512-ebO/Yl+EAvVe8DnMfi+iaAyIqYdK0q/q0y0rw82INWEKJOBe6b/P3YWE8NW7oOlF/nXFNrHwhARrN/hdgDkraA==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "undici-types": "~6.21.0" | |
| + } | |
| + }, | |
| + "node_modules/@types/prop-types": { | |
| + "version": "15.7.15", | |
| + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", | |
| + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", | |
| + "devOptional": true, | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/@types/react": { | |
| + "version": "18.3.27", | |
| + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.27.tgz", | |
| + "integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==", | |
| + "devOptional": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@types/prop-types": "*", | |
| + "csstype": "^3.2.2" | |
| + } | |
| + }, | |
| + "node_modules/@types/react-dom": { | |
| + "version": "18.3.7", | |
| + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", | |
| + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", | |
| + "devOptional": true, | |
| + "license": "MIT", | |
| + "peerDependencies": { | |
| + "@types/react": "^18.0.0" | |
| + } | |
| + }, | |
| + "node_modules/@types/trusted-types": { | |
| + "version": "2.0.7", | |
| + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", | |
| + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", | |
| + "license": "MIT", | |
| + "optional": true | |
| + }, | |
| + "node_modules/@typescript-eslint/eslint-plugin": { | |
| + "version": "8.54.0", | |
| + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.54.0.tgz", | |
| + "integrity": "sha512-hAAP5io/7csFStuOmR782YmTthKBJ9ND3WVL60hcOjvtGFb+HJxH4O5huAcmcZ9v9G8P+JETiZ/G1B8MALnWZQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@eslint-community/regexpp": "^4.12.2", | |
| + "@typescript-eslint/scope-manager": "8.54.0", | |
| + "@typescript-eslint/type-utils": "8.54.0", | |
| + "@typescript-eslint/utils": "8.54.0", | |
| + "@typescript-eslint/visitor-keys": "8.54.0", | |
| + "ignore": "^7.0.5", | |
| + "natural-compare": "^1.4.0", | |
| + "ts-api-utils": "^2.4.0" | |
| + }, | |
| + "engines": { | |
| + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" | |
| + }, | |
| + "funding": { | |
| + "type": "opencollective", | |
| + "url": "https://opencollective.com/typescript-eslint" | |
| + }, | |
| + "peerDependencies": { | |
| + "@typescript-eslint/parser": "^8.54.0", | |
| + "eslint": "^8.57.0 || ^9.0.0", | |
| + "typescript": ">=4.8.4 <6.0.0" | |
| + } | |
| + }, | |
| + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { | |
| + "version": "7.0.5", | |
| + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", | |
| + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">= 4" | |
| + } | |
| + }, | |
| + "node_modules/@typescript-eslint/parser": { | |
| + "version": "8.54.0", | |
| + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.54.0.tgz", | |
| + "integrity": "sha512-BtE0k6cjwjLZoZixN0t5AKP0kSzlGu7FctRXYuPAm//aaiZhmfq1JwdYpYr1brzEspYyFeF+8XF5j2VK6oalrA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@typescript-eslint/scope-manager": "8.54.0", | |
| + "@typescript-eslint/types": "8.54.0", | |
| + "@typescript-eslint/typescript-estree": "8.54.0", | |
| + "@typescript-eslint/visitor-keys": "8.54.0", | |
| + "debug": "^4.4.3" | |
| + }, | |
| + "engines": { | |
| + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" | |
| + }, | |
| + "funding": { | |
| + "type": "opencollective", | |
| + "url": "https://opencollective.com/typescript-eslint" | |
| + }, | |
| + "peerDependencies": { | |
| + "eslint": "^8.57.0 || ^9.0.0", | |
| + "typescript": ">=4.8.4 <6.0.0" | |
| + } | |
| + }, | |
| + "node_modules/@typescript-eslint/project-service": { | |
| + "version": "8.54.0", | |
| + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.54.0.tgz", | |
| + "integrity": "sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@typescript-eslint/tsconfig-utils": "^8.54.0", | |
| + "@typescript-eslint/types": "^8.54.0", | |
| + "debug": "^4.4.3" | |
| + }, | |
| + "engines": { | |
| + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" | |
| + }, | |
| + "funding": { | |
| + "type": "opencollective", | |
| + "url": "https://opencollective.com/typescript-eslint" | |
| + }, | |
| + "peerDependencies": { | |
| + "typescript": ">=4.8.4 <6.0.0" | |
| + } | |
| + }, | |
| + "node_modules/@typescript-eslint/scope-manager": { | |
| + "version": "8.54.0", | |
| + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.54.0.tgz", | |
| + "integrity": "sha512-27rYVQku26j/PbHYcVfRPonmOlVI6gihHtXFbTdB5sb6qA0wdAQAbyXFVarQ5t4HRojIz64IV90YtsjQSSGlQg==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@typescript-eslint/types": "8.54.0", | |
| + "@typescript-eslint/visitor-keys": "8.54.0" | |
| + }, | |
| + "engines": { | |
| + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" | |
| + }, | |
| + "funding": { | |
| + "type": "opencollective", | |
| + "url": "https://opencollective.com/typescript-eslint" | |
| + } | |
| + }, | |
| + "node_modules/@typescript-eslint/tsconfig-utils": { | |
| + "version": "8.54.0", | |
| + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.54.0.tgz", | |
| + "integrity": "sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" | |
| + }, | |
| + "funding": { | |
| + "type": "opencollective", | |
| + "url": "https://opencollective.com/typescript-eslint" | |
| + }, | |
| + "peerDependencies": { | |
| + "typescript": ">=4.8.4 <6.0.0" | |
| + } | |
| + }, | |
| + "node_modules/@typescript-eslint/type-utils": { | |
| + "version": "8.54.0", | |
| + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.54.0.tgz", | |
| + "integrity": "sha512-hiLguxJWHjjwL6xMBwD903ciAwd7DmK30Y9Axs/etOkftC3ZNN9K44IuRD/EB08amu+Zw6W37x9RecLkOo3pMA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@typescript-eslint/types": "8.54.0", | |
| + "@typescript-eslint/typescript-estree": "8.54.0", | |
| + "@typescript-eslint/utils": "8.54.0", | |
| + "debug": "^4.4.3", | |
| + "ts-api-utils": "^2.4.0" | |
| + }, | |
| + "engines": { | |
| + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" | |
| + }, | |
| + "funding": { | |
| + "type": "opencollective", | |
| + "url": "https://opencollective.com/typescript-eslint" | |
| + }, | |
| + "peerDependencies": { | |
| + "eslint": "^8.57.0 || ^9.0.0", | |
| + "typescript": ">=4.8.4 <6.0.0" | |
| + } | |
| + }, | |
| + "node_modules/@typescript-eslint/types": { | |
| + "version": "8.54.0", | |
| + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.54.0.tgz", | |
| + "integrity": "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" | |
| + }, | |
| + "funding": { | |
| + "type": "opencollective", | |
| + "url": "https://opencollective.com/typescript-eslint" | |
| + } | |
| + }, | |
| + "node_modules/@typescript-eslint/typescript-estree": { | |
| + "version": "8.54.0", | |
| + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.54.0.tgz", | |
| + "integrity": "sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@typescript-eslint/project-service": "8.54.0", | |
| + "@typescript-eslint/tsconfig-utils": "8.54.0", | |
| + "@typescript-eslint/types": "8.54.0", | |
| + "@typescript-eslint/visitor-keys": "8.54.0", | |
| + "debug": "^4.4.3", | |
| + "minimatch": "^9.0.5", | |
| + "semver": "^7.7.3", | |
| + "tinyglobby": "^0.2.15", | |
| + "ts-api-utils": "^2.4.0" | |
| + }, | |
| + "engines": { | |
| + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" | |
| + }, | |
| + "funding": { | |
| + "type": "opencollective", | |
| + "url": "https://opencollective.com/typescript-eslint" | |
| + }, | |
| + "peerDependencies": { | |
| + "typescript": ">=4.8.4 <6.0.0" | |
| + } | |
| + }, | |
| + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { | |
| + "version": "2.0.2", | |
| + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", | |
| + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "balanced-match": "^1.0.0" | |
| + } | |
| + }, | |
| + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { | |
| + "version": "9.0.5", | |
| + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", | |
| + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", | |
| + "dev": true, | |
| + "license": "ISC", | |
| + "dependencies": { | |
| + "brace-expansion": "^2.0.1" | |
| + }, | |
| + "engines": { | |
| + "node": ">=16 || 14 >=14.17" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/isaacs" | |
| + } | |
| + }, | |
| + "node_modules/@typescript-eslint/utils": { | |
| + "version": "8.54.0", | |
| + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.54.0.tgz", | |
| + "integrity": "sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@eslint-community/eslint-utils": "^4.9.1", | |
| + "@typescript-eslint/scope-manager": "8.54.0", | |
| + "@typescript-eslint/types": "8.54.0", | |
| + "@typescript-eslint/typescript-estree": "8.54.0" | |
| + }, | |
| + "engines": { | |
| + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" | |
| + }, | |
| + "funding": { | |
| + "type": "opencollective", | |
| + "url": "https://opencollective.com/typescript-eslint" | |
| + }, | |
| + "peerDependencies": { | |
| + "eslint": "^8.57.0 || ^9.0.0", | |
| + "typescript": ">=4.8.4 <6.0.0" | |
| + } | |
| + }, | |
| + "node_modules/@typescript-eslint/visitor-keys": { | |
| + "version": "8.54.0", | |
| + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.54.0.tgz", | |
| + "integrity": "sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@typescript-eslint/types": "8.54.0", | |
| + "eslint-visitor-keys": "^4.2.1" | |
| + }, | |
| + "engines": { | |
| + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" | |
| + }, | |
| + "funding": { | |
| + "type": "opencollective", | |
| + "url": "https://opencollective.com/typescript-eslint" | |
| + } | |
| + }, | |
| + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { | |
| + "version": "4.2.1", | |
| + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", | |
| + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", | |
| + "dev": true, | |
| + "license": "Apache-2.0", | |
| + "engines": { | |
| + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" | |
| + }, | |
| + "funding": { | |
| + "url": "https://opencollective.com/eslint" | |
| + } | |
| + }, | |
| + "node_modules/@ungap/structured-clone": { | |
| + "version": "1.3.0", | |
| + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", | |
| + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", | |
| + "dev": true, | |
| + "license": "ISC" | |
| + }, | |
| + "node_modules/@unrs/resolver-binding-android-arm-eabi": { | |
| + "version": "1.11.1", | |
| + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz", | |
| + "integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==", | |
| + "cpu": [ | |
| + "arm" | |
| + ], | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "optional": true, | |
| + "os": [ | |
| + "android" | |
| + ] | |
| + }, | |
| + "node_modules/@unrs/resolver-binding-android-arm64": { | |
| + "version": "1.11.1", | |
| + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz", | |
| + "integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==", | |
| + "cpu": [ | |
| + "arm64" | |
| + ], | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "optional": true, | |
| + "os": [ | |
| + "android" | |
| + ] | |
| + }, | |
| + "node_modules/@unrs/resolver-binding-darwin-arm64": { | |
| + "version": "1.11.1", | |
| + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz", | |
| + "integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==", | |
| + "cpu": [ | |
| + "arm64" | |
| + ], | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "optional": true, | |
| + "os": [ | |
| + "darwin" | |
| + ] | |
| + }, | |
| + "node_modules/@unrs/resolver-binding-darwin-x64": { | |
| + "version": "1.11.1", | |
| + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz", | |
| + "integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==", | |
| + "cpu": [ | |
| + "x64" | |
| + ], | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "optional": true, | |
| + "os": [ | |
| + "darwin" | |
| + ] | |
| + }, | |
| + "node_modules/@unrs/resolver-binding-freebsd-x64": { | |
| + "version": "1.11.1", | |
| + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz", | |
| + "integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==", | |
| + "cpu": [ | |
| + "x64" | |
| + ], | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "optional": true, | |
| + "os": [ | |
| + "freebsd" | |
| + ] | |
| + }, | |
| + "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { | |
| + "version": "1.11.1", | |
| + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz", | |
| + "integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==", | |
| + "cpu": [ | |
| + "arm" | |
| + ], | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "optional": true, | |
| + "os": [ | |
| + "linux" | |
| + ] | |
| + }, | |
| + "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { | |
| + "version": "1.11.1", | |
| + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz", | |
| + "integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==", | |
| + "cpu": [ | |
| + "arm" | |
| + ], | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "optional": true, | |
| + "os": [ | |
| + "linux" | |
| + ] | |
| + }, | |
| + "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { | |
| + "version": "1.11.1", | |
| + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz", | |
| + "integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==", | |
| + "cpu": [ | |
| + "arm64" | |
| + ], | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "optional": true, | |
| + "os": [ | |
| + "linux" | |
| + ] | |
| + }, | |
| + "node_modules/@unrs/resolver-binding-linux-arm64-musl": { | |
| + "version": "1.11.1", | |
| + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz", | |
| + "integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==", | |
| + "cpu": [ | |
| + "arm64" | |
| + ], | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "optional": true, | |
| + "os": [ | |
| + "linux" | |
| + ] | |
| + }, | |
| + "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { | |
| + "version": "1.11.1", | |
| + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz", | |
| + "integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==", | |
| + "cpu": [ | |
| + "ppc64" | |
| + ], | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "optional": true, | |
| + "os": [ | |
| + "linux" | |
| + ] | |
| + }, | |
| + "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { | |
| + "version": "1.11.1", | |
| + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz", | |
| + "integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==", | |
| + "cpu": [ | |
| + "riscv64" | |
| + ], | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "optional": true, | |
| + "os": [ | |
| + "linux" | |
| + ] | |
| + }, | |
| + "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { | |
| + "version": "1.11.1", | |
| + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz", | |
| + "integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==", | |
| + "cpu": [ | |
| + "riscv64" | |
| + ], | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "optional": true, | |
| + "os": [ | |
| + "linux" | |
| + ] | |
| + }, | |
| + "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { | |
| + "version": "1.11.1", | |
| + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz", | |
| + "integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==", | |
| + "cpu": [ | |
| + "s390x" | |
| + ], | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "optional": true, | |
| + "os": [ | |
| + "linux" | |
| + ] | |
| + }, | |
| + "node_modules/@unrs/resolver-binding-linux-x64-gnu": { | |
| + "version": "1.11.1", | |
| + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz", | |
| + "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==", | |
| + "cpu": [ | |
| + "x64" | |
| + ], | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "optional": true, | |
| + "os": [ | |
| + "linux" | |
| + ] | |
| + }, | |
| + "node_modules/@unrs/resolver-binding-linux-x64-musl": { | |
| + "version": "1.11.1", | |
| + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz", | |
| + "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==", | |
| + "cpu": [ | |
| + "x64" | |
| + ], | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "optional": true, | |
| + "os": [ | |
| + "linux" | |
| + ] | |
| + }, | |
| + "node_modules/@unrs/resolver-binding-wasm32-wasi": { | |
| + "version": "1.11.1", | |
| + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz", | |
| + "integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==", | |
| + "cpu": [ | |
| + "wasm32" | |
| + ], | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "optional": true, | |
| + "dependencies": { | |
| + "@napi-rs/wasm-runtime": "^0.2.11" | |
| + }, | |
| + "engines": { | |
| + "node": ">=14.0.0" | |
| + } | |
| + }, | |
| + "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { | |
| + "version": "1.11.1", | |
| + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz", | |
| + "integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==", | |
| + "cpu": [ | |
| + "arm64" | |
| + ], | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "optional": true, | |
| + "os": [ | |
| + "win32" | |
| + ] | |
| + }, | |
| + "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { | |
| + "version": "1.11.1", | |
| + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz", | |
| + "integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==", | |
| + "cpu": [ | |
| + "ia32" | |
| + ], | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "optional": true, | |
| + "os": [ | |
| + "win32" | |
| + ] | |
| + }, | |
| + "node_modules/@unrs/resolver-binding-win32-x64-msvc": { | |
| + "version": "1.11.1", | |
| + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz", | |
| + "integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==", | |
| + "cpu": [ | |
| + "x64" | |
| + ], | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "optional": true, | |
| + "os": [ | |
| + "win32" | |
| + ] | |
| + }, | |
| + "node_modules/@zip.js/zip.js": { | |
| + "version": "2.8.16", | |
| + "resolved": "https://registry.npmjs.org/@zip.js/zip.js/-/zip.js-2.8.16.tgz", | |
| + "integrity": "sha512-kCjaXh50GCf9afcof6ekjXPKR//rBVIxNHJLSUaM3VAET2F0+hymgrK1GpInRIIFUpt+wsnUfgx2+bbrmc+7Tw==", | |
| + "license": "BSD-3-Clause", | |
| + "engines": { | |
| + "bun": ">=0.7.0", | |
| + "deno": ">=1.0.0", | |
| + "node": ">=18.0.0" | |
| + } | |
| + }, | |
| + "node_modules/acorn": { | |
| + "version": "8.15.0", | |
| + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", | |
| + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "bin": { | |
| + "acorn": "bin/acorn" | |
| + }, | |
| + "engines": { | |
| + "node": ">=0.4.0" | |
| + } | |
| + }, | |
| + "node_modules/acorn-jsx": { | |
| + "version": "5.3.2", | |
| + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", | |
| + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "peerDependencies": { | |
| + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" | |
| + } | |
| + }, | |
| + "node_modules/ajv": { | |
| + "version": "6.12.6", | |
| + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", | |
| + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "fast-deep-equal": "^3.1.1", | |
| + "fast-json-stable-stringify": "^2.0.0", | |
| + "json-schema-traverse": "^0.4.1", | |
| + "uri-js": "^4.2.2" | |
| + }, | |
| + "funding": { | |
| + "type": "github", | |
| + "url": "https://github.com/sponsors/epoberezkin" | |
| + } | |
| + }, | |
| + "node_modules/ansi-regex": { | |
| + "version": "5.0.1", | |
| + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", | |
| + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=8" | |
| + } | |
| + }, | |
| + "node_modules/ansi-styles": { | |
| + "version": "4.3.0", | |
| + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", | |
| + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "color-convert": "^2.0.1" | |
| + }, | |
| + "engines": { | |
| + "node": ">=8" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/chalk/ansi-styles?sponsor=1" | |
| + } | |
| + }, | |
| + "node_modules/any-promise": { | |
| + "version": "1.3.0", | |
| + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", | |
| + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/anymatch": { | |
| + "version": "3.1.3", | |
| + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", | |
| + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", | |
| + "license": "ISC", | |
| + "dependencies": { | |
| + "normalize-path": "^3.0.0", | |
| + "picomatch": "^2.0.4" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 8" | |
| + } | |
| + }, | |
| + "node_modules/arg": { | |
| + "version": "5.0.2", | |
| + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", | |
| + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/argparse": { | |
| + "version": "2.0.1", | |
| + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", | |
| + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", | |
| + "dev": true, | |
| + "license": "Python-2.0" | |
| + }, | |
| + "node_modules/aria-hidden": { | |
| + "version": "1.2.6", | |
| + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", | |
| + "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "tslib": "^2.0.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">=10" | |
| + } | |
| + }, | |
| + "node_modules/aria-query": { | |
| + "version": "5.3.2", | |
| + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", | |
| + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", | |
| + "dev": true, | |
| + "license": "Apache-2.0", | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + } | |
| + }, | |
| + "node_modules/array-buffer-byte-length": { | |
| + "version": "1.0.2", | |
| + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", | |
| + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bound": "^1.0.3", | |
| + "is-array-buffer": "^3.0.5" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/array-includes": { | |
| + "version": "3.1.9", | |
| + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", | |
| + "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bind": "^1.0.8", | |
| + "call-bound": "^1.0.4", | |
| + "define-properties": "^1.2.1", | |
| + "es-abstract": "^1.24.0", | |
| + "es-object-atoms": "^1.1.1", | |
| + "get-intrinsic": "^1.3.0", | |
| + "is-string": "^1.1.1", | |
| + "math-intrinsics": "^1.1.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/array.prototype.findlast": { | |
| + "version": "1.2.5", | |
| + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", | |
| + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bind": "^1.0.7", | |
| + "define-properties": "^1.2.1", | |
| + "es-abstract": "^1.23.2", | |
| + "es-errors": "^1.3.0", | |
| + "es-object-atoms": "^1.0.0", | |
| + "es-shim-unscopables": "^1.0.2" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/array.prototype.findlastindex": { | |
| + "version": "1.2.6", | |
| + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", | |
| + "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bind": "^1.0.8", | |
| + "call-bound": "^1.0.4", | |
| + "define-properties": "^1.2.1", | |
| + "es-abstract": "^1.23.9", | |
| + "es-errors": "^1.3.0", | |
| + "es-object-atoms": "^1.1.1", | |
| + "es-shim-unscopables": "^1.1.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/array.prototype.flat": { | |
| + "version": "1.3.3", | |
| + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", | |
| + "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bind": "^1.0.8", | |
| + "define-properties": "^1.2.1", | |
| + "es-abstract": "^1.23.5", | |
| + "es-shim-unscopables": "^1.0.2" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/array.prototype.flatmap": { | |
| + "version": "1.3.3", | |
| + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", | |
| + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bind": "^1.0.8", | |
| + "define-properties": "^1.2.1", | |
| + "es-abstract": "^1.23.5", | |
| + "es-shim-unscopables": "^1.0.2" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/array.prototype.tosorted": { | |
| + "version": "1.1.4", | |
| + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", | |
| + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bind": "^1.0.7", | |
| + "define-properties": "^1.2.1", | |
| + "es-abstract": "^1.23.3", | |
| + "es-errors": "^1.3.0", | |
| + "es-shim-unscopables": "^1.0.2" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + } | |
| + }, | |
| + "node_modules/arraybuffer.prototype.slice": { | |
| + "version": "1.0.4", | |
| + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", | |
| + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "array-buffer-byte-length": "^1.0.1", | |
| + "call-bind": "^1.0.8", | |
| + "define-properties": "^1.2.1", | |
| + "es-abstract": "^1.23.5", | |
| + "es-errors": "^1.3.0", | |
| + "get-intrinsic": "^1.2.6", | |
| + "is-array-buffer": "^3.0.4" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/ast-types-flow": { | |
| + "version": "0.0.8", | |
| + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", | |
| + "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", | |
| + "dev": true, | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/async-function": { | |
| + "version": "1.0.0", | |
| + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", | |
| + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + } | |
| + }, | |
| + "node_modules/autolinker": { | |
| + "version": "4.1.5", | |
| + "resolved": "https://registry.npmjs.org/autolinker/-/autolinker-4.1.5.tgz", | |
| + "integrity": "sha512-vEfYZPmvVOIuE567XBVCsx8SBgOYtjB2+S1iAaJ+HgH+DNjAcrHem2hmAeC9yaNGWayicv4yR+9UaJlkF3pvtw==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "tslib": "^2.8.1" | |
| + }, | |
| + "engines": { | |
| + "pnpm": ">=10.10.0" | |
| + } | |
| + }, | |
| + "node_modules/autoprefixer": { | |
| + "version": "10.4.24", | |
| + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.24.tgz", | |
| + "integrity": "sha512-uHZg7N9ULTVbutaIsDRoUkoS8/h3bdsmVJYZ5l3wv8Cp/6UIIoRDm90hZ+BwxUj/hGBEzLxdHNSKuFpn8WOyZw==", | |
| + "dev": true, | |
| + "funding": [ | |
| + { | |
| + "type": "opencollective", | |
| + "url": "https://opencollective.com/postcss/" | |
| + }, | |
| + { | |
| + "type": "tidelift", | |
| + "url": "https://tidelift.com/funding/github/npm/autoprefixer" | |
| + }, | |
| + { | |
| + "type": "github", | |
| + "url": "https://github.com/sponsors/ai" | |
| + } | |
| + ], | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "browserslist": "^4.28.1", | |
| + "caniuse-lite": "^1.0.30001766", | |
| + "fraction.js": "^5.3.4", | |
| + "picocolors": "^1.1.1", | |
| + "postcss-value-parser": "^4.2.0" | |
| + }, | |
| + "bin": { | |
| + "autoprefixer": "bin/autoprefixer" | |
| + }, | |
| + "engines": { | |
| + "node": "^10 || ^12 || >=14" | |
| + }, | |
| + "peerDependencies": { | |
| + "postcss": "^8.1.0" | |
| + } | |
| + }, | |
| + "node_modules/available-typed-arrays": { | |
| + "version": "1.0.7", | |
| + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", | |
| + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "possible-typed-array-names": "^1.0.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/axe-core": { | |
| + "version": "4.11.1", | |
| + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.11.1.tgz", | |
| + "integrity": "sha512-BASOg+YwO2C+346x3LZOeoovTIoTrRqEsqMa6fmfAV0P+U9mFr9NsyOEpiYvFjbc64NMrSswhV50WdXzdb/Z5A==", | |
| + "dev": true, | |
| + "license": "MPL-2.0", | |
| + "engines": { | |
| + "node": ">=4" | |
| + } | |
| + }, | |
| + "node_modules/axobject-query": { | |
| + "version": "4.1.0", | |
| + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", | |
| + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", | |
| + "dev": true, | |
| + "license": "Apache-2.0", | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + } | |
| + }, | |
| + "node_modules/balanced-match": { | |
| + "version": "1.0.2", | |
| + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", | |
| + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", | |
| + "dev": true, | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/baseline-browser-mapping": { | |
| + "version": "2.9.19", | |
| + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz", | |
| + "integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==", | |
| + "dev": true, | |
| + "license": "Apache-2.0", | |
| + "bin": { | |
| + "baseline-browser-mapping": "dist/cli.js" | |
| + } | |
| + }, | |
| + "node_modules/binary-extensions": { | |
| + "version": "2.3.0", | |
| + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", | |
| + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=8" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/sindresorhus" | |
| + } | |
| + }, | |
| + "node_modules/bitmap-sdf": { | |
| + "version": "1.0.4", | |
| + "resolved": "https://registry.npmjs.org/bitmap-sdf/-/bitmap-sdf-1.0.4.tgz", | |
| + "integrity": "sha512-1G3U4n5JE6RAiALMxu0p1XmeZkTeCwGKykzsLTCqVzfSDaN6S7fKnkIkfejogz+iwqBWc0UYAIKnKHNN7pSfDg==", | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/brace-expansion": { | |
| + "version": "1.1.12", | |
| + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", | |
| + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "balanced-match": "^1.0.0", | |
| + "concat-map": "0.0.1" | |
| + } | |
| + }, | |
| + "node_modules/braces": { | |
| + "version": "3.0.3", | |
| + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", | |
| + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "fill-range": "^7.1.1" | |
| + }, | |
| + "engines": { | |
| + "node": ">=8" | |
| + } | |
| + }, | |
| + "node_modules/browserslist": { | |
| + "version": "4.28.1", | |
| + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", | |
| + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", | |
| + "dev": true, | |
| + "funding": [ | |
| + { | |
| + "type": "opencollective", | |
| + "url": "https://opencollective.com/browserslist" | |
| + }, | |
| + { | |
| + "type": "tidelift", | |
| + "url": "https://tidelift.com/funding/github/npm/browserslist" | |
| + }, | |
| + { | |
| + "type": "github", | |
| + "url": "https://github.com/sponsors/ai" | |
| + } | |
| + ], | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "baseline-browser-mapping": "^2.9.0", | |
| + "caniuse-lite": "^1.0.30001759", | |
| + "electron-to-chromium": "^1.5.263", | |
| + "node-releases": "^2.0.27", | |
| + "update-browserslist-db": "^1.2.0" | |
| + }, | |
| + "bin": { | |
| + "browserslist": "cli.js" | |
| + }, | |
| + "engines": { | |
| + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" | |
| + } | |
| + }, | |
| + "node_modules/busboy": { | |
| + "version": "1.6.0", | |
| + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", | |
| + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", | |
| + "dependencies": { | |
| + "streamsearch": "^1.1.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">=10.16.0" | |
| + } | |
| + }, | |
| + "node_modules/call-bind": { | |
| + "version": "1.0.8", | |
| + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", | |
| + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bind-apply-helpers": "^1.0.0", | |
| + "es-define-property": "^1.0.0", | |
| + "get-intrinsic": "^1.2.4", | |
| + "set-function-length": "^1.2.2" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/call-bind-apply-helpers": { | |
| + "version": "1.0.2", | |
| + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", | |
| + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "es-errors": "^1.3.0", | |
| + "function-bind": "^1.1.2" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + } | |
| + }, | |
| + "node_modules/call-bound": { | |
| + "version": "1.0.4", | |
| + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", | |
| + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bind-apply-helpers": "^1.0.2", | |
| + "get-intrinsic": "^1.3.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/callsites": { | |
| + "version": "3.1.0", | |
| + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", | |
| + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=6" | |
| + } | |
| + }, | |
| + "node_modules/camelcase-css": { | |
| + "version": "2.0.1", | |
| + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", | |
| + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">= 6" | |
| + } | |
| + }, | |
| + "node_modules/caniuse-lite": { | |
| + "version": "1.0.30001767", | |
| + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001767.tgz", | |
| + "integrity": "sha512-34+zUAMhSH+r+9eKmYG+k2Rpt8XttfE4yXAjoZvkAPs15xcYQhyBYdalJ65BzivAvGRMViEjy6oKr/S91loekQ==", | |
| + "funding": [ | |
| + { | |
| + "type": "opencollective", | |
| + "url": "https://opencollective.com/browserslist" | |
| + }, | |
| + { | |
| + "type": "tidelift", | |
| + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" | |
| + }, | |
| + { | |
| + "type": "github", | |
| + "url": "https://github.com/sponsors/ai" | |
| + } | |
| + ], | |
| + "license": "CC-BY-4.0" | |
| + }, | |
| + "node_modules/cesium": { | |
| + "version": "1.138.0", | |
| + "resolved": "https://registry.npmjs.org/cesium/-/cesium-1.138.0.tgz", | |
| + "integrity": "sha512-YX7Ttd4LzAxunuzcKPyOCQa+BPc2RmenqnkM5uZkk/GVwor724bd+F3kdVP4IyMbTgxFkchXuX2Aa8L1Y0/ZxA==", | |
| + "license": "Apache-2.0", | |
| + "workspaces": [ | |
| + "packages/engine", | |
| + "packages/widgets", | |
| + "packages/sandcastle" | |
| + ], | |
| + "dependencies": { | |
| + "@cesium/engine": "^22.3.0", | |
| + "@cesium/widgets": "^14.3.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">=20.19.0" | |
| + } | |
| + }, | |
| + "node_modules/chalk": { | |
| + "version": "4.1.2", | |
| + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", | |
| + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "ansi-styles": "^4.1.0", | |
| + "supports-color": "^7.1.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">=10" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/chalk/chalk?sponsor=1" | |
| + } | |
| + }, | |
| + "node_modules/chokidar": { | |
| + "version": "3.6.0", | |
| + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", | |
| + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "anymatch": "~3.1.2", | |
| + "braces": "~3.0.2", | |
| + "glob-parent": "~5.1.2", | |
| + "is-binary-path": "~2.1.0", | |
| + "is-glob": "~4.0.1", | |
| + "normalize-path": "~3.0.0", | |
| + "readdirp": "~3.6.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 8.10.0" | |
| + }, | |
| + "funding": { | |
| + "url": "https://paulmillr.com/funding/" | |
| + }, | |
| + "optionalDependencies": { | |
| + "fsevents": "~2.3.2" | |
| + } | |
| + }, | |
| + "node_modules/chokidar/node_modules/glob-parent": { | |
| + "version": "5.1.2", | |
| + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", | |
| + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", | |
| + "license": "ISC", | |
| + "dependencies": { | |
| + "is-glob": "^4.0.1" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 6" | |
| + } | |
| + }, | |
| + "node_modules/class-variance-authority": { | |
| + "version": "0.7.1", | |
| + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", | |
| + "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", | |
| + "license": "Apache-2.0", | |
| + "dependencies": { | |
| + "clsx": "^2.1.1" | |
| + }, | |
| + "funding": { | |
| + "url": "https://polar.sh/cva" | |
| + } | |
| + }, | |
| + "node_modules/client-only": { | |
| + "version": "0.0.1", | |
| + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", | |
| + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/clsx": { | |
| + "version": "2.1.1", | |
| + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", | |
| + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=6" | |
| + } | |
| + }, | |
| + "node_modules/color-convert": { | |
| + "version": "2.0.1", | |
| + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", | |
| + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "color-name": "~1.1.4" | |
| + }, | |
| + "engines": { | |
| + "node": ">=7.0.0" | |
| + } | |
| + }, | |
| + "node_modules/color-name": { | |
| + "version": "1.1.4", | |
| + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", | |
| + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", | |
| + "dev": true, | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/commander": { | |
| + "version": "4.1.1", | |
| + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", | |
| + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">= 6" | |
| + } | |
| + }, | |
| + "node_modules/concat-map": { | |
| + "version": "0.0.1", | |
| + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", | |
| + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", | |
| + "dev": true, | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/cross-spawn": { | |
| + "version": "7.0.6", | |
| + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", | |
| + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "path-key": "^3.1.0", | |
| + "shebang-command": "^2.0.0", | |
| + "which": "^2.0.1" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 8" | |
| + } | |
| + }, | |
| + "node_modules/cssesc": { | |
| + "version": "3.0.0", | |
| + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", | |
| + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", | |
| + "license": "MIT", | |
| + "bin": { | |
| + "cssesc": "bin/cssesc" | |
| + }, | |
| + "engines": { | |
| + "node": ">=4" | |
| + } | |
| + }, | |
| + "node_modules/csstype": { | |
| + "version": "3.2.3", | |
| + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", | |
| + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", | |
| + "devOptional": true, | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/damerau-levenshtein": { | |
| + "version": "1.0.8", | |
| + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", | |
| + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", | |
| + "dev": true, | |
| + "license": "BSD-2-Clause" | |
| + }, | |
| + "node_modules/data-view-buffer": { | |
| + "version": "1.0.2", | |
| + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", | |
| + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bound": "^1.0.3", | |
| + "es-errors": "^1.3.0", | |
| + "is-data-view": "^1.0.2" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/data-view-byte-length": { | |
| + "version": "1.0.2", | |
| + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", | |
| + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bound": "^1.0.3", | |
| + "es-errors": "^1.3.0", | |
| + "is-data-view": "^1.0.2" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/inspect-js" | |
| + } | |
| + }, | |
| + "node_modules/data-view-byte-offset": { | |
| + "version": "1.0.1", | |
| + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", | |
| + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bound": "^1.0.2", | |
| + "es-errors": "^1.3.0", | |
| + "is-data-view": "^1.0.1" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/debug": { | |
| + "version": "4.4.3", | |
| + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", | |
| + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "ms": "^2.1.3" | |
| + }, | |
| + "engines": { | |
| + "node": ">=6.0" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "supports-color": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/deep-is": { | |
| + "version": "0.1.4", | |
| + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", | |
| + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", | |
| + "dev": true, | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/define-data-property": { | |
| + "version": "1.1.4", | |
| + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", | |
| + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "es-define-property": "^1.0.0", | |
| + "es-errors": "^1.3.0", | |
| + "gopd": "^1.0.1" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/define-properties": { | |
| + "version": "1.2.1", | |
| + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", | |
| + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "define-data-property": "^1.0.1", | |
| + "has-property-descriptors": "^1.0.0", | |
| + "object-keys": "^1.1.1" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/detect-node-es": { | |
| + "version": "1.1.0", | |
| + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", | |
| + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/didyoumean": { | |
| + "version": "1.2.2", | |
| + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", | |
| + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", | |
| + "license": "Apache-2.0" | |
| + }, | |
| + "node_modules/dlv": { | |
| + "version": "1.1.3", | |
| + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", | |
| + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/doctrine": { | |
| + "version": "3.0.0", | |
| + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", | |
| + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", | |
| + "dev": true, | |
| + "license": "Apache-2.0", | |
| + "dependencies": { | |
| + "esutils": "^2.0.2" | |
| + }, | |
| + "engines": { | |
| + "node": ">=6.0.0" | |
| + } | |
| + }, | |
| + "node_modules/dompurify": { | |
| + "version": "3.3.1", | |
| + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.1.tgz", | |
| + "integrity": "sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q==", | |
| + "license": "(MPL-2.0 OR Apache-2.0)", | |
| + "optionalDependencies": { | |
| + "@types/trusted-types": "^2.0.7" | |
| + } | |
| + }, | |
| + "node_modules/draco3d": { | |
| + "version": "1.5.7", | |
| + "resolved": "https://registry.npmjs.org/draco3d/-/draco3d-1.5.7.tgz", | |
| + "integrity": "sha512-m6WCKt/erDXcw+70IJXnG7M3awwQPAsZvJGX5zY7beBqpELw6RDGkYVU0W43AFxye4pDZ5i2Lbyc/NNGqwjUVQ==", | |
| + "license": "Apache-2.0" | |
| + }, | |
| + "node_modules/dunder-proto": { | |
| + "version": "1.0.1", | |
| + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", | |
| + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bind-apply-helpers": "^1.0.1", | |
| + "es-errors": "^1.3.0", | |
| + "gopd": "^1.2.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + } | |
| + }, | |
| + "node_modules/earcut": { | |
| + "version": "3.0.2", | |
| + "resolved": "https://registry.npmjs.org/earcut/-/earcut-3.0.2.tgz", | |
| + "integrity": "sha512-X7hshQbLyMJ/3RPhyObLARM2sNxxmRALLKx1+NVFFnQ9gKzmCrxm9+uLIAdBcvc8FNLpctqlQ2V6AE92Ol9UDQ==", | |
| + "license": "ISC" | |
| + }, | |
| + "node_modules/eastasianwidth": { | |
| + "version": "0.2.0", | |
| + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", | |
| + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", | |
| + "dev": true, | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/electron-to-chromium": { | |
| + "version": "1.5.286", | |
| + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz", | |
| + "integrity": "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==", | |
| + "dev": true, | |
| + "license": "ISC" | |
| + }, | |
| + "node_modules/emoji-regex": { | |
| + "version": "9.2.2", | |
| + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", | |
| + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", | |
| + "dev": true, | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/es-abstract": { | |
| + "version": "1.24.1", | |
| + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.1.tgz", | |
| + "integrity": "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "array-buffer-byte-length": "^1.0.2", | |
| + "arraybuffer.prototype.slice": "^1.0.4", | |
| + "available-typed-arrays": "^1.0.7", | |
| + "call-bind": "^1.0.8", | |
| + "call-bound": "^1.0.4", | |
| + "data-view-buffer": "^1.0.2", | |
| + "data-view-byte-length": "^1.0.2", | |
| + "data-view-byte-offset": "^1.0.1", | |
| + "es-define-property": "^1.0.1", | |
| + "es-errors": "^1.3.0", | |
| + "es-object-atoms": "^1.1.1", | |
| + "es-set-tostringtag": "^2.1.0", | |
| + "es-to-primitive": "^1.3.0", | |
| + "function.prototype.name": "^1.1.8", | |
| + "get-intrinsic": "^1.3.0", | |
| + "get-proto": "^1.0.1", | |
| + "get-symbol-description": "^1.1.0", | |
| + "globalthis": "^1.0.4", | |
| + "gopd": "^1.2.0", | |
| + "has-property-descriptors": "^1.0.2", | |
| + "has-proto": "^1.2.0", | |
| + "has-symbols": "^1.1.0", | |
| + "hasown": "^2.0.2", | |
| + "internal-slot": "^1.1.0", | |
| + "is-array-buffer": "^3.0.5", | |
| + "is-callable": "^1.2.7", | |
| + "is-data-view": "^1.0.2", | |
| + "is-negative-zero": "^2.0.3", | |
| + "is-regex": "^1.2.1", | |
| + "is-set": "^2.0.3", | |
| + "is-shared-array-buffer": "^1.0.4", | |
| + "is-string": "^1.1.1", | |
| + "is-typed-array": "^1.1.15", | |
| + "is-weakref": "^1.1.1", | |
| + "math-intrinsics": "^1.1.0", | |
| + "object-inspect": "^1.13.4", | |
| + "object-keys": "^1.1.1", | |
| + "object.assign": "^4.1.7", | |
| + "own-keys": "^1.0.1", | |
| + "regexp.prototype.flags": "^1.5.4", | |
| + "safe-array-concat": "^1.1.3", | |
| + "safe-push-apply": "^1.0.0", | |
| + "safe-regex-test": "^1.1.0", | |
| + "set-proto": "^1.0.0", | |
| + "stop-iteration-iterator": "^1.1.0", | |
| + "string.prototype.trim": "^1.2.10", | |
| + "string.prototype.trimend": "^1.0.9", | |
| + "string.prototype.trimstart": "^1.0.8", | |
| + "typed-array-buffer": "^1.0.3", | |
| + "typed-array-byte-length": "^1.0.3", | |
| + "typed-array-byte-offset": "^1.0.4", | |
| + "typed-array-length": "^1.0.7", | |
| + "unbox-primitive": "^1.1.0", | |
| + "which-typed-array": "^1.1.19" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/es-define-property": { | |
| + "version": "1.0.1", | |
| + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", | |
| + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + } | |
| + }, | |
| + "node_modules/es-errors": { | |
| + "version": "1.3.0", | |
| + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", | |
| + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + } | |
| + }, | |
| + "node_modules/es-iterator-helpers": { | |
| + "version": "1.2.2", | |
| + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.2.tgz", | |
| + "integrity": "sha512-BrUQ0cPTB/IwXj23HtwHjS9n7O4h9FX94b4xc5zlTHxeLgTAdzYUDyy6KdExAl9lbN5rtfe44xpjpmj9grxs5w==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bind": "^1.0.8", | |
| + "call-bound": "^1.0.4", | |
| + "define-properties": "^1.2.1", | |
| + "es-abstract": "^1.24.1", | |
| + "es-errors": "^1.3.0", | |
| + "es-set-tostringtag": "^2.1.0", | |
| + "function-bind": "^1.1.2", | |
| + "get-intrinsic": "^1.3.0", | |
| + "globalthis": "^1.0.4", | |
| + "gopd": "^1.2.0", | |
| + "has-property-descriptors": "^1.0.2", | |
| + "has-proto": "^1.2.0", | |
| + "has-symbols": "^1.1.0", | |
| + "internal-slot": "^1.1.0", | |
| + "iterator.prototype": "^1.1.5", | |
| + "safe-array-concat": "^1.1.3" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + } | |
| + }, | |
| + "node_modules/es-object-atoms": { | |
| + "version": "1.1.1", | |
| + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", | |
| + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "es-errors": "^1.3.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + } | |
| + }, | |
| + "node_modules/es-set-tostringtag": { | |
| + "version": "2.1.0", | |
| + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", | |
| + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "es-errors": "^1.3.0", | |
| + "get-intrinsic": "^1.2.6", | |
| + "has-tostringtag": "^1.0.2", | |
| + "hasown": "^2.0.2" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + } | |
| + }, | |
| + "node_modules/es-shim-unscopables": { | |
| + "version": "1.1.0", | |
| + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", | |
| + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "hasown": "^2.0.2" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + } | |
| + }, | |
| + "node_modules/es-to-primitive": { | |
| + "version": "1.3.0", | |
| + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", | |
| + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "is-callable": "^1.2.7", | |
| + "is-date-object": "^1.0.5", | |
| + "is-symbol": "^1.0.4" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/escalade": { | |
| + "version": "3.2.0", | |
| + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", | |
| + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=6" | |
| + } | |
| + }, | |
| + "node_modules/escape-string-regexp": { | |
| + "version": "4.0.0", | |
| + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", | |
| + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=10" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/sindresorhus" | |
| + } | |
| + }, | |
| + "node_modules/eslint": { | |
| + "version": "8.57.1", | |
| + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", | |
| + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", | |
| + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@eslint-community/eslint-utils": "^4.2.0", | |
| + "@eslint-community/regexpp": "^4.6.1", | |
| + "@eslint/eslintrc": "^2.1.4", | |
| + "@eslint/js": "8.57.1", | |
| + "@humanwhocodes/config-array": "^0.13.0", | |
| + "@humanwhocodes/module-importer": "^1.0.1", | |
| + "@nodelib/fs.walk": "^1.2.8", | |
| + "@ungap/structured-clone": "^1.2.0", | |
| + "ajv": "^6.12.4", | |
| + "chalk": "^4.0.0", | |
| + "cross-spawn": "^7.0.2", | |
| + "debug": "^4.3.2", | |
| + "doctrine": "^3.0.0", | |
| + "escape-string-regexp": "^4.0.0", | |
| + "eslint-scope": "^7.2.2", | |
| + "eslint-visitor-keys": "^3.4.3", | |
| + "espree": "^9.6.1", | |
| + "esquery": "^1.4.2", | |
| + "esutils": "^2.0.2", | |
| + "fast-deep-equal": "^3.1.3", | |
| + "file-entry-cache": "^6.0.1", | |
| + "find-up": "^5.0.0", | |
| + "glob-parent": "^6.0.2", | |
| + "globals": "^13.19.0", | |
| + "graphemer": "^1.4.0", | |
| + "ignore": "^5.2.0", | |
| + "imurmurhash": "^0.1.4", | |
| + "is-glob": "^4.0.0", | |
| + "is-path-inside": "^3.0.3", | |
| + "js-yaml": "^4.1.0", | |
| + "json-stable-stringify-without-jsonify": "^1.0.1", | |
| + "levn": "^0.4.1", | |
| + "lodash.merge": "^4.6.2", | |
| + "minimatch": "^3.1.2", | |
| + "natural-compare": "^1.4.0", | |
| + "optionator": "^0.9.3", | |
| + "strip-ansi": "^6.0.1", | |
| + "text-table": "^0.2.0" | |
| + }, | |
| + "bin": { | |
| + "eslint": "bin/eslint.js" | |
| + }, | |
| + "engines": { | |
| + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" | |
| + }, | |
| + "funding": { | |
| + "url": "https://opencollective.com/eslint" | |
| + } | |
| + }, | |
| + "node_modules/eslint-config-next": { | |
| + "version": "14.2.15", | |
| + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-14.2.15.tgz", | |
| + "integrity": "sha512-mKg+NC/8a4JKLZRIOBplxXNdStgxy7lzWuedUaCc8tev+Al9mwDUTujQH6W6qXDH9kycWiVo28tADWGvpBsZcQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@next/eslint-plugin-next": "14.2.15", | |
| + "@rushstack/eslint-patch": "^1.3.3", | |
| + "@typescript-eslint/eslint-plugin": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0", | |
| + "@typescript-eslint/parser": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0", | |
| + "eslint-import-resolver-node": "^0.3.6", | |
| + "eslint-import-resolver-typescript": "^3.5.2", | |
| + "eslint-plugin-import": "^2.28.1", | |
| + "eslint-plugin-jsx-a11y": "^6.7.1", | |
| + "eslint-plugin-react": "^7.33.2", | |
| + "eslint-plugin-react-hooks": "^4.5.0 || 5.0.0-canary-7118f5dd7-20230705" | |
| + }, | |
| + "peerDependencies": { | |
| + "eslint": "^7.23.0 || ^8.0.0", | |
| + "typescript": ">=3.3.1" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "typescript": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/eslint-import-resolver-node": { | |
| + "version": "0.3.9", | |
| + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", | |
| + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "debug": "^3.2.7", | |
| + "is-core-module": "^2.13.0", | |
| + "resolve": "^1.22.4" | |
| + } | |
| + }, | |
| + "node_modules/eslint-import-resolver-node/node_modules/debug": { | |
| + "version": "3.2.7", | |
| + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", | |
| + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "ms": "^2.1.1" | |
| + } | |
| + }, | |
| + "node_modules/eslint-import-resolver-typescript": { | |
| + "version": "3.10.1", | |
| + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.1.tgz", | |
| + "integrity": "sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==", | |
| + "dev": true, | |
| + "license": "ISC", | |
| + "dependencies": { | |
| + "@nolyfill/is-core-module": "1.0.39", | |
| + "debug": "^4.4.0", | |
| + "get-tsconfig": "^4.10.0", | |
| + "is-bun-module": "^2.0.0", | |
| + "stable-hash": "^0.0.5", | |
| + "tinyglobby": "^0.2.13", | |
| + "unrs-resolver": "^1.6.2" | |
| + }, | |
| + "engines": { | |
| + "node": "^14.18.0 || >=16.0.0" | |
| + }, | |
| + "funding": { | |
| + "url": "https://opencollective.com/eslint-import-resolver-typescript" | |
| + }, | |
| + "peerDependencies": { | |
| + "eslint": "*", | |
| + "eslint-plugin-import": "*", | |
| + "eslint-plugin-import-x": "*" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "eslint-plugin-import": { | |
| + "optional": true | |
| + }, | |
| + "eslint-plugin-import-x": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/eslint-module-utils": { | |
| + "version": "2.12.1", | |
| + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz", | |
| + "integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "debug": "^3.2.7" | |
| + }, | |
| + "engines": { | |
| + "node": ">=4" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "eslint": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/eslint-module-utils/node_modules/debug": { | |
| + "version": "3.2.7", | |
| + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", | |
| + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "ms": "^2.1.1" | |
| + } | |
| + }, | |
| + "node_modules/eslint-plugin-import": { | |
| + "version": "2.32.0", | |
| + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", | |
| + "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@rtsao/scc": "^1.1.0", | |
| + "array-includes": "^3.1.9", | |
| + "array.prototype.findlastindex": "^1.2.6", | |
| + "array.prototype.flat": "^1.3.3", | |
| + "array.prototype.flatmap": "^1.3.3", | |
| + "debug": "^3.2.7", | |
| + "doctrine": "^2.1.0", | |
| + "eslint-import-resolver-node": "^0.3.9", | |
| + "eslint-module-utils": "^2.12.1", | |
| + "hasown": "^2.0.2", | |
| + "is-core-module": "^2.16.1", | |
| + "is-glob": "^4.0.3", | |
| + "minimatch": "^3.1.2", | |
| + "object.fromentries": "^2.0.8", | |
| + "object.groupby": "^1.0.3", | |
| + "object.values": "^1.2.1", | |
| + "semver": "^6.3.1", | |
| + "string.prototype.trimend": "^1.0.9", | |
| + "tsconfig-paths": "^3.15.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">=4" | |
| + }, | |
| + "peerDependencies": { | |
| + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" | |
| + } | |
| + }, | |
| + "node_modules/eslint-plugin-import/node_modules/debug": { | |
| + "version": "3.2.7", | |
| + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", | |
| + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "ms": "^2.1.1" | |
| + } | |
| + }, | |
| + "node_modules/eslint-plugin-import/node_modules/doctrine": { | |
| + "version": "2.1.0", | |
| + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", | |
| + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", | |
| + "dev": true, | |
| + "license": "Apache-2.0", | |
| + "dependencies": { | |
| + "esutils": "^2.0.2" | |
| + }, | |
| + "engines": { | |
| + "node": ">=0.10.0" | |
| + } | |
| + }, | |
| + "node_modules/eslint-plugin-import/node_modules/semver": { | |
| + "version": "6.3.1", | |
| + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", | |
| + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", | |
| + "dev": true, | |
| + "license": "ISC", | |
| + "bin": { | |
| + "semver": "bin/semver.js" | |
| + } | |
| + }, | |
| + "node_modules/eslint-plugin-jsx-a11y": { | |
| + "version": "6.10.2", | |
| + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz", | |
| + "integrity": "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "aria-query": "^5.3.2", | |
| + "array-includes": "^3.1.8", | |
| + "array.prototype.flatmap": "^1.3.2", | |
| + "ast-types-flow": "^0.0.8", | |
| + "axe-core": "^4.10.0", | |
| + "axobject-query": "^4.1.0", | |
| + "damerau-levenshtein": "^1.0.8", | |
| + "emoji-regex": "^9.2.2", | |
| + "hasown": "^2.0.2", | |
| + "jsx-ast-utils": "^3.3.5", | |
| + "language-tags": "^1.0.9", | |
| + "minimatch": "^3.1.2", | |
| + "object.fromentries": "^2.0.8", | |
| + "safe-regex-test": "^1.0.3", | |
| + "string.prototype.includes": "^2.0.1" | |
| + }, | |
| + "engines": { | |
| + "node": ">=4.0" | |
| + }, | |
| + "peerDependencies": { | |
| + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9" | |
| + } | |
| + }, | |
| + "node_modules/eslint-plugin-react": { | |
| + "version": "7.37.5", | |
| + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", | |
| + "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "array-includes": "^3.1.8", | |
| + "array.prototype.findlast": "^1.2.5", | |
| + "array.prototype.flatmap": "^1.3.3", | |
| + "array.prototype.tosorted": "^1.1.4", | |
| + "doctrine": "^2.1.0", | |
| + "es-iterator-helpers": "^1.2.1", | |
| + "estraverse": "^5.3.0", | |
| + "hasown": "^2.0.2", | |
| + "jsx-ast-utils": "^2.4.1 || ^3.0.0", | |
| + "minimatch": "^3.1.2", | |
| + "object.entries": "^1.1.9", | |
| + "object.fromentries": "^2.0.8", | |
| + "object.values": "^1.2.1", | |
| + "prop-types": "^15.8.1", | |
| + "resolve": "^2.0.0-next.5", | |
| + "semver": "^6.3.1", | |
| + "string.prototype.matchall": "^4.0.12", | |
| + "string.prototype.repeat": "^1.0.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">=4" | |
| + }, | |
| + "peerDependencies": { | |
| + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" | |
| + } | |
| + }, | |
| + "node_modules/eslint-plugin-react-hooks": { | |
| + "version": "5.0.0-canary-7118f5dd7-20230705", | |
| + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.0.0-canary-7118f5dd7-20230705.tgz", | |
| + "integrity": "sha512-AZYbMo/NW9chdL7vk6HQzQhT+PvTAEVqWk9ziruUoW2kAOcN5qNyelv70e0F1VNQAbvutOC9oc+xfWycI9FxDw==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=10" | |
| + }, | |
| + "peerDependencies": { | |
| + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" | |
| + } | |
| + }, | |
| + "node_modules/eslint-plugin-react/node_modules/doctrine": { | |
| + "version": "2.1.0", | |
| + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", | |
| + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", | |
| + "dev": true, | |
| + "license": "Apache-2.0", | |
| + "dependencies": { | |
| + "esutils": "^2.0.2" | |
| + }, | |
| + "engines": { | |
| + "node": ">=0.10.0" | |
| + } | |
| + }, | |
| + "node_modules/eslint-plugin-react/node_modules/resolve": { | |
| + "version": "2.0.0-next.5", | |
| + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", | |
| + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "is-core-module": "^2.13.0", | |
| + "path-parse": "^1.0.7", | |
| + "supports-preserve-symlinks-flag": "^1.0.0" | |
| + }, | |
| + "bin": { | |
| + "resolve": "bin/resolve" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/eslint-plugin-react/node_modules/semver": { | |
| + "version": "6.3.1", | |
| + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", | |
| + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", | |
| + "dev": true, | |
| + "license": "ISC", | |
| + "bin": { | |
| + "semver": "bin/semver.js" | |
| + } | |
| + }, | |
| + "node_modules/eslint-scope": { | |
| + "version": "7.2.2", | |
| + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", | |
| + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", | |
| + "dev": true, | |
| + "license": "BSD-2-Clause", | |
| + "dependencies": { | |
| + "esrecurse": "^4.3.0", | |
| + "estraverse": "^5.2.0" | |
| + }, | |
| + "engines": { | |
| + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" | |
| + }, | |
| + "funding": { | |
| + "url": "https://opencollective.com/eslint" | |
| + } | |
| + }, | |
| + "node_modules/eslint-visitor-keys": { | |
| + "version": "3.4.3", | |
| + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", | |
| + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", | |
| + "dev": true, | |
| + "license": "Apache-2.0", | |
| + "engines": { | |
| + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" | |
| + }, | |
| + "funding": { | |
| + "url": "https://opencollective.com/eslint" | |
| + } | |
| + }, | |
| + "node_modules/espree": { | |
| + "version": "9.6.1", | |
| + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", | |
| + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", | |
| + "dev": true, | |
| + "license": "BSD-2-Clause", | |
| + "dependencies": { | |
| + "acorn": "^8.9.0", | |
| + "acorn-jsx": "^5.3.2", | |
| + "eslint-visitor-keys": "^3.4.1" | |
| + }, | |
| + "engines": { | |
| + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" | |
| + }, | |
| + "funding": { | |
| + "url": "https://opencollective.com/eslint" | |
| + } | |
| + }, | |
| + "node_modules/esquery": { | |
| + "version": "1.7.0", | |
| + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", | |
| + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", | |
| + "dev": true, | |
| + "license": "BSD-3-Clause", | |
| + "dependencies": { | |
| + "estraverse": "^5.1.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">=0.10" | |
| + } | |
| + }, | |
| + "node_modules/esrecurse": { | |
| + "version": "4.3.0", | |
| + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", | |
| + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", | |
| + "dev": true, | |
| + "license": "BSD-2-Clause", | |
| + "dependencies": { | |
| + "estraverse": "^5.2.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">=4.0" | |
| + } | |
| + }, | |
| + "node_modules/estraverse": { | |
| + "version": "5.3.0", | |
| + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", | |
| + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", | |
| + "dev": true, | |
| + "license": "BSD-2-Clause", | |
| + "engines": { | |
| + "node": ">=4.0" | |
| + } | |
| + }, | |
| + "node_modules/esutils": { | |
| + "version": "2.0.3", | |
| + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", | |
| + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", | |
| + "dev": true, | |
| + "license": "BSD-2-Clause", | |
| + "engines": { | |
| + "node": ">=0.10.0" | |
| + } | |
| + }, | |
| + "node_modules/fast-deep-equal": { | |
| + "version": "3.1.3", | |
| + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", | |
| + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", | |
| + "dev": true, | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/fast-glob": { | |
| + "version": "3.3.3", | |
| + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", | |
| + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@nodelib/fs.stat": "^2.0.2", | |
| + "@nodelib/fs.walk": "^1.2.3", | |
| + "glob-parent": "^5.1.2", | |
| + "merge2": "^1.3.0", | |
| + "micromatch": "^4.0.8" | |
| + }, | |
| + "engines": { | |
| + "node": ">=8.6.0" | |
| + } | |
| + }, | |
| + "node_modules/fast-glob/node_modules/glob-parent": { | |
| + "version": "5.1.2", | |
| + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", | |
| + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", | |
| + "license": "ISC", | |
| + "dependencies": { | |
| + "is-glob": "^4.0.1" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 6" | |
| + } | |
| + }, | |
| + "node_modules/fast-json-stable-stringify": { | |
| + "version": "2.1.0", | |
| + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", | |
| + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", | |
| + "dev": true, | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/fast-levenshtein": { | |
| + "version": "2.0.6", | |
| + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", | |
| + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", | |
| + "dev": true, | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/fastq": { | |
| + "version": "1.20.1", | |
| + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", | |
| + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", | |
| + "license": "ISC", | |
| + "dependencies": { | |
| + "reusify": "^1.0.4" | |
| + } | |
| + }, | |
| + "node_modules/file-entry-cache": { | |
| + "version": "6.0.1", | |
| + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", | |
| + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "flat-cache": "^3.0.4" | |
| + }, | |
| + "engines": { | |
| + "node": "^10.12.0 || >=12.0.0" | |
| + } | |
| + }, | |
| + "node_modules/fill-range": { | |
| + "version": "7.1.1", | |
| + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", | |
| + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "to-regex-range": "^5.0.1" | |
| + }, | |
| + "engines": { | |
| + "node": ">=8" | |
| + } | |
| + }, | |
| + "node_modules/find-up": { | |
| + "version": "5.0.0", | |
| + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", | |
| + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "locate-path": "^6.0.0", | |
| + "path-exists": "^4.0.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">=10" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/sindresorhus" | |
| + } | |
| + }, | |
| + "node_modules/flat-cache": { | |
| + "version": "3.2.0", | |
| + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", | |
| + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "flatted": "^3.2.9", | |
| + "keyv": "^4.5.3", | |
| + "rimraf": "^3.0.2" | |
| + }, | |
| + "engines": { | |
| + "node": "^10.12.0 || >=12.0.0" | |
| + } | |
| + }, | |
| + "node_modules/flatted": { | |
| + "version": "3.3.3", | |
| + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", | |
| + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", | |
| + "dev": true, | |
| + "license": "ISC" | |
| + }, | |
| + "node_modules/for-each": { | |
| + "version": "0.3.5", | |
| + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", | |
| + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "is-callable": "^1.2.7" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/foreground-child": { | |
| + "version": "3.3.1", | |
| + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", | |
| + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", | |
| + "dev": true, | |
| + "license": "ISC", | |
| + "dependencies": { | |
| + "cross-spawn": "^7.0.6", | |
| + "signal-exit": "^4.0.1" | |
| + }, | |
| + "engines": { | |
| + "node": ">=14" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/isaacs" | |
| + } | |
| + }, | |
| + "node_modules/fraction.js": { | |
| + "version": "5.3.4", | |
| + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", | |
| + "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": "*" | |
| + }, | |
| + "funding": { | |
| + "type": "github", | |
| + "url": "https://github.com/sponsors/rawify" | |
| + } | |
| + }, | |
| + "node_modules/fs.realpath": { | |
| + "version": "1.0.0", | |
| + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", | |
| + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", | |
| + "dev": true, | |
| + "license": "ISC" | |
| + }, | |
| + "node_modules/fsevents": { | |
| + "version": "2.3.3", | |
| + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", | |
| + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", | |
| + "hasInstallScript": true, | |
| + "license": "MIT", | |
| + "optional": true, | |
| + "os": [ | |
| + "darwin" | |
| + ], | |
| + "engines": { | |
| + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" | |
| + } | |
| + }, | |
| + "node_modules/function-bind": { | |
| + "version": "1.1.2", | |
| + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", | |
| + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", | |
| + "license": "MIT", | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/function.prototype.name": { | |
| + "version": "1.1.8", | |
| + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", | |
| + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bind": "^1.0.8", | |
| + "call-bound": "^1.0.3", | |
| + "define-properties": "^1.2.1", | |
| + "functions-have-names": "^1.2.3", | |
| + "hasown": "^2.0.2", | |
| + "is-callable": "^1.2.7" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/functions-have-names": { | |
| + "version": "1.2.3", | |
| + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", | |
| + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/generator-function": { | |
| + "version": "2.0.1", | |
| + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", | |
| + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + } | |
| + }, | |
| + "node_modules/get-intrinsic": { | |
| + "version": "1.3.0", | |
| + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", | |
| + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bind-apply-helpers": "^1.0.2", | |
| + "es-define-property": "^1.0.1", | |
| + "es-errors": "^1.3.0", | |
| + "es-object-atoms": "^1.1.1", | |
| + "function-bind": "^1.1.2", | |
| + "get-proto": "^1.0.1", | |
| + "gopd": "^1.2.0", | |
| + "has-symbols": "^1.1.0", | |
| + "hasown": "^2.0.2", | |
| + "math-intrinsics": "^1.1.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/get-nonce": { | |
| + "version": "1.0.1", | |
| + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", | |
| + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=6" | |
| + } | |
| + }, | |
| + "node_modules/get-proto": { | |
| + "version": "1.0.1", | |
| + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", | |
| + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "dunder-proto": "^1.0.1", | |
| + "es-object-atoms": "^1.0.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + } | |
| + }, | |
| + "node_modules/get-symbol-description": { | |
| + "version": "1.1.0", | |
| + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", | |
| + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bound": "^1.0.3", | |
| + "es-errors": "^1.3.0", | |
| + "get-intrinsic": "^1.2.6" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/get-tsconfig": { | |
| + "version": "4.13.1", | |
| + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.1.tgz", | |
| + "integrity": "sha512-EoY1N2xCn44xU6750Sx7OjOIT59FkmstNc3X6y5xpz7D5cBtZRe/3pSlTkDJgqsOk3WwZPkWfonhhUJfttQo3w==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "resolve-pkg-maps": "^1.0.0" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" | |
| + } | |
| + }, | |
| + "node_modules/glob": { | |
| + "version": "10.3.10", | |
| + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", | |
| + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", | |
| + "dev": true, | |
| + "license": "ISC", | |
| + "dependencies": { | |
| + "foreground-child": "^3.1.0", | |
| + "jackspeak": "^2.3.5", | |
| + "minimatch": "^9.0.1", | |
| + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", | |
| + "path-scurry": "^1.10.1" | |
| + }, | |
| + "bin": { | |
| + "glob": "dist/esm/bin.mjs" | |
| + }, | |
| + "engines": { | |
| + "node": ">=16 || 14 >=14.17" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/isaacs" | |
| + } | |
| + }, | |
| + "node_modules/glob-parent": { | |
| + "version": "6.0.2", | |
| + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", | |
| + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", | |
| + "license": "ISC", | |
| + "dependencies": { | |
| + "is-glob": "^4.0.3" | |
| + }, | |
| + "engines": { | |
| + "node": ">=10.13.0" | |
| + } | |
| + }, | |
| + "node_modules/glob/node_modules/brace-expansion": { | |
| + "version": "2.0.2", | |
| + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", | |
| + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "balanced-match": "^1.0.0" | |
| + } | |
| + }, | |
| + "node_modules/glob/node_modules/minimatch": { | |
| + "version": "9.0.5", | |
| + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", | |
| + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", | |
| + "dev": true, | |
| + "license": "ISC", | |
| + "dependencies": { | |
| + "brace-expansion": "^2.0.1" | |
| + }, | |
| + "engines": { | |
| + "node": ">=16 || 14 >=14.17" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/isaacs" | |
| + } | |
| + }, | |
| + "node_modules/globals": { | |
| + "version": "13.24.0", | |
| + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", | |
| + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "type-fest": "^0.20.2" | |
| + }, | |
| + "engines": { | |
| + "node": ">=8" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/sindresorhus" | |
| + } | |
| + }, | |
| + "node_modules/globalthis": { | |
| + "version": "1.0.4", | |
| + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", | |
| + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "define-properties": "^1.2.1", | |
| + "gopd": "^1.0.1" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/gopd": { | |
| + "version": "1.2.0", | |
| + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", | |
| + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/graceful-fs": { | |
| + "version": "4.2.11", | |
| + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", | |
| + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", | |
| + "license": "ISC" | |
| + }, | |
| + "node_modules/grapheme-splitter": { | |
| + "version": "1.0.4", | |
| + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", | |
| + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/graphemer": { | |
| + "version": "1.4.0", | |
| + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", | |
| + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", | |
| + "dev": true, | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/has-bigints": { | |
| + "version": "1.1.0", | |
| + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", | |
| + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/has-flag": { | |
| + "version": "4.0.0", | |
| + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", | |
| + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=8" | |
| + } | |
| + }, | |
| + "node_modules/has-property-descriptors": { | |
| + "version": "1.0.2", | |
| + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", | |
| + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "es-define-property": "^1.0.0" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/has-proto": { | |
| + "version": "1.2.0", | |
| + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", | |
| + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "dunder-proto": "^1.0.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/has-symbols": { | |
| + "version": "1.1.0", | |
| + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", | |
| + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/has-tostringtag": { | |
| + "version": "1.0.2", | |
| + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", | |
| + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "has-symbols": "^1.0.3" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/hasown": { | |
| + "version": "2.0.2", | |
| + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", | |
| + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "function-bind": "^1.1.2" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + } | |
| + }, | |
| + "node_modules/ignore": { | |
| + "version": "5.3.2", | |
| + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", | |
| + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">= 4" | |
| + } | |
| + }, | |
| + "node_modules/import-fresh": { | |
| + "version": "3.3.1", | |
| + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", | |
| + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "parent-module": "^1.0.0", | |
| + "resolve-from": "^4.0.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">=6" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/sindresorhus" | |
| + } | |
| + }, | |
| + "node_modules/imurmurhash": { | |
| + "version": "0.1.4", | |
| + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", | |
| + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=0.8.19" | |
| + } | |
| + }, | |
| + "node_modules/inflight": { | |
| + "version": "1.0.6", | |
| + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", | |
| + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", | |
| + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", | |
| + "dev": true, | |
| + "license": "ISC", | |
| + "dependencies": { | |
| + "once": "^1.3.0", | |
| + "wrappy": "1" | |
| + } | |
| + }, | |
| + "node_modules/inherits": { | |
| + "version": "2.0.4", | |
| + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", | |
| + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", | |
| + "dev": true, | |
| + "license": "ISC" | |
| + }, | |
| + "node_modules/internal-slot": { | |
| + "version": "1.1.0", | |
| + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", | |
| + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "es-errors": "^1.3.0", | |
| + "hasown": "^2.0.2", | |
| + "side-channel": "^1.1.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + } | |
| + }, | |
| + "node_modules/is-array-buffer": { | |
| + "version": "3.0.5", | |
| + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", | |
| + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bind": "^1.0.8", | |
| + "call-bound": "^1.0.3", | |
| + "get-intrinsic": "^1.2.6" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/is-async-function": { | |
| + "version": "2.1.1", | |
| + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", | |
| + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "async-function": "^1.0.0", | |
| + "call-bound": "^1.0.3", | |
| + "get-proto": "^1.0.1", | |
| + "has-tostringtag": "^1.0.2", | |
| + "safe-regex-test": "^1.1.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/is-bigint": { | |
| + "version": "1.1.0", | |
| + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", | |
| + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "has-bigints": "^1.0.2" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/is-binary-path": { | |
| + "version": "2.1.0", | |
| + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", | |
| + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "binary-extensions": "^2.0.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">=8" | |
| + } | |
| + }, | |
| + "node_modules/is-boolean-object": { | |
| + "version": "1.2.2", | |
| + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", | |
| + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bound": "^1.0.3", | |
| + "has-tostringtag": "^1.0.2" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/is-bun-module": { | |
| + "version": "2.0.0", | |
| + "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz", | |
| + "integrity": "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "semver": "^7.7.1" | |
| + } | |
| + }, | |
| + "node_modules/is-callable": { | |
| + "version": "1.2.7", | |
| + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", | |
| + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/is-core-module": { | |
| + "version": "2.16.1", | |
| + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", | |
| + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "hasown": "^2.0.2" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/is-data-view": { | |
| + "version": "1.0.2", | |
| + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", | |
| + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bound": "^1.0.2", | |
| + "get-intrinsic": "^1.2.6", | |
| + "is-typed-array": "^1.1.13" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/is-date-object": { | |
| + "version": "1.1.0", | |
| + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", | |
| + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bound": "^1.0.2", | |
| + "has-tostringtag": "^1.0.2" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/is-extglob": { | |
| + "version": "2.1.1", | |
| + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", | |
| + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=0.10.0" | |
| + } | |
| + }, | |
| + "node_modules/is-finalizationregistry": { | |
| + "version": "1.1.1", | |
| + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", | |
| + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bound": "^1.0.3" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/is-fullwidth-code-point": { | |
| + "version": "3.0.0", | |
| + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", | |
| + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=8" | |
| + } | |
| + }, | |
| + "node_modules/is-generator-function": { | |
| + "version": "1.1.2", | |
| + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", | |
| + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bound": "^1.0.4", | |
| + "generator-function": "^2.0.0", | |
| + "get-proto": "^1.0.1", | |
| + "has-tostringtag": "^1.0.2", | |
| + "safe-regex-test": "^1.1.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/is-glob": { | |
| + "version": "4.0.3", | |
| + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", | |
| + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "is-extglob": "^2.1.1" | |
| + }, | |
| + "engines": { | |
| + "node": ">=0.10.0" | |
| + } | |
| + }, | |
| + "node_modules/is-map": { | |
| + "version": "2.0.3", | |
| + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", | |
| + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/is-negative-zero": { | |
| + "version": "2.0.3", | |
| + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", | |
| + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/is-number": { | |
| + "version": "7.0.0", | |
| + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", | |
| + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=0.12.0" | |
| + } | |
| + }, | |
| + "node_modules/is-number-object": { | |
| + "version": "1.1.1", | |
| + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", | |
| + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bound": "^1.0.3", | |
| + "has-tostringtag": "^1.0.2" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/is-path-inside": { | |
| + "version": "3.0.3", | |
| + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", | |
| + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=8" | |
| + } | |
| + }, | |
| + "node_modules/is-regex": { | |
| + "version": "1.2.1", | |
| + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", | |
| + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bound": "^1.0.2", | |
| + "gopd": "^1.2.0", | |
| + "has-tostringtag": "^1.0.2", | |
| + "hasown": "^2.0.2" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/is-set": { | |
| + "version": "2.0.3", | |
| + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", | |
| + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/is-shared-array-buffer": { | |
| + "version": "1.0.4", | |
| + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", | |
| + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bound": "^1.0.3" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/is-string": { | |
| + "version": "1.1.1", | |
| + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", | |
| + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bound": "^1.0.3", | |
| + "has-tostringtag": "^1.0.2" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/is-symbol": { | |
| + "version": "1.1.1", | |
| + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", | |
| + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bound": "^1.0.2", | |
| + "has-symbols": "^1.1.0", | |
| + "safe-regex-test": "^1.1.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/is-typed-array": { | |
| + "version": "1.1.15", | |
| + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", | |
| + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "which-typed-array": "^1.1.16" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/is-weakmap": { | |
| + "version": "2.0.2", | |
| + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", | |
| + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/is-weakref": { | |
| + "version": "1.1.1", | |
| + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", | |
| + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bound": "^1.0.3" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/is-weakset": { | |
| + "version": "2.0.4", | |
| + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", | |
| + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bound": "^1.0.3", | |
| + "get-intrinsic": "^1.2.6" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/isarray": { | |
| + "version": "2.0.5", | |
| + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", | |
| + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", | |
| + "dev": true, | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/isexe": { | |
| + "version": "2.0.0", | |
| + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", | |
| + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", | |
| + "dev": true, | |
| + "license": "ISC" | |
| + }, | |
| + "node_modules/iterator.prototype": { | |
| + "version": "1.1.5", | |
| + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", | |
| + "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "define-data-property": "^1.1.4", | |
| + "es-object-atoms": "^1.0.0", | |
| + "get-intrinsic": "^1.2.6", | |
| + "get-proto": "^1.0.0", | |
| + "has-symbols": "^1.1.0", | |
| + "set-function-name": "^2.0.2" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + } | |
| + }, | |
| + "node_modules/jackspeak": { | |
| + "version": "2.3.6", | |
| + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", | |
| + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", | |
| + "dev": true, | |
| + "license": "BlueOak-1.0.0", | |
| + "dependencies": { | |
| + "@isaacs/cliui": "^8.0.2" | |
| + }, | |
| + "engines": { | |
| + "node": ">=14" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/isaacs" | |
| + }, | |
| + "optionalDependencies": { | |
| + "@pkgjs/parseargs": "^0.11.0" | |
| + } | |
| + }, | |
| + "node_modules/jiti": { | |
| + "version": "1.21.7", | |
| + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", | |
| + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", | |
| + "license": "MIT", | |
| + "bin": { | |
| + "jiti": "bin/jiti.js" | |
| + } | |
| + }, | |
| + "node_modules/js-tokens": { | |
| + "version": "4.0.0", | |
| + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", | |
| + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/js-yaml": { | |
| + "version": "4.1.1", | |
| + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", | |
| + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "argparse": "^2.0.1" | |
| + }, | |
| + "bin": { | |
| + "js-yaml": "bin/js-yaml.js" | |
| + } | |
| + }, | |
| + "node_modules/jsep": { | |
| + "version": "1.4.0", | |
| + "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.4.0.tgz", | |
| + "integrity": "sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==", | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">= 10.16.0" | |
| + } | |
| + }, | |
| + "node_modules/json-buffer": { | |
| + "version": "3.0.1", | |
| + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", | |
| + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", | |
| + "dev": true, | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/json-schema-traverse": { | |
| + "version": "0.4.1", | |
| + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", | |
| + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", | |
| + "dev": true, | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/json-stable-stringify-without-jsonify": { | |
| + "version": "1.0.1", | |
| + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", | |
| + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", | |
| + "dev": true, | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/json5": { | |
| + "version": "1.0.2", | |
| + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", | |
| + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "minimist": "^1.2.0" | |
| + }, | |
| + "bin": { | |
| + "json5": "lib/cli.js" | |
| + } | |
| + }, | |
| + "node_modules/jsx-ast-utils": { | |
| + "version": "3.3.5", | |
| + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", | |
| + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "array-includes": "^3.1.6", | |
| + "array.prototype.flat": "^1.3.1", | |
| + "object.assign": "^4.1.4", | |
| + "object.values": "^1.1.6" | |
| + }, | |
| + "engines": { | |
| + "node": ">=4.0" | |
| + } | |
| + }, | |
| + "node_modules/kdbush": { | |
| + "version": "4.0.2", | |
| + "resolved": "https://registry.npmjs.org/kdbush/-/kdbush-4.0.2.tgz", | |
| + "integrity": "sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA==", | |
| + "license": "ISC" | |
| + }, | |
| + "node_modules/keyv": { | |
| + "version": "4.5.4", | |
| + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", | |
| + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "json-buffer": "3.0.1" | |
| + } | |
| + }, | |
| + "node_modules/ktx-parse": { | |
| + "version": "1.1.0", | |
| + "resolved": "https://registry.npmjs.org/ktx-parse/-/ktx-parse-1.1.0.tgz", | |
| + "integrity": "sha512-mKp3y+FaYgR7mXWAbyyzpa/r1zDWeaunH+INJO4fou3hb45XuNSwar+7llrRyvpMWafxSIi99RNFJ05MHedaJQ==", | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/language-subtag-registry": { | |
| + "version": "0.3.23", | |
| + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", | |
| + "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==", | |
| + "dev": true, | |
| + "license": "CC0-1.0" | |
| + }, | |
| + "node_modules/language-tags": { | |
| + "version": "1.0.9", | |
| + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", | |
| + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "language-subtag-registry": "^0.3.20" | |
| + }, | |
| + "engines": { | |
| + "node": ">=0.10" | |
| + } | |
| + }, | |
| + "node_modules/lerc": { | |
| + "version": "2.0.0", | |
| + "resolved": "https://registry.npmjs.org/lerc/-/lerc-2.0.0.tgz", | |
| + "integrity": "sha512-7qo1Mq8ZNmaR4USHHm615nEW2lPeeWJ3bTyoqFbd35DLx0LUH7C6ptt5FDCTAlbIzs3+WKrk5SkJvw8AFDE2hg==", | |
| + "license": "Apache-2.0" | |
| + }, | |
| + "node_modules/levn": { | |
| + "version": "0.4.1", | |
| + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", | |
| + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "prelude-ls": "^1.2.1", | |
| + "type-check": "~0.4.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.8.0" | |
| + } | |
| + }, | |
| + "node_modules/lilconfig": { | |
| + "version": "3.1.3", | |
| + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", | |
| + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=14" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/antonk52" | |
| + } | |
| + }, | |
| + "node_modules/lines-and-columns": { | |
| + "version": "1.2.4", | |
| + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", | |
| + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/locate-path": { | |
| + "version": "6.0.0", | |
| + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", | |
| + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "p-locate": "^5.0.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">=10" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/sindresorhus" | |
| + } | |
| + }, | |
| + "node_modules/lodash.merge": { | |
| + "version": "4.6.2", | |
| + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", | |
| + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", | |
| + "dev": true, | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/long": { | |
| + "version": "5.3.2", | |
| + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", | |
| + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", | |
| + "license": "Apache-2.0" | |
| + }, | |
| + "node_modules/loose-envify": { | |
| + "version": "1.4.0", | |
| + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", | |
| + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "js-tokens": "^3.0.0 || ^4.0.0" | |
| + }, | |
| + "bin": { | |
| + "loose-envify": "cli.js" | |
| + } | |
| + }, | |
| + "node_modules/lru-cache": { | |
| + "version": "10.4.3", | |
| + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", | |
| + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", | |
| + "dev": true, | |
| + "license": "ISC" | |
| + }, | |
| + "node_modules/lucide-react": { | |
| + "version": "0.454.0", | |
| + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.454.0.tgz", | |
| + "integrity": "sha512-hw7zMDwykCLnEzgncEEjHeA6+45aeEzRYuKHuyRSOPkhko+J3ySGjGIzu+mmMfDFG1vazHepMaYFYHbTFAZAAQ==", | |
| + "license": "ISC", | |
| + "peerDependencies": { | |
| + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc" | |
| + } | |
| + }, | |
| + "node_modules/math-intrinsics": { | |
| + "version": "1.1.0", | |
| + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", | |
| + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + } | |
| + }, | |
| + "node_modules/merge2": { | |
| + "version": "1.4.1", | |
| + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", | |
| + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">= 8" | |
| + } | |
| + }, | |
| + "node_modules/mersenne-twister": { | |
| + "version": "1.1.0", | |
| + "resolved": "https://registry.npmjs.org/mersenne-twister/-/mersenne-twister-1.1.0.tgz", | |
| + "integrity": "sha512-mUYWsMKNrm4lfygPkL3OfGzOPTR2DBlTkBNHM//F6hGp8cLThY897crAlk3/Jo17LEOOjQUrNAx6DvgO77QJkA==", | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/meshoptimizer": { | |
| + "version": "1.0.1", | |
| + "resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-1.0.1.tgz", | |
| + "integrity": "sha512-Vix+QlA1YYT3FwmBBZ+49cE5y/b+pRrcXKqGpS5ouh33d3lSp2PoTpCw19E0cKDFWalembrHnIaZetf27a+W2g==", | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/micromatch": { | |
| + "version": "4.0.8", | |
| + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", | |
| + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "braces": "^3.0.3", | |
| + "picomatch": "^2.3.1" | |
| + }, | |
| + "engines": { | |
| + "node": ">=8.6" | |
| + } | |
| + }, | |
| + "node_modules/minimatch": { | |
| + "version": "3.1.2", | |
| + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", | |
| + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", | |
| + "dev": true, | |
| + "license": "ISC", | |
| + "dependencies": { | |
| + "brace-expansion": "^1.1.7" | |
| + }, | |
| + "engines": { | |
| + "node": "*" | |
| + } | |
| + }, | |
| + "node_modules/minimist": { | |
| + "version": "1.2.8", | |
| + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", | |
| + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/minipass": { | |
| + "version": "7.1.2", | |
| + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", | |
| + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", | |
| + "dev": true, | |
| + "license": "ISC", | |
| + "engines": { | |
| + "node": ">=16 || 14 >=14.17" | |
| + } | |
| + }, | |
| + "node_modules/ms": { | |
| + "version": "2.1.3", | |
| + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", | |
| + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", | |
| + "dev": true, | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/mz": { | |
| + "version": "2.7.0", | |
| + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", | |
| + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "any-promise": "^1.0.0", | |
| + "object-assign": "^4.0.1", | |
| + "thenify-all": "^1.0.0" | |
| + } | |
| + }, | |
| + "node_modules/nanoid": { | |
| + "version": "3.3.11", | |
| + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", | |
| + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", | |
| + "funding": [ | |
| + { | |
| + "type": "github", | |
| + "url": "https://github.com/sponsors/ai" | |
| + } | |
| + ], | |
| + "license": "MIT", | |
| + "bin": { | |
| + "nanoid": "bin/nanoid.cjs" | |
| + }, | |
| + "engines": { | |
| + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" | |
| + } | |
| + }, | |
| + "node_modules/napi-postinstall": { | |
| + "version": "0.3.4", | |
| + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", | |
| + "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "bin": { | |
| + "napi-postinstall": "lib/cli.js" | |
| + }, | |
| + "engines": { | |
| + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" | |
| + }, | |
| + "funding": { | |
| + "url": "https://opencollective.com/napi-postinstall" | |
| + } | |
| + }, | |
| + "node_modules/natural-compare": { | |
| + "version": "1.4.0", | |
| + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", | |
| + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", | |
| + "dev": true, | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/next": { | |
| + "version": "14.2.15", | |
| + "resolved": "https://registry.npmjs.org/next/-/next-14.2.15.tgz", | |
| + "integrity": "sha512-h9ctmOokpoDphRvMGnwOJAedT6zKhwqyZML9mDtspgf4Rh3Pn7UTYKqePNoDvhsWBAO5GoPNYshnAUGIazVGmw==", | |
| + "deprecated": "This version has a security vulnerability. Please upgrade to a patched version. See https://nextjs.org/blog/security-update-2025-12-11 for more details.", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@next/env": "14.2.15", | |
| + "@swc/helpers": "0.5.5", | |
| + "busboy": "1.6.0", | |
| + "caniuse-lite": "^1.0.30001579", | |
| + "graceful-fs": "^4.2.11", | |
| + "postcss": "8.4.31", | |
| + "styled-jsx": "5.1.1" | |
| + }, | |
| + "bin": { | |
| + "next": "dist/bin/next" | |
| + }, | |
| + "engines": { | |
| + "node": ">=18.17.0" | |
| + }, | |
| + "optionalDependencies": { | |
| + "@next/swc-darwin-arm64": "14.2.15", | |
| + "@next/swc-darwin-x64": "14.2.15", | |
| + "@next/swc-linux-arm64-gnu": "14.2.15", | |
| + "@next/swc-linux-arm64-musl": "14.2.15", | |
| + "@next/swc-linux-x64-gnu": "14.2.15", | |
| + "@next/swc-linux-x64-musl": "14.2.15", | |
| + "@next/swc-win32-arm64-msvc": "14.2.15", | |
| + "@next/swc-win32-ia32-msvc": "14.2.15", | |
| + "@next/swc-win32-x64-msvc": "14.2.15" | |
| + }, | |
| + "peerDependencies": { | |
| + "@opentelemetry/api": "^1.1.0", | |
| + "@playwright/test": "^1.41.2", | |
| + "react": "^18.2.0", | |
| + "react-dom": "^18.2.0", | |
| + "sass": "^1.3.0" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@opentelemetry/api": { | |
| + "optional": true | |
| + }, | |
| + "@playwright/test": { | |
| + "optional": true | |
| + }, | |
| + "sass": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/next-themes": { | |
| + "version": "0.3.0", | |
| + "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.3.0.tgz", | |
| + "integrity": "sha512-/QHIrsYpd6Kfk7xakK4svpDI5mmXP0gfvCoJdGpZQ2TOrQZmsW0QxjaiLn8wbIKjtm4BTSqLoix4lxYYOnLJ/w==", | |
| + "license": "MIT", | |
| + "peerDependencies": { | |
| + "react": "^16.8 || ^17 || ^18", | |
| + "react-dom": "^16.8 || ^17 || ^18" | |
| + } | |
| + }, | |
| + "node_modules/next/node_modules/postcss": { | |
| + "version": "8.4.31", | |
| + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", | |
| + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", | |
| + "funding": [ | |
| + { | |
| + "type": "opencollective", | |
| + "url": "https://opencollective.com/postcss/" | |
| + }, | |
| + { | |
| + "type": "tidelift", | |
| + "url": "https://tidelift.com/funding/github/npm/postcss" | |
| + }, | |
| + { | |
| + "type": "github", | |
| + "url": "https://github.com/sponsors/ai" | |
| + } | |
| + ], | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "nanoid": "^3.3.6", | |
| + "picocolors": "^1.0.0", | |
| + "source-map-js": "^1.0.2" | |
| + }, | |
| + "engines": { | |
| + "node": "^10 || ^12 || >=14" | |
| + } | |
| + }, | |
| + "node_modules/node-releases": { | |
| + "version": "2.0.27", | |
| + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", | |
| + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", | |
| + "dev": true, | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/normalize-path": { | |
| + "version": "3.0.0", | |
| + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", | |
| + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=0.10.0" | |
| + } | |
| + }, | |
| + "node_modules/nosleep.js": { | |
| + "version": "0.12.0", | |
| + "resolved": "https://registry.npmjs.org/nosleep.js/-/nosleep.js-0.12.0.tgz", | |
| + "integrity": "sha512-9d1HbpKLh3sdWlhXMhU6MMH+wQzKkrgfRkYV0EBdvt99YJfj0ilCJrWRDYG2130Tm4GXbEoTCx5b34JSaP+HhA==", | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/object-assign": { | |
| + "version": "4.1.1", | |
| + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", | |
| + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=0.10.0" | |
| + } | |
| + }, | |
| + "node_modules/object-hash": { | |
| + "version": "3.0.0", | |
| + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", | |
| + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">= 6" | |
| + } | |
| + }, | |
| + "node_modules/object-inspect": { | |
| + "version": "1.13.4", | |
| + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", | |
| + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/object-keys": { | |
| + "version": "1.1.1", | |
| + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", | |
| + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + } | |
| + }, | |
| + "node_modules/object.assign": { | |
| + "version": "4.1.7", | |
| + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", | |
| + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bind": "^1.0.8", | |
| + "call-bound": "^1.0.3", | |
| + "define-properties": "^1.2.1", | |
| + "es-object-atoms": "^1.0.0", | |
| + "has-symbols": "^1.1.0", | |
| + "object-keys": "^1.1.1" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/object.entries": { | |
| + "version": "1.1.9", | |
| + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz", | |
| + "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bind": "^1.0.8", | |
| + "call-bound": "^1.0.4", | |
| + "define-properties": "^1.2.1", | |
| + "es-object-atoms": "^1.1.1" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + } | |
| + }, | |
| + "node_modules/object.fromentries": { | |
| + "version": "2.0.8", | |
| + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", | |
| + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bind": "^1.0.7", | |
| + "define-properties": "^1.2.1", | |
| + "es-abstract": "^1.23.2", | |
| + "es-object-atoms": "^1.0.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/object.groupby": { | |
| + "version": "1.0.3", | |
| + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", | |
| + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bind": "^1.0.7", | |
| + "define-properties": "^1.2.1", | |
| + "es-abstract": "^1.23.2" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + } | |
| + }, | |
| + "node_modules/object.values": { | |
| + "version": "1.2.1", | |
| + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", | |
| + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bind": "^1.0.8", | |
| + "call-bound": "^1.0.3", | |
| + "define-properties": "^1.2.1", | |
| + "es-object-atoms": "^1.0.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/once": { | |
| + "version": "1.4.0", | |
| + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", | |
| + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", | |
| + "dev": true, | |
| + "license": "ISC", | |
| + "dependencies": { | |
| + "wrappy": "1" | |
| + } | |
| + }, | |
| + "node_modules/optionator": { | |
| + "version": "0.9.4", | |
| + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", | |
| + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "deep-is": "^0.1.3", | |
| + "fast-levenshtein": "^2.0.6", | |
| + "levn": "^0.4.1", | |
| + "prelude-ls": "^1.2.1", | |
| + "type-check": "^0.4.0", | |
| + "word-wrap": "^1.2.5" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.8.0" | |
| + } | |
| + }, | |
| + "node_modules/own-keys": { | |
| + "version": "1.0.1", | |
| + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", | |
| + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "get-intrinsic": "^1.2.6", | |
| + "object-keys": "^1.1.1", | |
| + "safe-push-apply": "^1.0.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/p-limit": { | |
| + "version": "3.1.0", | |
| + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", | |
| + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "yocto-queue": "^0.1.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">=10" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/sindresorhus" | |
| + } | |
| + }, | |
| + "node_modules/p-locate": { | |
| + "version": "5.0.0", | |
| + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", | |
| + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "p-limit": "^3.0.2" | |
| + }, | |
| + "engines": { | |
| + "node": ">=10" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/sindresorhus" | |
| + } | |
| + }, | |
| + "node_modules/pako": { | |
| + "version": "2.1.0", | |
| + "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", | |
| + "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==", | |
| + "license": "(MIT AND Zlib)" | |
| + }, | |
| + "node_modules/parent-module": { | |
| + "version": "1.0.1", | |
| + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", | |
| + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "callsites": "^3.0.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">=6" | |
| + } | |
| + }, | |
| + "node_modules/path-exists": { | |
| + "version": "4.0.0", | |
| + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", | |
| + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=8" | |
| + } | |
| + }, | |
| + "node_modules/path-is-absolute": { | |
| + "version": "1.0.1", | |
| + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", | |
| + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=0.10.0" | |
| + } | |
| + }, | |
| + "node_modules/path-key": { | |
| + "version": "3.1.1", | |
| + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", | |
| + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=8" | |
| + } | |
| + }, | |
| + "node_modules/path-parse": { | |
| + "version": "1.0.7", | |
| + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", | |
| + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/path-scurry": { | |
| + "version": "1.11.1", | |
| + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", | |
| + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", | |
| + "dev": true, | |
| + "license": "BlueOak-1.0.0", | |
| + "dependencies": { | |
| + "lru-cache": "^10.2.0", | |
| + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">=16 || 14 >=14.18" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/isaacs" | |
| + } | |
| + }, | |
| + "node_modules/picocolors": { | |
| + "version": "1.1.1", | |
| + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", | |
| + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", | |
| + "license": "ISC" | |
| + }, | |
| + "node_modules/picomatch": { | |
| + "version": "2.3.1", | |
| + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", | |
| + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=8.6" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/jonschlinkert" | |
| + } | |
| + }, | |
| + "node_modules/pify": { | |
| + "version": "2.3.0", | |
| + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", | |
| + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=0.10.0" | |
| + } | |
| + }, | |
| + "node_modules/pirates": { | |
| + "version": "4.0.7", | |
| + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", | |
| + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">= 6" | |
| + } | |
| + }, | |
| + "node_modules/possible-typed-array-names": { | |
| + "version": "1.1.0", | |
| + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", | |
| + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + } | |
| + }, | |
| + "node_modules/postcss": { | |
| + "version": "8.5.6", | |
| + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", | |
| + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", | |
| + "funding": [ | |
| + { | |
| + "type": "opencollective", | |
| + "url": "https://opencollective.com/postcss/" | |
| + }, | |
| + { | |
| + "type": "tidelift", | |
| + "url": "https://tidelift.com/funding/github/npm/postcss" | |
| + }, | |
| + { | |
| + "type": "github", | |
| + "url": "https://github.com/sponsors/ai" | |
| + } | |
| + ], | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "nanoid": "^3.3.11", | |
| + "picocolors": "^1.1.1", | |
| + "source-map-js": "^1.2.1" | |
| + }, | |
| + "engines": { | |
| + "node": "^10 || ^12 || >=14" | |
| + } | |
| + }, | |
| + "node_modules/postcss-import": { | |
| + "version": "15.1.0", | |
| + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", | |
| + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "postcss-value-parser": "^4.0.0", | |
| + "read-cache": "^1.0.0", | |
| + "resolve": "^1.1.7" | |
| + }, | |
| + "engines": { | |
| + "node": ">=14.0.0" | |
| + }, | |
| + "peerDependencies": { | |
| + "postcss": "^8.0.0" | |
| + } | |
| + }, | |
| + "node_modules/postcss-js": { | |
| + "version": "4.1.0", | |
| + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", | |
| + "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", | |
| + "funding": [ | |
| + { | |
| + "type": "opencollective", | |
| + "url": "https://opencollective.com/postcss/" | |
| + }, | |
| + { | |
| + "type": "github", | |
| + "url": "https://github.com/sponsors/ai" | |
| + } | |
| + ], | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "camelcase-css": "^2.0.1" | |
| + }, | |
| + "engines": { | |
| + "node": "^12 || ^14 || >= 16" | |
| + }, | |
| + "peerDependencies": { | |
| + "postcss": "^8.4.21" | |
| + } | |
| + }, | |
| + "node_modules/postcss-load-config": { | |
| + "version": "6.0.1", | |
| + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", | |
| + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", | |
| + "funding": [ | |
| + { | |
| + "type": "opencollective", | |
| + "url": "https://opencollective.com/postcss/" | |
| + }, | |
| + { | |
| + "type": "github", | |
| + "url": "https://github.com/sponsors/ai" | |
| + } | |
| + ], | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "lilconfig": "^3.1.1" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 18" | |
| + }, | |
| + "peerDependencies": { | |
| + "jiti": ">=1.21.0", | |
| + "postcss": ">=8.0.9", | |
| + "tsx": "^4.8.1", | |
| + "yaml": "^2.4.2" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "jiti": { | |
| + "optional": true | |
| + }, | |
| + "postcss": { | |
| + "optional": true | |
| + }, | |
| + "tsx": { | |
| + "optional": true | |
| + }, | |
| + "yaml": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/postcss-nested": { | |
| + "version": "6.2.0", | |
| + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", | |
| + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", | |
| + "funding": [ | |
| + { | |
| + "type": "opencollective", | |
| + "url": "https://opencollective.com/postcss/" | |
| + }, | |
| + { | |
| + "type": "github", | |
| + "url": "https://github.com/sponsors/ai" | |
| + } | |
| + ], | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "postcss-selector-parser": "^6.1.1" | |
| + }, | |
| + "engines": { | |
| + "node": ">=12.0" | |
| + }, | |
| + "peerDependencies": { | |
| + "postcss": "^8.2.14" | |
| + } | |
| + }, | |
| + "node_modules/postcss-selector-parser": { | |
| + "version": "6.1.2", | |
| + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", | |
| + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "cssesc": "^3.0.0", | |
| + "util-deprecate": "^1.0.2" | |
| + }, | |
| + "engines": { | |
| + "node": ">=4" | |
| + } | |
| + }, | |
| + "node_modules/postcss-value-parser": { | |
| + "version": "4.2.0", | |
| + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", | |
| + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/prelude-ls": { | |
| + "version": "1.2.1", | |
| + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", | |
| + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">= 0.8.0" | |
| + } | |
| + }, | |
| + "node_modules/prop-types": { | |
| + "version": "15.8.1", | |
| + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", | |
| + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "loose-envify": "^1.4.0", | |
| + "object-assign": "^4.1.1", | |
| + "react-is": "^16.13.1" | |
| + } | |
| + }, | |
| + "node_modules/protobufjs": { | |
| + "version": "8.0.0", | |
| + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-8.0.0.tgz", | |
| + "integrity": "sha512-jx6+sE9h/UryaCZhsJWbJtTEy47yXoGNYI4z8ZaRncM0zBKeRqjO2JEcOUYwrYGb1WLhXM1FfMzW3annvFv0rw==", | |
| + "hasInstallScript": true, | |
| + "license": "BSD-3-Clause", | |
| + "dependencies": { | |
| + "@protobufjs/aspromise": "^1.1.2", | |
| + "@protobufjs/base64": "^1.1.2", | |
| + "@protobufjs/codegen": "^2.0.4", | |
| + "@protobufjs/eventemitter": "^1.1.0", | |
| + "@protobufjs/fetch": "^1.1.0", | |
| + "@protobufjs/float": "^1.0.2", | |
| + "@protobufjs/inquire": "^1.1.0", | |
| + "@protobufjs/path": "^1.1.2", | |
| + "@protobufjs/pool": "^1.1.0", | |
| + "@protobufjs/utf8": "^1.1.0", | |
| + "@types/node": ">=13.7.0", | |
| + "long": "^5.0.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">=12.0.0" | |
| + } | |
| + }, | |
| + "node_modules/punycode": { | |
| + "version": "2.3.1", | |
| + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", | |
| + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=6" | |
| + } | |
| + }, | |
| + "node_modules/queue-microtask": { | |
| + "version": "1.2.3", | |
| + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", | |
| + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", | |
| + "funding": [ | |
| + { | |
| + "type": "github", | |
| + "url": "https://github.com/sponsors/feross" | |
| + }, | |
| + { | |
| + "type": "patreon", | |
| + "url": "https://www.patreon.com/feross" | |
| + }, | |
| + { | |
| + "type": "consulting", | |
| + "url": "https://feross.org/support" | |
| + } | |
| + ], | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/quickselect": { | |
| + "version": "3.0.0", | |
| + "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-3.0.0.tgz", | |
| + "integrity": "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==", | |
| + "license": "ISC" | |
| + }, | |
| + "node_modules/rbush": { | |
| + "version": "4.0.1", | |
| + "resolved": "https://registry.npmjs.org/rbush/-/rbush-4.0.1.tgz", | |
| + "integrity": "sha512-IP0UpfeWQujYC8Jg162rMNc01Rf0gWMMAb2Uxus/Q0qOFw4lCcq6ZnQEZwUoJqWyUGJ9th7JjwI4yIWo+uvoAQ==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "quickselect": "^3.0.0" | |
| + } | |
| + }, | |
| + "node_modules/react": { | |
| + "version": "18.2.0", | |
| + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", | |
| + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "loose-envify": "^1.1.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">=0.10.0" | |
| + } | |
| + }, | |
| + "node_modules/react-dom": { | |
| + "version": "18.2.0", | |
| + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", | |
| + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "loose-envify": "^1.1.0", | |
| + "scheduler": "^0.23.0" | |
| + }, | |
| + "peerDependencies": { | |
| + "react": "^18.2.0" | |
| + } | |
| + }, | |
| + "node_modules/react-is": { | |
| + "version": "16.13.1", | |
| + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", | |
| + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", | |
| + "dev": true, | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/react-remove-scroll": { | |
| + "version": "2.7.2", | |
| + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz", | |
| + "integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "react-remove-scroll-bar": "^2.3.7", | |
| + "react-style-singleton": "^2.2.3", | |
| + "tslib": "^2.1.0", | |
| + "use-callback-ref": "^1.3.3", | |
| + "use-sidecar": "^1.1.3" | |
| + }, | |
| + "engines": { | |
| + "node": ">=10" | |
| + }, | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/react-remove-scroll-bar": { | |
| + "version": "2.3.8", | |
| + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", | |
| + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "react-style-singleton": "^2.2.2", | |
| + "tslib": "^2.0.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">=10" | |
| + }, | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/react-style-singleton": { | |
| + "version": "2.2.3", | |
| + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", | |
| + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "get-nonce": "^1.0.0", | |
| + "tslib": "^2.0.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">=10" | |
| + }, | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/read-cache": { | |
| + "version": "1.0.0", | |
| + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", | |
| + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "pify": "^2.3.0" | |
| + } | |
| + }, | |
| + "node_modules/readdirp": { | |
| + "version": "3.6.0", | |
| + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", | |
| + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "picomatch": "^2.2.1" | |
| + }, | |
| + "engines": { | |
| + "node": ">=8.10.0" | |
| + } | |
| + }, | |
| + "node_modules/reflect.getprototypeof": { | |
| + "version": "1.0.10", | |
| + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", | |
| + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bind": "^1.0.8", | |
| + "define-properties": "^1.2.1", | |
| + "es-abstract": "^1.23.9", | |
| + "es-errors": "^1.3.0", | |
| + "es-object-atoms": "^1.0.0", | |
| + "get-intrinsic": "^1.2.7", | |
| + "get-proto": "^1.0.1", | |
| + "which-builtin-type": "^1.2.1" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/regexp.prototype.flags": { | |
| + "version": "1.5.4", | |
| + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", | |
| + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bind": "^1.0.8", | |
| + "define-properties": "^1.2.1", | |
| + "es-errors": "^1.3.0", | |
| + "get-proto": "^1.0.1", | |
| + "gopd": "^1.2.0", | |
| + "set-function-name": "^2.0.2" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/resolve": { | |
| + "version": "1.22.11", | |
| + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", | |
| + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "is-core-module": "^2.16.1", | |
| + "path-parse": "^1.0.7", | |
| + "supports-preserve-symlinks-flag": "^1.0.0" | |
| + }, | |
| + "bin": { | |
| + "resolve": "bin/resolve" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/resolve-from": { | |
| + "version": "4.0.0", | |
| + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", | |
| + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=4" | |
| + } | |
| + }, | |
| + "node_modules/resolve-pkg-maps": { | |
| + "version": "1.0.0", | |
| + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", | |
| + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "funding": { | |
| + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" | |
| + } | |
| + }, | |
| + "node_modules/reusify": { | |
| + "version": "1.1.0", | |
| + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", | |
| + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", | |
| + "license": "MIT", | |
| + "engines": { | |
| + "iojs": ">=1.0.0", | |
| + "node": ">=0.10.0" | |
| + } | |
| + }, | |
| + "node_modules/rimraf": { | |
| + "version": "3.0.2", | |
| + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", | |
| + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", | |
| + "deprecated": "Rimraf versions prior to v4 are no longer supported", | |
| + "dev": true, | |
| + "license": "ISC", | |
| + "dependencies": { | |
| + "glob": "^7.1.3" | |
| + }, | |
| + "bin": { | |
| + "rimraf": "bin.js" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/isaacs" | |
| + } | |
| + }, | |
| + "node_modules/rimraf/node_modules/glob": { | |
| + "version": "7.2.3", | |
| + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", | |
| + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", | |
| + "deprecated": "Glob versions prior to v9 are no longer supported", | |
| + "dev": true, | |
| + "license": "ISC", | |
| + "dependencies": { | |
| + "fs.realpath": "^1.0.0", | |
| + "inflight": "^1.0.4", | |
| + "inherits": "2", | |
| + "minimatch": "^3.1.1", | |
| + "once": "^1.3.0", | |
| + "path-is-absolute": "^1.0.0" | |
| + }, | |
| + "engines": { | |
| + "node": "*" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/isaacs" | |
| + } | |
| + }, | |
| + "node_modules/run-parallel": { | |
| + "version": "1.2.0", | |
| + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", | |
| + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", | |
| + "funding": [ | |
| + { | |
| + "type": "github", | |
| + "url": "https://github.com/sponsors/feross" | |
| + }, | |
| + { | |
| + "type": "patreon", | |
| + "url": "https://www.patreon.com/feross" | |
| + }, | |
| + { | |
| + "type": "consulting", | |
| + "url": "https://feross.org/support" | |
| + } | |
| + ], | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "queue-microtask": "^1.2.2" | |
| + } | |
| + }, | |
| + "node_modules/safe-array-concat": { | |
| + "version": "1.1.3", | |
| + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", | |
| + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bind": "^1.0.8", | |
| + "call-bound": "^1.0.2", | |
| + "get-intrinsic": "^1.2.6", | |
| + "has-symbols": "^1.1.0", | |
| + "isarray": "^2.0.5" | |
| + }, | |
| + "engines": { | |
| + "node": ">=0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/safe-push-apply": { | |
| + "version": "1.0.0", | |
| + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", | |
| + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "es-errors": "^1.3.0", | |
| + "isarray": "^2.0.5" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/safe-regex-test": { | |
| + "version": "1.1.0", | |
| + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", | |
| + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bound": "^1.0.2", | |
| + "es-errors": "^1.3.0", | |
| + "is-regex": "^1.2.1" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/scheduler": { | |
| + "version": "0.23.2", | |
| + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", | |
| + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "loose-envify": "^1.1.0" | |
| + } | |
| + }, | |
| + "node_modules/semver": { | |
| + "version": "7.7.3", | |
| + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", | |
| + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", | |
| + "dev": true, | |
| + "license": "ISC", | |
| + "bin": { | |
| + "semver": "bin/semver.js" | |
| + }, | |
| + "engines": { | |
| + "node": ">=10" | |
| + } | |
| + }, | |
| + "node_modules/set-function-length": { | |
| + "version": "1.2.2", | |
| + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", | |
| + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "define-data-property": "^1.1.4", | |
| + "es-errors": "^1.3.0", | |
| + "function-bind": "^1.1.2", | |
| + "get-intrinsic": "^1.2.4", | |
| + "gopd": "^1.0.1", | |
| + "has-property-descriptors": "^1.0.2" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + } | |
| + }, | |
| + "node_modules/set-function-name": { | |
| + "version": "2.0.2", | |
| + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", | |
| + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "define-data-property": "^1.1.4", | |
| + "es-errors": "^1.3.0", | |
| + "functions-have-names": "^1.2.3", | |
| + "has-property-descriptors": "^1.0.2" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + } | |
| + }, | |
| + "node_modules/set-proto": { | |
| + "version": "1.0.0", | |
| + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", | |
| + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "dunder-proto": "^1.0.1", | |
| + "es-errors": "^1.3.0", | |
| + "es-object-atoms": "^1.0.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + } | |
| + }, | |
| + "node_modules/shebang-command": { | |
| + "version": "2.0.0", | |
| + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", | |
| + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "shebang-regex": "^3.0.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">=8" | |
| + } | |
| + }, | |
| + "node_modules/shebang-regex": { | |
| + "version": "3.0.0", | |
| + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", | |
| + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=8" | |
| + } | |
| + }, | |
| + "node_modules/side-channel": { | |
| + "version": "1.1.0", | |
| + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", | |
| + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "es-errors": "^1.3.0", | |
| + "object-inspect": "^1.13.3", | |
| + "side-channel-list": "^1.0.0", | |
| + "side-channel-map": "^1.0.1", | |
| + "side-channel-weakmap": "^1.0.2" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/side-channel-list": { | |
| + "version": "1.0.0", | |
| + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", | |
| + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "es-errors": "^1.3.0", | |
| + "object-inspect": "^1.13.3" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/side-channel-map": { | |
| + "version": "1.0.1", | |
| + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", | |
| + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bound": "^1.0.2", | |
| + "es-errors": "^1.3.0", | |
| + "get-intrinsic": "^1.2.5", | |
| + "object-inspect": "^1.13.3" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/side-channel-weakmap": { | |
| + "version": "1.0.2", | |
| + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", | |
| + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bound": "^1.0.2", | |
| + "es-errors": "^1.3.0", | |
| + "get-intrinsic": "^1.2.5", | |
| + "object-inspect": "^1.13.3", | |
| + "side-channel-map": "^1.0.1" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/signal-exit": { | |
| + "version": "4.1.0", | |
| + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", | |
| + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", | |
| + "dev": true, | |
| + "license": "ISC", | |
| + "engines": { | |
| + "node": ">=14" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/isaacs" | |
| + } | |
| + }, | |
| + "node_modules/source-map-js": { | |
| + "version": "1.2.1", | |
| + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", | |
| + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", | |
| + "license": "BSD-3-Clause", | |
| + "engines": { | |
| + "node": ">=0.10.0" | |
| + } | |
| + }, | |
| + "node_modules/stable-hash": { | |
| + "version": "0.0.5", | |
| + "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz", | |
| + "integrity": "sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==", | |
| + "dev": true, | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/stop-iteration-iterator": { | |
| + "version": "1.1.0", | |
| + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", | |
| + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "es-errors": "^1.3.0", | |
| + "internal-slot": "^1.1.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + } | |
| + }, | |
| + "node_modules/streamsearch": { | |
| + "version": "1.1.0", | |
| + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", | |
| + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", | |
| + "engines": { | |
| + "node": ">=10.0.0" | |
| + } | |
| + }, | |
| + "node_modules/string-width": { | |
| + "version": "5.1.2", | |
| + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", | |
| + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "eastasianwidth": "^0.2.0", | |
| + "emoji-regex": "^9.2.2", | |
| + "strip-ansi": "^7.0.1" | |
| + }, | |
| + "engines": { | |
| + "node": ">=12" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/sindresorhus" | |
| + } | |
| + }, | |
| + "node_modules/string-width-cjs": { | |
| + "name": "string-width", | |
| + "version": "4.2.3", | |
| + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", | |
| + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "emoji-regex": "^8.0.0", | |
| + "is-fullwidth-code-point": "^3.0.0", | |
| + "strip-ansi": "^6.0.1" | |
| + }, | |
| + "engines": { | |
| + "node": ">=8" | |
| + } | |
| + }, | |
| + "node_modules/string-width-cjs/node_modules/emoji-regex": { | |
| + "version": "8.0.0", | |
| + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", | |
| + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", | |
| + "dev": true, | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/string-width/node_modules/ansi-regex": { | |
| + "version": "6.2.2", | |
| + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", | |
| + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=12" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/chalk/ansi-regex?sponsor=1" | |
| + } | |
| + }, | |
| + "node_modules/string-width/node_modules/strip-ansi": { | |
| + "version": "7.1.2", | |
| + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", | |
| + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "ansi-regex": "^6.0.1" | |
| + }, | |
| + "engines": { | |
| + "node": ">=12" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/chalk/strip-ansi?sponsor=1" | |
| + } | |
| + }, | |
| + "node_modules/string.prototype.includes": { | |
| + "version": "2.0.1", | |
| + "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", | |
| + "integrity": "sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bind": "^1.0.7", | |
| + "define-properties": "^1.2.1", | |
| + "es-abstract": "^1.23.3" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + } | |
| + }, | |
| + "node_modules/string.prototype.matchall": { | |
| + "version": "4.0.12", | |
| + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", | |
| + "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bind": "^1.0.8", | |
| + "call-bound": "^1.0.3", | |
| + "define-properties": "^1.2.1", | |
| + "es-abstract": "^1.23.6", | |
| + "es-errors": "^1.3.0", | |
| + "es-object-atoms": "^1.0.0", | |
| + "get-intrinsic": "^1.2.6", | |
| + "gopd": "^1.2.0", | |
| + "has-symbols": "^1.1.0", | |
| + "internal-slot": "^1.1.0", | |
| + "regexp.prototype.flags": "^1.5.3", | |
| + "set-function-name": "^2.0.2", | |
| + "side-channel": "^1.1.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/string.prototype.repeat": { | |
| + "version": "1.0.0", | |
| + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", | |
| + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "define-properties": "^1.1.3", | |
| + "es-abstract": "^1.17.5" | |
| + } | |
| + }, | |
| + "node_modules/string.prototype.trim": { | |
| + "version": "1.2.10", | |
| + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", | |
| + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bind": "^1.0.8", | |
| + "call-bound": "^1.0.2", | |
| + "define-data-property": "^1.1.4", | |
| + "define-properties": "^1.2.1", | |
| + "es-abstract": "^1.23.5", | |
| + "es-object-atoms": "^1.0.0", | |
| + "has-property-descriptors": "^1.0.2" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/string.prototype.trimend": { | |
| + "version": "1.0.9", | |
| + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", | |
| + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bind": "^1.0.8", | |
| + "call-bound": "^1.0.2", | |
| + "define-properties": "^1.2.1", | |
| + "es-object-atoms": "^1.0.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/string.prototype.trimstart": { | |
| + "version": "1.0.8", | |
| + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", | |
| + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bind": "^1.0.7", | |
| + "define-properties": "^1.2.1", | |
| + "es-object-atoms": "^1.0.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/strip-ansi": { | |
| + "version": "6.0.1", | |
| + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", | |
| + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "ansi-regex": "^5.0.1" | |
| + }, | |
| + "engines": { | |
| + "node": ">=8" | |
| + } | |
| + }, | |
| + "node_modules/strip-ansi-cjs": { | |
| + "name": "strip-ansi", | |
| + "version": "6.0.1", | |
| + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", | |
| + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "ansi-regex": "^5.0.1" | |
| + }, | |
| + "engines": { | |
| + "node": ">=8" | |
| + } | |
| + }, | |
| + "node_modules/strip-bom": { | |
| + "version": "3.0.0", | |
| + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", | |
| + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=4" | |
| + } | |
| + }, | |
| + "node_modules/strip-json-comments": { | |
| + "version": "3.1.1", | |
| + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", | |
| + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=8" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/sindresorhus" | |
| + } | |
| + }, | |
| + "node_modules/styled-jsx": { | |
| + "version": "5.1.1", | |
| + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", | |
| + "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "client-only": "0.0.1" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 12.0.0" | |
| + }, | |
| + "peerDependencies": { | |
| + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@babel/core": { | |
| + "optional": true | |
| + }, | |
| + "babel-plugin-macros": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/sucrase": { | |
| + "version": "3.35.1", | |
| + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", | |
| + "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@jridgewell/gen-mapping": "^0.3.2", | |
| + "commander": "^4.0.0", | |
| + "lines-and-columns": "^1.1.6", | |
| + "mz": "^2.7.0", | |
| + "pirates": "^4.0.1", | |
| + "tinyglobby": "^0.2.11", | |
| + "ts-interface-checker": "^0.1.9" | |
| + }, | |
| + "bin": { | |
| + "sucrase": "bin/sucrase", | |
| + "sucrase-node": "bin/sucrase-node" | |
| + }, | |
| + "engines": { | |
| + "node": ">=16 || 14 >=14.17" | |
| + } | |
| + }, | |
| + "node_modules/supports-color": { | |
| + "version": "7.2.0", | |
| + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", | |
| + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "has-flag": "^4.0.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">=8" | |
| + } | |
| + }, | |
| + "node_modules/supports-preserve-symlinks-flag": { | |
| + "version": "1.0.0", | |
| + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", | |
| + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/tailwind-merge": { | |
| + "version": "2.6.1", | |
| + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.6.1.tgz", | |
| + "integrity": "sha512-Oo6tHdpZsGpkKG88HJ8RR1rg/RdnEkQEfMoEk2x1XRI3F1AxeU+ijRXpiVUF4UbLfcxxRGw6TbUINKYdWVsQTQ==", | |
| + "license": "MIT", | |
| + "funding": { | |
| + "type": "github", | |
| + "url": "https://github.com/sponsors/dcastil" | |
| + } | |
| + }, | |
| + "node_modules/tailwindcss": { | |
| + "version": "3.4.19", | |
| + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", | |
| + "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@alloc/quick-lru": "^5.2.0", | |
| + "arg": "^5.0.2", | |
| + "chokidar": "^3.6.0", | |
| + "didyoumean": "^1.2.2", | |
| + "dlv": "^1.1.3", | |
| + "fast-glob": "^3.3.2", | |
| + "glob-parent": "^6.0.2", | |
| + "is-glob": "^4.0.3", | |
| + "jiti": "^1.21.7", | |
| + "lilconfig": "^3.1.3", | |
| + "micromatch": "^4.0.8", | |
| + "normalize-path": "^3.0.0", | |
| + "object-hash": "^3.0.0", | |
| + "picocolors": "^1.1.1", | |
| + "postcss": "^8.4.47", | |
| + "postcss-import": "^15.1.0", | |
| + "postcss-js": "^4.0.1", | |
| + "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", | |
| + "postcss-nested": "^6.2.0", | |
| + "postcss-selector-parser": "^6.1.2", | |
| + "resolve": "^1.22.8", | |
| + "sucrase": "^3.35.0" | |
| + }, | |
| + "bin": { | |
| + "tailwind": "lib/cli.js", | |
| + "tailwindcss": "lib/cli.js" | |
| + }, | |
| + "engines": { | |
| + "node": ">=14.0.0" | |
| + } | |
| + }, | |
| + "node_modules/tailwindcss-animate": { | |
| + "version": "1.0.7", | |
| + "resolved": "https://registry.npmjs.org/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz", | |
| + "integrity": "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==", | |
| + "license": "MIT", | |
| + "peerDependencies": { | |
| + "tailwindcss": ">=3.0.0 || insiders" | |
| + } | |
| + }, | |
| + "node_modules/text-table": { | |
| + "version": "0.2.0", | |
| + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", | |
| + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", | |
| + "dev": true, | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/thenify": { | |
| + "version": "3.3.1", | |
| + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", | |
| + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "any-promise": "^1.0.0" | |
| + } | |
| + }, | |
| + "node_modules/thenify-all": { | |
| + "version": "1.6.0", | |
| + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", | |
| + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "thenify": ">= 3.1.0 < 4" | |
| + }, | |
| + "engines": { | |
| + "node": ">=0.8" | |
| + } | |
| + }, | |
| + "node_modules/tinyglobby": { | |
| + "version": "0.2.15", | |
| + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", | |
| + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "fdir": "^6.5.0", | |
| + "picomatch": "^4.0.3" | |
| + }, | |
| + "engines": { | |
| + "node": ">=12.0.0" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/SuperchupuDev" | |
| + } | |
| + }, | |
| + "node_modules/tinyglobby/node_modules/fdir": { | |
| + "version": "6.5.0", | |
| + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", | |
| + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=12.0.0" | |
| + }, | |
| + "peerDependencies": { | |
| + "picomatch": "^3 || ^4" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "picomatch": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/tinyglobby/node_modules/picomatch": { | |
| + "version": "4.0.3", | |
| + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", | |
| + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=12" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/jonschlinkert" | |
| + } | |
| + }, | |
| + "node_modules/to-regex-range": { | |
| + "version": "5.0.1", | |
| + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", | |
| + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "is-number": "^7.0.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">=8.0" | |
| + } | |
| + }, | |
| + "node_modules/topojson-client": { | |
| + "version": "3.1.0", | |
| + "resolved": "https://registry.npmjs.org/topojson-client/-/topojson-client-3.1.0.tgz", | |
| + "integrity": "sha512-605uxS6bcYxGXw9qi62XyrV6Q3xwbndjachmNxu8HWTtVPxZfEJN9fd/SZS1Q54Sn2y0TMyMxFj/cJINqGHrKw==", | |
| + "license": "ISC", | |
| + "dependencies": { | |
| + "commander": "2" | |
| + }, | |
| + "bin": { | |
| + "topo2geo": "bin/topo2geo", | |
| + "topomerge": "bin/topomerge", | |
| + "topoquantize": "bin/topoquantize" | |
| + } | |
| + }, | |
| + "node_modules/topojson-client/node_modules/commander": { | |
| + "version": "2.20.3", | |
| + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", | |
| + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/ts-api-utils": { | |
| + "version": "2.4.0", | |
| + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", | |
| + "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=18.12" | |
| + }, | |
| + "peerDependencies": { | |
| + "typescript": ">=4.8.4" | |
| + } | |
| + }, | |
| + "node_modules/ts-interface-checker": { | |
| + "version": "0.1.13", | |
| + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", | |
| + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", | |
| + "license": "Apache-2.0" | |
| + }, | |
| + "node_modules/tsconfig-paths": { | |
| + "version": "3.15.0", | |
| + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", | |
| + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@types/json5": "^0.0.29", | |
| + "json5": "^1.0.2", | |
| + "minimist": "^1.2.6", | |
| + "strip-bom": "^3.0.0" | |
| + } | |
| + }, | |
| + "node_modules/tslib": { | |
| + "version": "2.8.1", | |
| + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", | |
| + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", | |
| + "license": "0BSD" | |
| + }, | |
| + "node_modules/type-check": { | |
| + "version": "0.4.0", | |
| + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", | |
| + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "prelude-ls": "^1.2.1" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.8.0" | |
| + } | |
| + }, | |
| + "node_modules/type-fest": { | |
| + "version": "0.20.2", | |
| + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", | |
| + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", | |
| + "dev": true, | |
| + "license": "(MIT OR CC0-1.0)", | |
| + "engines": { | |
| + "node": ">=10" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/sindresorhus" | |
| + } | |
| + }, | |
| + "node_modules/typed-array-buffer": { | |
| + "version": "1.0.3", | |
| + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", | |
| + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bound": "^1.0.3", | |
| + "es-errors": "^1.3.0", | |
| + "is-typed-array": "^1.1.14" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + } | |
| + }, | |
| + "node_modules/typed-array-byte-length": { | |
| + "version": "1.0.3", | |
| + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", | |
| + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bind": "^1.0.8", | |
| + "for-each": "^0.3.3", | |
| + "gopd": "^1.2.0", | |
| + "has-proto": "^1.2.0", | |
| + "is-typed-array": "^1.1.14" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/typed-array-byte-offset": { | |
| + "version": "1.0.4", | |
| + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", | |
| + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "available-typed-arrays": "^1.0.7", | |
| + "call-bind": "^1.0.8", | |
| + "for-each": "^0.3.3", | |
| + "gopd": "^1.2.0", | |
| + "has-proto": "^1.2.0", | |
| + "is-typed-array": "^1.1.15", | |
| + "reflect.getprototypeof": "^1.0.9" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/typed-array-length": { | |
| + "version": "1.0.7", | |
| + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", | |
| + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bind": "^1.0.7", | |
| + "for-each": "^0.3.3", | |
| + "gopd": "^1.0.1", | |
| + "is-typed-array": "^1.1.13", | |
| + "possible-typed-array-names": "^1.0.0", | |
| + "reflect.getprototypeof": "^1.0.6" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/typescript": { | |
| + "version": "5.9.3", | |
| + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", | |
| + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", | |
| + "dev": true, | |
| + "license": "Apache-2.0", | |
| + "bin": { | |
| + "tsc": "bin/tsc", | |
| + "tsserver": "bin/tsserver" | |
| + }, | |
| + "engines": { | |
| + "node": ">=14.17" | |
| + } | |
| + }, | |
| + "node_modules/unbox-primitive": { | |
| + "version": "1.1.0", | |
| + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", | |
| + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bound": "^1.0.3", | |
| + "has-bigints": "^1.0.2", | |
| + "has-symbols": "^1.1.0", | |
| + "which-boxed-primitive": "^1.1.1" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/undici-types": { | |
| + "version": "6.21.0", | |
| + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", | |
| + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/unrs-resolver": { | |
| + "version": "1.11.1", | |
| + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz", | |
| + "integrity": "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==", | |
| + "dev": true, | |
| + "hasInstallScript": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "napi-postinstall": "^0.3.0" | |
| + }, | |
| + "funding": { | |
| + "url": "https://opencollective.com/unrs-resolver" | |
| + }, | |
| + "optionalDependencies": { | |
| + "@unrs/resolver-binding-android-arm-eabi": "1.11.1", | |
| + "@unrs/resolver-binding-android-arm64": "1.11.1", | |
| + "@unrs/resolver-binding-darwin-arm64": "1.11.1", | |
| + "@unrs/resolver-binding-darwin-x64": "1.11.1", | |
| + "@unrs/resolver-binding-freebsd-x64": "1.11.1", | |
| + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", | |
| + "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", | |
| + "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", | |
| + "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", | |
| + "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", | |
| + "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", | |
| + "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", | |
| + "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", | |
| + "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", | |
| + "@unrs/resolver-binding-linux-x64-musl": "1.11.1", | |
| + "@unrs/resolver-binding-wasm32-wasi": "1.11.1", | |
| + "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", | |
| + "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", | |
| + "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" | |
| + } | |
| + }, | |
| + "node_modules/update-browserslist-db": { | |
| + "version": "1.2.3", | |
| + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", | |
| + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", | |
| + "dev": true, | |
| + "funding": [ | |
| + { | |
| + "type": "opencollective", | |
| + "url": "https://opencollective.com/browserslist" | |
| + }, | |
| + { | |
| + "type": "tidelift", | |
| + "url": "https://tidelift.com/funding/github/npm/browserslist" | |
| + }, | |
| + { | |
| + "type": "github", | |
| + "url": "https://github.com/sponsors/ai" | |
| + } | |
| + ], | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "escalade": "^3.2.0", | |
| + "picocolors": "^1.1.1" | |
| + }, | |
| + "bin": { | |
| + "update-browserslist-db": "cli.js" | |
| + }, | |
| + "peerDependencies": { | |
| + "browserslist": ">= 4.21.0" | |
| + } | |
| + }, | |
| + "node_modules/uri-js": { | |
| + "version": "4.4.1", | |
| + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", | |
| + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", | |
| + "dev": true, | |
| + "license": "BSD-2-Clause", | |
| + "dependencies": { | |
| + "punycode": "^2.1.0" | |
| + } | |
| + }, | |
| + "node_modules/urijs": { | |
| + "version": "1.19.11", | |
| + "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.11.tgz", | |
| + "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==", | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/use-callback-ref": { | |
| + "version": "1.3.3", | |
| + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", | |
| + "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "tslib": "^2.0.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">=10" | |
| + }, | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/use-sidecar": { | |
| + "version": "1.1.3", | |
| + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", | |
| + "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "detect-node-es": "^1.1.0", | |
| + "tslib": "^2.0.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">=10" | |
| + }, | |
| + "peerDependencies": { | |
| + "@types/react": "*", | |
| + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/util-deprecate": { | |
| + "version": "1.0.2", | |
| + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", | |
| + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/which": { | |
| + "version": "2.0.2", | |
| + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", | |
| + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", | |
| + "dev": true, | |
| + "license": "ISC", | |
| + "dependencies": { | |
| + "isexe": "^2.0.0" | |
| + }, | |
| + "bin": { | |
| + "node-which": "bin/node-which" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 8" | |
| + } | |
| + }, | |
| + "node_modules/which-boxed-primitive": { | |
| + "version": "1.1.1", | |
| + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", | |
| + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "is-bigint": "^1.1.0", | |
| + "is-boolean-object": "^1.2.1", | |
| + "is-number-object": "^1.1.1", | |
| + "is-string": "^1.1.1", | |
| + "is-symbol": "^1.1.1" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/which-builtin-type": { | |
| + "version": "1.2.1", | |
| + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", | |
| + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "call-bound": "^1.0.2", | |
| + "function.prototype.name": "^1.1.6", | |
| + "has-tostringtag": "^1.0.2", | |
| + "is-async-function": "^2.0.0", | |
| + "is-date-object": "^1.1.0", | |
| + "is-finalizationregistry": "^1.1.0", | |
| + "is-generator-function": "^1.0.10", | |
| + "is-regex": "^1.2.1", | |
| + "is-weakref": "^1.0.2", | |
| + "isarray": "^2.0.5", | |
| + "which-boxed-primitive": "^1.1.0", | |
| + "which-collection": "^1.0.2", | |
| + "which-typed-array": "^1.1.16" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/which-collection": { | |
| + "version": "1.0.2", | |
| + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", | |
| + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "is-map": "^2.0.3", | |
| + "is-set": "^2.0.3", | |
| + "is-weakmap": "^2.0.2", | |
| + "is-weakset": "^2.0.3" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/which-typed-array": { | |
| + "version": "1.1.20", | |
| + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz", | |
| + "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "available-typed-arrays": "^1.0.7", | |
| + "call-bind": "^1.0.8", | |
| + "call-bound": "^1.0.4", | |
| + "for-each": "^0.3.5", | |
| + "get-proto": "^1.0.1", | |
| + "gopd": "^1.2.0", | |
| + "has-tostringtag": "^1.0.2" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.4" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/ljharb" | |
| + } | |
| + }, | |
| + "node_modules/word-wrap": { | |
| + "version": "1.2.5", | |
| + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", | |
| + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=0.10.0" | |
| + } | |
| + }, | |
| + "node_modules/wrap-ansi": { | |
| + "version": "8.1.0", | |
| + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", | |
| + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "ansi-styles": "^6.1.0", | |
| + "string-width": "^5.0.1", | |
| + "strip-ansi": "^7.0.1" | |
| + }, | |
| + "engines": { | |
| + "node": ">=12" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" | |
| + } | |
| + }, | |
| + "node_modules/wrap-ansi-cjs": { | |
| + "name": "wrap-ansi", | |
| + "version": "7.0.0", | |
| + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", | |
| + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "ansi-styles": "^4.0.0", | |
| + "string-width": "^4.1.0", | |
| + "strip-ansi": "^6.0.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">=10" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" | |
| + } | |
| + }, | |
| + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { | |
| + "version": "8.0.0", | |
| + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", | |
| + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", | |
| + "dev": true, | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/wrap-ansi-cjs/node_modules/string-width": { | |
| + "version": "4.2.3", | |
| + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", | |
| + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "emoji-regex": "^8.0.0", | |
| + "is-fullwidth-code-point": "^3.0.0", | |
| + "strip-ansi": "^6.0.1" | |
| + }, | |
| + "engines": { | |
| + "node": ">=8" | |
| + } | |
| + }, | |
| + "node_modules/wrap-ansi/node_modules/ansi-regex": { | |
| + "version": "6.2.2", | |
| + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", | |
| + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=12" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/chalk/ansi-regex?sponsor=1" | |
| + } | |
| + }, | |
| + "node_modules/wrap-ansi/node_modules/ansi-styles": { | |
| + "version": "6.2.3", | |
| + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", | |
| + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=12" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/chalk/ansi-styles?sponsor=1" | |
| + } | |
| + }, | |
| + "node_modules/wrap-ansi/node_modules/strip-ansi": { | |
| + "version": "7.1.2", | |
| + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", | |
| + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "ansi-regex": "^6.0.1" | |
| + }, | |
| + "engines": { | |
| + "node": ">=12" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/chalk/strip-ansi?sponsor=1" | |
| + } | |
| + }, | |
| + "node_modules/wrappy": { | |
| + "version": "1.0.2", | |
| + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", | |
| + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", | |
| + "dev": true, | |
| + "license": "ISC" | |
| + }, | |
| + "node_modules/yocto-queue": { | |
| + "version": "0.1.0", | |
| + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", | |
| + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", | |
| + "dev": true, | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=10" | |
| + }, | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/sindresorhus" | |
| + } | |
| + }, | |
| + "node_modules/zod": { | |
| + "version": "3.25.76", | |
| + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", | |
| + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", | |
| + "license": "MIT", | |
| + "funding": { | |
| + "url": "https://github.com/sponsors/colinhacks" | |
| + } | |
| + }, | |
| + "node_modules/zustand": { | |
| + "version": "5.0.11", | |
| + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.11.tgz", | |
| + "integrity": "sha512-fdZY+dk7zn/vbWNCYmzZULHRrss0jx5pPFiOuMZ/5HJN6Yv3u+1Wswy/4MpZEkEGhtNH+pwxZB8OKgUBPzYAGg==", | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=12.20.0" | |
| + }, | |
| + "peerDependencies": { | |
| + "@types/react": ">=18.0.0", | |
| + "immer": ">=9.0.6", | |
| + "react": ">=18.0.0", | |
| + "use-sync-external-store": ">=1.2.0" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "@types/react": { | |
| + "optional": true | |
| + }, | |
| + "immer": { | |
| + "optional": true | |
| + }, | |
| + "react": { | |
| + "optional": true | |
| + }, | |
| + "use-sync-external-store": { | |
| + "optional": true | |
| + } | |
| + } | |
| + } | |
| + } | |
| +} | |
| diff --git a/package.json b/package.json | |
| new file mode 100644 | |
| index 0000000..cf8ea60 | |
| --- /dev/null | |
| +++ b/package.json | |
| @@ -0,0 +1,46 @@ | |
| +{ | |
| + "name": "terraview", | |
| + "version": "1.0.0", | |
| + "private": true, | |
| + "scripts": { | |
| + "dev": "next dev", | |
| + "build": "next build", | |
| + "start": "next start", | |
| + "lint": "next lint", | |
| + "lint:fix": "next lint --fix" | |
| + }, | |
| + "dependencies": { | |
| + "@radix-ui/react-dialog": "^1.1.2", | |
| + "@radix-ui/react-dropdown-menu": "^2.1.2", | |
| + "@radix-ui/react-label": "^2.1.0", | |
| + "@radix-ui/react-scroll-area": "^1.2.0", | |
| + "@radix-ui/react-slot": "^1.1.0", | |
| + "@radix-ui/react-switch": "^1.1.1", | |
| + "@radix-ui/react-tabs": "^1.1.1", | |
| + "@radix-ui/react-toast": "^1.2.2", | |
| + "@radix-ui/react-tooltip": "^1.1.3", | |
| + "cesium": "^1.122.0", | |
| + "class-variance-authority": "^0.7.0", | |
| + "clsx": "^2.1.1", | |
| + "lucide-react": "^0.454.0", | |
| + "next": "14.2.15", | |
| + "next-themes": "^0.3.0", | |
| + "react": "18.2.0", | |
| + "react-dom": "18.2.0", | |
| + "tailwind-merge": "^2.5.4", | |
| + "tailwindcss-animate": "^1.0.7", | |
| + "zod": "^3.23.8", | |
| + "zustand": "^5.0.1" | |
| + }, | |
| + "devDependencies": { | |
| + "@types/node": "^22.8.1", | |
| + "@types/react": "^18.2.0", | |
| + "@types/react-dom": "^18.2.0", | |
| + "autoprefixer": "^10.4.20", | |
| + "eslint": "^8.57.1", | |
| + "eslint-config-next": "14.2.15", | |
| + "postcss": "^8.4.47", | |
| + "tailwindcss": "^3.4.14", | |
| + "typescript": "^5.6.3" | |
| + } | |
| +} | |
| diff --git a/postcss.config.js b/postcss.config.js | |
| new file mode 100644 | |
| index 0000000..12a703d | |
| --- /dev/null | |
| +++ b/postcss.config.js | |
| @@ -0,0 +1,6 @@ | |
| +module.exports = { | |
| + plugins: { | |
| + tailwindcss: {}, | |
| + autoprefixer: {}, | |
| + }, | |
| +}; | |
| diff --git a/store/index.ts b/store/index.ts | |
| new file mode 100644 | |
| index 0000000..5fc8b11 | |
| --- /dev/null | |
| +++ b/store/index.ts | |
| @@ -0,0 +1,4 @@ | |
| +export { useGlobeStore } from './useGlobeStore'; | |
| +export { usePlacesStore } from './usePlacesStore'; | |
| +export { useLayersStore } from './useLayersStore'; | |
| +export { useMeasureStore } from './useMeasureStore'; | |
| diff --git a/store/useGlobeStore.ts b/store/useGlobeStore.ts | |
| new file mode 100644 | |
| index 0000000..5556ced | |
| --- /dev/null | |
| +++ b/store/useGlobeStore.ts | |
| @@ -0,0 +1,44 @@ | |
| +import { create } from 'zustand'; | |
| +import type { CursorPosition, PanelTab, GlobeRef } from '@/types'; | |
| + | |
| +interface GlobeState { | |
| + isLoading: boolean; | |
| + cursorPosition: CursorPosition | null; | |
| + cameraAltitude: number; | |
| + activeTab: PanelTab; | |
| + isPanelOpen: boolean; | |
| + isMeasuring: boolean; | |
| + pendingPinLocation: { latitude: number; longitude: number } | null; | |
| + globeRef: GlobeRef | null; | |
| + | |
| + setIsLoading: (loading: boolean) => void; | |
| + setCursorPosition: (position: CursorPosition | null) => void; | |
| + setCameraAltitude: (altitude: number) => void; | |
| + setActiveTab: (tab: PanelTab) => void; | |
| + togglePanel: () => void; | |
| + setIsPanelOpen: (open: boolean) => void; | |
| + setIsMeasuring: (measuring: boolean) => void; | |
| + setPendingPinLocation: (location: { latitude: number; longitude: number } | null) => void; | |
| + setGlobeRef: (ref: GlobeRef | null) => void; | |
| +} | |
| + | |
| +export const useGlobeStore = create<GlobeState>((set) => ({ | |
| + isLoading: true, | |
| + cursorPosition: null, | |
| + cameraAltitude: 20000000, | |
| + activeTab: 'layers', | |
| + isPanelOpen: true, | |
| + isMeasuring: false, | |
| + pendingPinLocation: null, | |
| + globeRef: null, | |
| + | |
| + setIsLoading: (loading) => set({ isLoading: loading }), | |
| + setCursorPosition: (position) => set({ cursorPosition: position }), | |
| + setCameraAltitude: (altitude) => set({ cameraAltitude: altitude }), | |
| + setActiveTab: (tab) => set({ activeTab: tab }), | |
| + togglePanel: () => set((state) => ({ isPanelOpen: !state.isPanelOpen })), | |
| + setIsPanelOpen: (open) => set({ isPanelOpen: open }), | |
| + setIsMeasuring: (measuring) => set({ isMeasuring: measuring }), | |
| + setPendingPinLocation: (location) => set({ pendingPinLocation: location }), | |
| + setGlobeRef: (ref) => set({ globeRef: ref }), | |
| +})); | |
| diff --git a/store/useLayersStore.ts b/store/useLayersStore.ts | |
| new file mode 100644 | |
| index 0000000..cdff73d | |
| --- /dev/null | |
| +++ b/store/useLayersStore.ts | |
| @@ -0,0 +1,73 @@ | |
| +import { create } from 'zustand'; | |
| +import type { LayerState, BaseLayerType } from '@/types'; | |
| +import { loadLayers, saveLayers } from '@/lib/storage'; | |
| + | |
| +interface LayersStoreState extends LayerState { | |
| + isInitialized: boolean; | |
| + | |
| + initializeLayers: () => void; | |
| + setBaseLayer: (layer: BaseLayerType) => void; | |
| + toggleOverlay: (overlay: keyof LayerState['overlays']) => void; | |
| + setOverlay: (overlay: keyof LayerState['overlays'], enabled: boolean) => void; | |
| +} | |
| + | |
| +const DEFAULT_LAYERS: LayerState = { | |
| + baseLayer: 'arcgis', | |
| + overlays: { | |
| + borders: false, | |
| + labels: true, | |
| + roads: false, | |
| + }, | |
| +}; | |
| + | |
| +export const useLayersStore = create<LayersStoreState>((set, get) => ({ | |
| + ...DEFAULT_LAYERS, | |
| + isInitialized: false, | |
| + | |
| + initializeLayers: () => { | |
| + if (get().isInitialized) return; | |
| + const loaded = loadLayers(); | |
| + if (loaded) { | |
| + set({ ...loaded, isInitialized: true }); | |
| + } else { | |
| + set({ isInitialized: true }); | |
| + } | |
| + }, | |
| + | |
| + setBaseLayer: (layer) => { | |
| + set({ baseLayer: layer }); | |
| + const state = get(); | |
| + saveLayers({ | |
| + baseLayer: state.baseLayer, | |
| + overlays: state.overlays, | |
| + }); | |
| + }, | |
| + | |
| + toggleOverlay: (overlay) => { | |
| + set((state) => ({ | |
| + overlays: { | |
| + ...state.overlays, | |
| + [overlay]: !state.overlays[overlay], | |
| + }, | |
| + })); | |
| + const state = get(); | |
| + saveLayers({ | |
| + baseLayer: state.baseLayer, | |
| + overlays: state.overlays, | |
| + }); | |
| + }, | |
| + | |
| + setOverlay: (overlay, enabled) => { | |
| + set((state) => ({ | |
| + overlays: { | |
| + ...state.overlays, | |
| + [overlay]: enabled, | |
| + }, | |
| + })); | |
| + const state = get(); | |
| + saveLayers({ | |
| + baseLayer: state.baseLayer, | |
| + overlays: state.overlays, | |
| + }); | |
| + }, | |
| +})); | |
| diff --git a/store/useMeasureStore.ts b/store/useMeasureStore.ts | |
| new file mode 100644 | |
| index 0000000..3926c1c | |
| --- /dev/null | |
| +++ b/store/useMeasureStore.ts | |
| @@ -0,0 +1,70 @@ | |
| +import { create } from 'zustand'; | |
| +import type { MeasurementPoint, Coordinates } from '@/types'; | |
| +import { generateId } from '@/lib/utils'; | |
| +import { calculateHaversineDistance } from '@/lib/formatting'; | |
| + | |
| +interface MeasureState { | |
| + points: MeasurementPoint[]; | |
| + isActive: boolean; | |
| + totalDistance: number; | |
| + | |
| + startMeasuring: () => void; | |
| + stopMeasuring: () => void; | |
| + addPoint: (coordinates: Coordinates) => void; | |
| + removeLastPoint: () => void; | |
| + clearMeasurement: () => void; | |
| +} | |
| + | |
| +function calculateTotalDistance(points: MeasurementPoint[]): number { | |
| + if (points.length < 2) return 0; | |
| + | |
| + let total = 0; | |
| + for (let i = 1; i < points.length; i++) { | |
| + total += calculateHaversineDistance( | |
| + points[i - 1].coordinates, | |
| + points[i].coordinates | |
| + ); | |
| + } | |
| + return total; | |
| +} | |
| + | |
| +export const useMeasureStore = create<MeasureState>((set, get) => ({ | |
| + points: [], | |
| + isActive: false, | |
| + totalDistance: 0, | |
| + | |
| + startMeasuring: () => { | |
| + set({ isActive: true, points: [], totalDistance: 0 }); | |
| + }, | |
| + | |
| + stopMeasuring: () => { | |
| + set({ isActive: false }); | |
| + }, | |
| + | |
| + addPoint: (coordinates) => { | |
| + const newPoint: MeasurementPoint = { | |
| + id: generateId(), | |
| + coordinates, | |
| + }; | |
| + const updatedPoints = [...get().points, newPoint]; | |
| + set({ | |
| + points: updatedPoints, | |
| + totalDistance: calculateTotalDistance(updatedPoints), | |
| + }); | |
| + }, | |
| + | |
| + removeLastPoint: () => { | |
| + const currentPoints = get().points; | |
| + if (currentPoints.length === 0) return; | |
| + | |
| + const updatedPoints = currentPoints.slice(0, -1); | |
| + set({ | |
| + points: updatedPoints, | |
| + totalDistance: calculateTotalDistance(updatedPoints), | |
| + }); | |
| + }, | |
| + | |
| + clearMeasurement: () => { | |
| + set({ points: [], totalDistance: 0 }); | |
| + }, | |
| +})); | |
| diff --git a/store/usePlacesStore.ts b/store/usePlacesStore.ts | |
| new file mode 100644 | |
| index 0000000..9a55aad | |
| --- /dev/null | |
| +++ b/store/usePlacesStore.ts | |
| @@ -0,0 +1,82 @@ | |
| +import { create } from 'zustand'; | |
| +import type { SavedPlace, Coordinates } from '@/types'; | |
| +import { loadPlaces, savePlaces, importPlaces } from '@/lib/storage'; | |
| +import { generateId } from '@/lib/utils'; | |
| + | |
| +interface PlacesState { | |
| + places: SavedPlace[]; | |
| + isInitialized: boolean; | |
| + | |
| + initializePlaces: () => void; | |
| + addPlace: (name: string, note: string, coordinates: Coordinates) => SavedPlace; | |
| + updatePlace: (id: string, updates: Partial<Pick<SavedPlace, 'name' | 'note'>>) => void; | |
| + deletePlace: (id: string) => void; | |
| + importPlacesFromJson: (json: string) => boolean; | |
| + clearAllPlaces: () => void; | |
| +} | |
| + | |
| +export const usePlacesStore = create<PlacesState>((set, get) => ({ | |
| + places: [], | |
| + isInitialized: false, | |
| + | |
| + initializePlaces: () => { | |
| + if (get().isInitialized) return; | |
| + const loaded = loadPlaces(); | |
| + set({ places: loaded, isInitialized: true }); | |
| + }, | |
| + | |
| + addPlace: (name, note, coordinates) => { | |
| + const now = new Date().toISOString(); | |
| + const newPlace: SavedPlace = { | |
| + id: generateId(), | |
| + name, | |
| + note, | |
| + coordinates, | |
| + createdAt: now, | |
| + updatedAt: now, | |
| + }; | |
| + | |
| + const updatedPlaces = [...get().places, newPlace]; | |
| + set({ places: updatedPlaces }); | |
| + savePlaces(updatedPlaces); | |
| + | |
| + return newPlace; | |
| + }, | |
| + | |
| + updatePlace: (id, updates) => { | |
| + const updatedPlaces = get().places.map((place) => | |
| + place.id === id | |
| + ? { ...place, ...updates, updatedAt: new Date().toISOString() } | |
| + : place | |
| + ); | |
| + set({ places: updatedPlaces }); | |
| + savePlaces(updatedPlaces); | |
| + }, | |
| + | |
| + deletePlace: (id) => { | |
| + const updatedPlaces = get().places.filter((place) => place.id !== id); | |
| + set({ places: updatedPlaces }); | |
| + savePlaces(updatedPlaces); | |
| + }, | |
| + | |
| + importPlacesFromJson: (json) => { | |
| + const imported = importPlaces(json); | |
| + if (!imported) return false; | |
| + | |
| + const existingIds = new Set(get().places.map((p) => p.id)); | |
| + const newPlaces = imported.map((place) => ({ | |
| + ...place, | |
| + id: existingIds.has(place.id) ? generateId() : place.id, | |
| + })); | |
| + | |
| + const updatedPlaces = [...get().places, ...newPlaces]; | |
| + set({ places: updatedPlaces }); | |
| + savePlaces(updatedPlaces); | |
| + return true; | |
| + }, | |
| + | |
| + clearAllPlaces: () => { | |
| + set({ places: [] }); | |
| + savePlaces([]); | |
| + }, | |
| +})); | |
| diff --git a/tailwind.config.ts b/tailwind.config.ts | |
| new file mode 100644 | |
| index 0000000..098afb2 | |
| --- /dev/null | |
| +++ b/tailwind.config.ts | |
| @@ -0,0 +1,76 @@ | |
| +import type { Config } from 'tailwindcss'; | |
| + | |
| +const config: Config = { | |
| + darkMode: ['class'], | |
| + content: [ | |
| + './pages/**/*.{js,ts,jsx,tsx,mdx}', | |
| + './components/**/*.{js,ts,jsx,tsx,mdx}', | |
| + './app/**/*.{js,ts,jsx,tsx,mdx}', | |
| + ], | |
| + theme: { | |
| + extend: { | |
| + colors: { | |
| + border: 'hsl(var(--border))', | |
| + input: 'hsl(var(--input))', | |
| + ring: 'hsl(var(--ring))', | |
| + background: 'hsl(var(--background))', | |
| + foreground: 'hsl(var(--foreground))', | |
| + primary: { | |
| + DEFAULT: 'hsl(var(--primary))', | |
| + foreground: 'hsl(var(--primary-foreground))', | |
| + }, | |
| + secondary: { | |
| + DEFAULT: 'hsl(var(--secondary))', | |
| + foreground: 'hsl(var(--secondary-foreground))', | |
| + }, | |
| + destructive: { | |
| + DEFAULT: 'hsl(var(--destructive))', | |
| + foreground: 'hsl(var(--destructive-foreground))', | |
| + }, | |
| + muted: { | |
| + DEFAULT: 'hsl(var(--muted))', | |
| + foreground: 'hsl(var(--muted-foreground))', | |
| + }, | |
| + accent: { | |
| + DEFAULT: 'hsl(var(--accent))', | |
| + foreground: 'hsl(var(--accent-foreground))', | |
| + }, | |
| + popover: { | |
| + DEFAULT: 'hsl(var(--popover))', | |
| + foreground: 'hsl(var(--popover-foreground))', | |
| + }, | |
| + card: { | |
| + DEFAULT: 'hsl(var(--card))', | |
| + foreground: 'hsl(var(--card-foreground))', | |
| + }, | |
| + }, | |
| + borderRadius: { | |
| + lg: 'var(--radius)', | |
| + md: 'calc(var(--radius) - 2px)', | |
| + sm: 'calc(var(--radius) - 4px)', | |
| + }, | |
| + keyframes: { | |
| + 'fade-in': { | |
| + '0%': { opacity: '0', transform: 'translateY(-10px)' }, | |
| + '100%': { opacity: '1', transform: 'translateY(0)' }, | |
| + }, | |
| + 'slide-in-left': { | |
| + '0%': { opacity: '0', transform: 'translateX(-20px)' }, | |
| + '100%': { opacity: '1', transform: 'translateX(0)' }, | |
| + }, | |
| + 'pulse-subtle': { | |
| + '0%, 100%': { opacity: '1' }, | |
| + '50%': { opacity: '0.7' }, | |
| + }, | |
| + }, | |
| + animation: { | |
| + 'fade-in': 'fade-in 0.3s ease-out', | |
| + 'slide-in-left': 'slide-in-left 0.3s ease-out', | |
| + 'pulse-subtle': 'pulse-subtle 2s ease-in-out infinite', | |
| + }, | |
| + }, | |
| + }, | |
| + plugins: [require('tailwindcss-animate')], | |
| +}; | |
| + | |
| +export default config; | |
| diff --git a/tsconfig.json b/tsconfig.json | |
| new file mode 100644 | |
| index 0000000..e7ff90f | |
| --- /dev/null | |
| +++ b/tsconfig.json | |
| @@ -0,0 +1,26 @@ | |
| +{ | |
| + "compilerOptions": { | |
| + "lib": ["dom", "dom.iterable", "esnext"], | |
| + "allowJs": true, | |
| + "skipLibCheck": true, | |
| + "strict": true, | |
| + "noEmit": true, | |
| + "esModuleInterop": true, | |
| + "module": "esnext", | |
| + "moduleResolution": "bundler", | |
| + "resolveJsonModule": true, | |
| + "isolatedModules": true, | |
| + "jsx": "preserve", | |
| + "incremental": true, | |
| + "plugins": [ | |
| + { | |
| + "name": "next" | |
| + } | |
| + ], | |
| + "paths": { | |
| + "@/*": ["./*"] | |
| + } | |
| + }, | |
| + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], | |
| + "exclude": ["node_modules"] | |
| +} | |
| diff --git a/types/index.ts b/types/index.ts | |
| new file mode 100644 | |
| index 0000000..ac58bac | |
| --- /dev/null | |
| +++ b/types/index.ts | |
| @@ -0,0 +1,97 @@ | |
| +import { z } from 'zod'; | |
| + | |
| +export interface Coordinates { | |
| + latitude: number; | |
| + longitude: number; | |
| +} | |
| + | |
| +export interface CameraPosition extends Coordinates { | |
| + height: number; | |
| + heading?: number; | |
| + pitch?: number; | |
| + roll?: number; | |
| +} | |
| + | |
| +export interface SavedPlace { | |
| + id: string; | |
| + name: string; | |
| + note: string; | |
| + coordinates: Coordinates; | |
| + createdAt: string; | |
| + updatedAt: string; | |
| +} | |
| + | |
| +export interface MeasurementPoint { | |
| + id: string; | |
| + coordinates: Coordinates; | |
| +} | |
| + | |
| +export interface GeocodingResult { | |
| + id: string; | |
| + name: string; | |
| + displayName: string; | |
| + coordinates: Coordinates; | |
| + type: string; | |
| + importance: number; | |
| +} | |
| + | |
| +export type BaseLayerType = 'osm' | 'arcgis' | 'stamen'; | |
| + | |
| +export interface LayerConfig { | |
| + id: string; | |
| + name: string; | |
| + type: 'base' | 'overlay'; | |
| + enabled: boolean; | |
| +} | |
| + | |
| +export interface LayerState { | |
| + baseLayer: BaseLayerType; | |
| + overlays: { | |
| + borders: boolean; | |
| + labels: boolean; | |
| + roads: boolean; | |
| + }; | |
| +} | |
| + | |
| +export type PanelTab = 'layers' | 'places' | 'measure'; | |
| + | |
| +export interface CursorPosition extends Coordinates { | |
| + height?: number; | |
| +} | |
| + | |
| +export interface GlobeRef { | |
| + flyTo: (lat: number, lon: number, height?: number, duration?: number) => void; | |
| + zoomIn: () => void; | |
| + zoomOut: () => void; | |
| + tiltUp: () => void; | |
| + tiltDown: () => void; | |
| + rotateLeft: () => void; | |
| + rotateRight: () => void; | |
| + resetView: () => void; | |
| + getCameraPosition: () => CameraPosition | null; | |
| +} | |
| + | |
| +export const SavedPlaceSchema = z.object({ | |
| + id: z.string(), | |
| + name: z.string().min(1), | |
| + note: z.string(), | |
| + coordinates: z.object({ | |
| + latitude: z.number().min(-90).max(90), | |
| + longitude: z.number().min(-180).max(180), | |
| + }), | |
| + createdAt: z.string(), | |
| + updatedAt: z.string(), | |
| +}); | |
| + | |
| +export const SavedPlacesArraySchema = z.array(SavedPlaceSchema); | |
| + | |
| +export const LayerStateSchema = z.object({ | |
| + baseLayer: z.enum(['osm', 'arcgis', 'stamen']), | |
| + overlays: z.object({ | |
| + borders: z.boolean(), | |
| + labels: z.boolean(), | |
| + roads: z.boolean(), | |
| + }), | |
| +}); | |
| + | |
| +export type ThemeMode = 'light' | 'dark' | 'system'; | |
| -- | |
| 2.52.0 | |
| From b9101fb3b60202ea91d62cd7104fa9db9c2ab804 Mon Sep 17 00:00:00 2001 | |
| From: Shrijal Acharya <shrijal.acharya@gmail.com> | |
| Date: Thu, 5 Feb 2026 23:43:20 +0545 | |
| Subject: [PATCH 2/2] fix | |
| --- | |
| .env.example | 38 + | |
| app/api/active-users/route.ts | 118 +++ | |
| app/page.tsx | 18 +- | |
| app/providers.tsx | 5 +- | |
| components/Header.tsx | 57 +- | |
| components/globe/GlobeViewer.tsx | 69 ++ | |
| components/modals/AuthModal.tsx | 173 +++++ | |
| components/panels/SidePanel.tsx | 24 +- | |
| components/panels/UsersPanel.tsx | 178 +++++ | |
| components/providers/AnalyticsProvider.tsx | 154 ++++ | |
| hooks/index.ts | 1 + | |
| hooks/useAnalytics.ts | 107 +++ | |
| lib/auth.ts | 193 +++++ | |
| lib/composio.ts | 463 ++++++++++++ | |
| lib/geolocation.ts | 293 ++++++++ | |
| lib/posthog.ts | 174 +++++ | |
| package-lock.json | 797 ++++++++++++++++++++- | |
| package.json | 4 + | |
| store/index.ts | 2 + | |
| store/useActiveUsersStore.ts | 96 +++ | |
| store/useAuthStore.ts | 86 +++ | |
| types/index.ts | 13 +- | |
| 22 files changed, 3018 insertions(+), 45 deletions(-) | |
| create mode 100644 app/api/active-users/route.ts | |
| create mode 100644 components/modals/AuthModal.tsx | |
| create mode 100644 components/panels/UsersPanel.tsx | |
| create mode 100644 components/providers/AnalyticsProvider.tsx | |
| create mode 100644 hooks/useAnalytics.ts | |
| create mode 100644 lib/auth.ts | |
| create mode 100644 lib/composio.ts | |
| create mode 100644 lib/geolocation.ts | |
| create mode 100644 lib/posthog.ts | |
| create mode 100644 store/useActiveUsersStore.ts | |
| create mode 100644 store/useAuthStore.ts | |
| diff --git a/.env.example b/.env.example | |
| index 3e61e42..36cc795 100644 | |
| --- a/.env.example | |
| +++ b/.env.example | |
| @@ -9,3 +9,41 @@ NEXT_PUBLIC_CESIUM_ION_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI0OT | |
| # Optional: Custom base URL for Cesium assets | |
| # Defaults to /cesium if not set | |
| NEXT_PUBLIC_CESIUM_BASE_URL= | |
| + | |
| +# ============================================ | |
| +# PostHog Analytics (via Composio) | |
| +# ============================================ | |
| + | |
| +# PostHog Project API Key (client-side, public) | |
| +# Get from: PostHog Settings > Project > Project API Key | |
| +NEXT_PUBLIC_POSTHOG_KEY=phc_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | |
| + | |
| +# PostHog Host (defaults to US cloud) | |
| +NEXT_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com | |
| + | |
| +# PostHog Personal API Key (server-side, private) | |
| +# Get from: PostHog Settings > Personal API Keys | |
| +POSTHOG_API_KEY=phx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | |
| + | |
| +# PostHog Project ID (for API queries) | |
| +# Get from: PostHog Settings > Project > Project ID | |
| +POSTHOG_PROJECT_ID=12345 | |
| + | |
| +# Same as NEXT_PUBLIC_POSTHOG_HOST for server-side use | |
| +POSTHOG_HOST=https://us.i.posthog.com | |
| + | |
| +# ============================================ | |
| +# Composio Configuration | |
| +# ============================================ | |
| + | |
| +# Composio API Key | |
| +# Get from: https://platform.composio.dev/settings | |
| +COMPOSIO_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxx | |
| + | |
| +# ============================================ | |
| +# OpenAI Configuration (for Composio tool execution) | |
| +# ============================================ | |
| + | |
| +# OpenAI API Key | |
| +# Get from: https://platform.openai.com/api-keys | |
| +OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxx | |
| diff --git a/app/api/active-users/route.ts b/app/api/active-users/route.ts | |
| new file mode 100644 | |
| index 0000000..7df729c | |
| --- /dev/null | |
| +++ b/app/api/active-users/route.ts | |
| @@ -0,0 +1,118 @@ | |
| +import { NextResponse } from 'next/server'; | |
| +import { getPostHogComposioService, type ActiveUser } from '@/lib/composio'; | |
| + | |
| +// Refresh interval for fetching users (5 minutes) | |
| +const CACHE_DURATION_MS = 5 * 60 * 1000; | |
| + | |
| +// In-memory cache for active users | |
| +let cachedUsers: ActiveUser[] = []; | |
| +let lastFetchTime = 0; | |
| + | |
| +export async function GET() { | |
| + try { | |
| + const now = Date.now(); | |
| + | |
| + // Return cached data if still fresh | |
| + if (cachedUsers.length > 0 && now - lastFetchTime < CACHE_DURATION_MS) { | |
| + return NextResponse.json({ | |
| + users: cachedUsers, | |
| + cached: true, | |
| + lastFetched: new Date(lastFetchTime).toISOString(), | |
| + }); | |
| + } | |
| + | |
| + // Fetch fresh data from PostHog via Composio | |
| + const service = getPostHogComposioService(); | |
| + const users = await service.getActiveUsers(100); | |
| + | |
| + // Update cache | |
| + cachedUsers = users; | |
| + lastFetchTime = now; | |
| + | |
| + return NextResponse.json({ | |
| + users, | |
| + cached: false, | |
| + lastFetched: new Date(now).toISOString(), | |
| + }); | |
| + } catch (error) { | |
| + console.error('Error fetching active users:', error); | |
| + | |
| + // Return cached data on error if available | |
| + if (cachedUsers.length > 0) { | |
| + return NextResponse.json({ | |
| + users: cachedUsers, | |
| + cached: true, | |
| + error: 'Failed to fetch fresh data, returning cached', | |
| + lastFetched: new Date(lastFetchTime).toISOString(), | |
| + }); | |
| + } | |
| + | |
| + return NextResponse.json( | |
| + { error: 'Failed to fetch active users', users: [] }, | |
| + { status: 500 } | |
| + ); | |
| + } | |
| +} | |
| + | |
| +// POST endpoint for updating user location | |
| +export async function POST(request: Request) { | |
| + try { | |
| + const body = await request.json(); | |
| + const { distinctId, latitude, longitude, accuracy } = body; | |
| + | |
| + if (!distinctId || latitude === undefined || longitude === undefined) { | |
| + return NextResponse.json( | |
| + { error: 'Missing required fields: distinctId, latitude, longitude' }, | |
| + { status: 400 } | |
| + ); | |
| + } | |
| + | |
| + const service = getPostHogComposioService(); | |
| + | |
| + // Update user location in PostHog | |
| + const success = await service.updateUserLocation( | |
| + distinctId, | |
| + latitude, | |
| + longitude, | |
| + accuracy | |
| + ); | |
| + | |
| + if (!success) { | |
| + return NextResponse.json( | |
| + { error: 'Failed to update location' }, | |
| + { status: 500 } | |
| + ); | |
| + } | |
| + | |
| + // Update in-memory cache for immediate reflection | |
| + const existingUserIndex = cachedUsers.findIndex( | |
| + (u) => u.distinctId === distinctId | |
| + ); | |
| + | |
| + if (existingUserIndex >= 0) { | |
| + cachedUsers[existingUserIndex] = { | |
| + ...cachedUsers[existingUserIndex], | |
| + location: { latitude, longitude }, | |
| + lastSeen: new Date().toISOString(), | |
| + isOnline: true, | |
| + }; | |
| + } else { | |
| + // Add new user to cache | |
| + cachedUsers.push({ | |
| + id: distinctId, | |
| + distinctId, | |
| + location: { latitude, longitude }, | |
| + lastSeen: new Date().toISOString(), | |
| + isOnline: true, | |
| + }); | |
| + } | |
| + | |
| + return NextResponse.json({ success: true }); | |
| + } catch (error) { | |
| + console.error('Error updating user location:', error); | |
| + return NextResponse.json( | |
| + { error: 'Failed to update location' }, | |
| + { status: 500 } | |
| + ); | |
| + } | |
| +} | |
| diff --git a/app/page.tsx b/app/page.tsx | |
| index 82119cb..52158a5 100644 | |
| --- a/app/page.tsx | |
| +++ b/app/page.tsx | |
| @@ -6,18 +6,22 @@ import { SidePanel } from '@/components/panels/SidePanel'; | |
| import { GlobeWrapper } from '@/components/globe/GlobeWrapper'; | |
| import { PinModal } from '@/components/modals/PinModal'; | |
| import { KeyboardShortcuts } from '@/components/modals/KeyboardShortcuts'; | |
| +import { AuthModal } from '@/components/modals/AuthModal'; | |
| import { useKeyboardShortcuts } from '@/hooks'; | |
| import { | |
| useGlobeStore, | |
| usePlacesStore, | |
| useLayersStore, | |
| useMeasureStore, | |
| + useAuthStore, | |
| } from '@/store'; | |
| +import { trackEvent } from '@/lib/posthog'; | |
| import type { SavedPlace } from '@/types'; | |
| export default function Home() { | |
| const [showShortcuts, setShowShortcuts] = useState(false); | |
| const [showPinModal, setShowPinModal] = useState(false); | |
| + const [showAuthModal, setShowAuthModal] = useState(false); | |
| const [editingPlace, setEditingPlace] = useState<SavedPlace | null>(null); | |
| const { | |
| @@ -30,11 +34,13 @@ export default function Home() { | |
| const { initializePlaces, places } = usePlacesStore(); | |
| const { initializeLayers } = useLayersStore(); | |
| const { isActive: isMeasuring, startMeasuring, stopMeasuring } = useMeasureStore(); | |
| + const { user, initialize: initializeAuth, signOut } = useAuthStore(); | |
| useEffect(() => { | |
| initializePlaces(); | |
| initializeLayers(); | |
| - }, [initializePlaces, initializeLayers]); | |
| + initializeAuth(); | |
| + }, [initializePlaces, initializeLayers, initializeAuth]); | |
| useEffect(() => { | |
| if (pendingPinLocation && !isMeasuring) { | |
| @@ -93,7 +99,10 @@ export default function Home() { | |
| return ( | |
| <main className="min-h-screen bg-background"> | |
| - <Header onShowShortcuts={() => setShowShortcuts(true)} /> | |
| + <Header | |
| + onShowShortcuts={() => setShowShortcuts(true)} | |
| + onShowAuth={() => setShowAuthModal(true)} | |
| + /> | |
| <SidePanel onEditPlace={handleEditPlace} /> | |
| <GlobeWrapper /> | |
| @@ -107,6 +116,11 @@ export default function Home() { | |
| isOpen={showShortcuts} | |
| onClose={() => setShowShortcuts(false)} | |
| /> | |
| + | |
| + <AuthModal | |
| + isOpen={showAuthModal} | |
| + onClose={() => setShowAuthModal(false)} | |
| + /> | |
| </main> | |
| ); | |
| } | |
| diff --git a/app/providers.tsx b/app/providers.tsx | |
| index d696087..7ab5fe3 100644 | |
| --- a/app/providers.tsx | |
| +++ b/app/providers.tsx | |
| @@ -2,6 +2,7 @@ | |
| import { ThemeProvider } from 'next-themes'; | |
| import { TooltipProvider } from '@/components/ui/tooltip'; | |
| +import { AnalyticsProvider } from '@/components/providers/AnalyticsProvider'; | |
| interface ProvidersProps { | |
| children: React.ReactNode; | |
| @@ -15,7 +16,9 @@ export function Providers({ children }: ProvidersProps) { | |
| enableSystem | |
| disableTransitionOnChange | |
| > | |
| - <TooltipProvider delayDuration={300}>{children}</TooltipProvider> | |
| + <TooltipProvider delayDuration={300}> | |
| + <AnalyticsProvider>{children}</AnalyticsProvider> | |
| + </TooltipProvider> | |
| </ThemeProvider> | |
| ); | |
| } | |
| diff --git a/components/Header.tsx b/components/Header.tsx | |
| index 3ab3b8b..78ecc4f 100644 | |
| --- a/components/Header.tsx | |
| +++ b/components/Header.tsx | |
| @@ -1,6 +1,6 @@ | |
| 'use client'; | |
| -import { Globe2, Keyboard, Moon, Sun, PanelLeftClose, PanelLeft } from 'lucide-react'; | |
| +import { Globe2, Keyboard, Moon, Sun, PanelLeftClose, PanelLeft, LogIn, LogOut, User } from 'lucide-react'; | |
| import { useTheme } from 'next-themes'; | |
| import { Button } from '@/components/ui/button'; | |
| import { | |
| @@ -8,21 +8,36 @@ import { | |
| TooltipContent, | |
| TooltipTrigger, | |
| } from '@/components/ui/tooltip'; | |
| +import { | |
| + DropdownMenu, | |
| + DropdownMenuContent, | |
| + DropdownMenuItem, | |
| + DropdownMenuSeparator, | |
| + DropdownMenuTrigger, | |
| +} from '@/components/ui/dropdown-menu'; | |
| import { SearchBar } from '@/components/search/SearchBar'; | |
| -import { useGlobeStore } from '@/store'; | |
| +import { useGlobeStore, useAuthStore } from '@/store'; | |
| +import { trackEvent } from '@/lib/posthog'; | |
| interface HeaderProps { | |
| onShowShortcuts: () => void; | |
| + onShowAuth: () => void; | |
| } | |
| -export function Header({ onShowShortcuts }: HeaderProps) { | |
| +export function Header({ onShowShortcuts, onShowAuth }: HeaderProps) { | |
| const { theme, setTheme } = useTheme(); | |
| const { isPanelOpen, togglePanel } = useGlobeStore(); | |
| + const { user, signOut } = useAuthStore(); | |
| const toggleTheme = () => { | |
| setTheme(theme === 'dark' ? 'light' : 'dark'); | |
| }; | |
| + const handleSignOut = () => { | |
| + signOut(); | |
| + trackEvent('user_logged_out', {}); | |
| + }; | |
| + | |
| return ( | |
| <header className="fixed top-0 left-0 right-0 z-40 h-14 bg-background/80 backdrop-blur-md border-b border-border"> | |
| <div className="flex items-center justify-between h-full px-4"> | |
| @@ -78,6 +93,42 @@ export function Header({ onShowShortcuts }: HeaderProps) { | |
| </TooltipTrigger> | |
| <TooltipContent>Toggle theme</TooltipContent> | |
| </Tooltip> | |
| + | |
| + {user ? ( | |
| + <DropdownMenu> | |
| + <DropdownMenuTrigger asChild> | |
| + <Button variant="ghost" size="sm" className="gap-2"> | |
| + <div className="h-6 w-6 rounded-full bg-primary/20 flex items-center justify-center"> | |
| + <User className="h-4 w-4" /> | |
| + </div> | |
| + <span className="hidden sm:inline-block max-w-[100px] truncate"> | |
| + {user.name || user.email} | |
| + </span> | |
| + </Button> | |
| + </DropdownMenuTrigger> | |
| + <DropdownMenuContent align="end" className="w-48"> | |
| + <div className="px-2 py-1.5"> | |
| + <p className="text-sm font-medium truncate">{user.name}</p> | |
| + <p className="text-xs text-muted-foreground truncate">{user.email}</p> | |
| + </div> | |
| + <DropdownMenuSeparator /> | |
| + <DropdownMenuItem onClick={handleSignOut}> | |
| + <LogOut className="mr-2 h-4 w-4" /> | |
| + Sign out | |
| + </DropdownMenuItem> | |
| + </DropdownMenuContent> | |
| + </DropdownMenu> | |
| + ) : ( | |
| + <Tooltip> | |
| + <TooltipTrigger asChild> | |
| + <Button variant="default" size="sm" onClick={onShowAuth} className="gap-2"> | |
| + <LogIn className="h-4 w-4" /> | |
| + <span className="hidden sm:inline-block">Sign In</span> | |
| + </Button> | |
| + </TooltipTrigger> | |
| + <TooltipContent>Sign in to track your location</TooltipContent> | |
| + </Tooltip> | |
| + )} | |
| </div> | |
| </div> | |
| </header> | |
| diff --git a/components/globe/GlobeViewer.tsx b/components/globe/GlobeViewer.tsx | |
| index 6d781c2..4767e67 100644 | |
| --- a/components/globe/GlobeViewer.tsx | |
| +++ b/components/globe/GlobeViewer.tsx | |
| @@ -23,6 +23,7 @@ import { | |
| useLayersStore, | |
| useMeasureStore, | |
| usePlacesStore, | |
| + useActiveUsersStore, | |
| } from '@/store'; | |
| import { | |
| getCesiumIonToken, | |
| @@ -60,6 +61,7 @@ export function GlobeViewer() { | |
| const { baseLayer } = useLayersStore(); | |
| const { points: measurePoints, isActive: isMeasuring, addPoint } = useMeasureStore(); | |
| const { places } = usePlacesStore(); | |
| + const { users: activeUsers, currentUserId } = useActiveUsersStore(); | |
| const flyTo = useCallback( | |
| @@ -379,6 +381,73 @@ export function GlobeViewer() { | |
| } | |
| }, [measurePoints, isReady]); | |
| + // Update active user markers on the globe | |
| + useEffect(() => { | |
| + const viewer = viewerRef.current; | |
| + if (!viewer || !isReady) return; | |
| + | |
| + // Remove old active user entities | |
| + const toRemove: Entity[] = []; | |
| + viewer.entities.values.forEach((entity) => { | |
| + if (entity.id?.toString().startsWith('active-user-')) { | |
| + toRemove.push(entity); | |
| + } | |
| + }); | |
| + toRemove.forEach((entity) => viewer.entities.remove(entity)); | |
| + | |
| + // Add active user markers | |
| + activeUsers.forEach((user) => { | |
| + // Determine if this is the current user | |
| + const isCurrentUser = user.id === currentUserId || user.distinctId === currentUserId; | |
| + | |
| + // Use different colors for current user vs other users | |
| + // Current user: green, Online users: purple, Offline users: gray | |
| + let markerColor: string; | |
| + if (isCurrentUser) { | |
| + markerColor = '#22c55e'; // Green for current user | |
| + } else if (user.isOnline) { | |
| + markerColor = '#a855f7'; // Purple for online users | |
| + } else { | |
| + markerColor = '#6b7280'; // Gray for offline users | |
| + } | |
| + | |
| + // Create user label | |
| + const displayName = user.name || user.email?.split('@')[0] || 'Anonymous'; | |
| + const statusText = isCurrentUser ? 'You' : user.isOnline ? 'Online' : 'Offline'; | |
| + | |
| + viewer.entities.add({ | |
| + id: `active-user-${user.id}`, | |
| + position: Cartesian3.fromDegrees( | |
| + user.location.longitude, | |
| + user.location.latitude | |
| + ), | |
| + point: { | |
| + pixelSize: isCurrentUser ? 14 : 10, | |
| + color: Color.fromCssColorString(markerColor), | |
| + outlineColor: Color.WHITE, | |
| + outlineWidth: 2, | |
| + }, | |
| + label: { | |
| + text: displayName, | |
| + font: '12px sans-serif', | |
| + fillColor: Color.WHITE, | |
| + outlineColor: Color.BLACK, | |
| + outlineWidth: 2, | |
| + style: 2, // FILL_AND_OUTLINE | |
| + verticalOrigin: 1, // BOTTOM | |
| + pixelOffset: new Cartesian2(0, -16), | |
| + show: false, // Will show on hover via billboard picking | |
| + }, | |
| + name: displayName, | |
| + description: `<div style="padding: 8px;"> | |
| + <strong>${displayName}</strong><br/> | |
| + <span style="color: ${markerColor};">${statusText}</span><br/> | |
| + <small>Last seen: ${new Date(user.lastSeen).toLocaleString()}</small> | |
| + </div>`, | |
| + }); | |
| + }); | |
| + }, [activeUsers, currentUserId, isReady]); | |
| + | |
| return ( | |
| <div className="fixed inset-0 pt-14"> | |
| <div | |
| diff --git a/components/modals/AuthModal.tsx b/components/modals/AuthModal.tsx | |
| new file mode 100644 | |
| index 0000000..3e2964e | |
| --- /dev/null | |
| +++ b/components/modals/AuthModal.tsx | |
| @@ -0,0 +1,173 @@ | |
| +'use client'; | |
| + | |
| +import { useState } from 'react'; | |
| +import { | |
| + Dialog, | |
| + DialogContent, | |
| + DialogHeader, | |
| + DialogTitle, | |
| +} from '@/components/ui/dialog'; | |
| +import { Button } from '@/components/ui/button'; | |
| +import { Input } from '@/components/ui/input'; | |
| +import { Label } from '@/components/ui/label'; | |
| +import { useAuthStore } from '@/store/useAuthStore'; | |
| +import { trackEvent } from '@/lib/posthog'; | |
| +import { Loader2, Mail, Lock, User } from 'lucide-react'; | |
| + | |
| +interface AuthModalProps { | |
| + isOpen: boolean; | |
| + onClose: () => void; | |
| +} | |
| + | |
| +type AuthMode = 'signin' | 'signup'; | |
| + | |
| +export function AuthModal({ isOpen, onClose }: AuthModalProps) { | |
| + const [mode, setMode] = useState<AuthMode>('signin'); | |
| + const [email, setEmail] = useState(''); | |
| + const [password, setPassword] = useState(''); | |
| + const [name, setName] = useState(''); | |
| + const [error, setError] = useState<string | null>(null); | |
| + | |
| + const { signIn, signUp, isLoading } = useAuthStore(); | |
| + | |
| + const handleSubmit = async (e: React.FormEvent) => { | |
| + e.preventDefault(); | |
| + setError(null); | |
| + | |
| + let result; | |
| + if (mode === 'signin') { | |
| + result = await signIn(email, password); | |
| + if (result.success) { | |
| + trackEvent('user_logged_in', { method: 'email' }); | |
| + } | |
| + } else { | |
| + result = await signUp(email, password, name); | |
| + if (result.success) { | |
| + trackEvent('user_signed_up', { method: 'email' }); | |
| + } | |
| + } | |
| + | |
| + if (result.success) { | |
| + setEmail(''); | |
| + setPassword(''); | |
| + setName(''); | |
| + onClose(); | |
| + } else { | |
| + setError(result.error || 'An error occurred'); | |
| + } | |
| + }; | |
| + | |
| + const toggleMode = () => { | |
| + setMode(mode === 'signin' ? 'signup' : 'signin'); | |
| + setError(null); | |
| + }; | |
| + | |
| + return ( | |
| + <Dialog open={isOpen} onOpenChange={(open) => !open && onClose()}> | |
| + <DialogContent className="sm:max-w-md"> | |
| + <DialogHeader> | |
| + <DialogTitle> | |
| + {mode === 'signin' ? 'Welcome Back' : 'Create Account'} | |
| + </DialogTitle> | |
| + </DialogHeader> | |
| + | |
| + <form onSubmit={handleSubmit} className="space-y-4 pt-4"> | |
| + {mode === 'signup' && ( | |
| + <div className="space-y-2"> | |
| + <Label htmlFor="name">Name</Label> | |
| + <div className="relative"> | |
| + <User className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" /> | |
| + <Input | |
| + id="name" | |
| + type="text" | |
| + placeholder="Your name" | |
| + value={name} | |
| + onChange={(e) => setName(e.target.value)} | |
| + className="pl-10" | |
| + /> | |
| + </div> | |
| + </div> | |
| + )} | |
| + | |
| + <div className="space-y-2"> | |
| + <Label htmlFor="email">Email</Label> | |
| + <div className="relative"> | |
| + <Mail className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" /> | |
| + <Input | |
| + id="email" | |
| + type="email" | |
| + placeholder="your@email.com" | |
| + value={email} | |
| + onChange={(e) => setEmail(e.target.value)} | |
| + required | |
| + className="pl-10" | |
| + /> | |
| + </div> | |
| + </div> | |
| + | |
| + <div className="space-y-2"> | |
| + <Label htmlFor="password">Password</Label> | |
| + <div className="relative"> | |
| + <Lock className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" /> | |
| + <Input | |
| + id="password" | |
| + type="password" | |
| + placeholder={mode === 'signup' ? 'Min 6 characters' : 'Your password'} | |
| + value={password} | |
| + onChange={(e) => setPassword(e.target.value)} | |
| + required | |
| + minLength={6} | |
| + className="pl-10" | |
| + /> | |
| + </div> | |
| + </div> | |
| + | |
| + {error && ( | |
| + <div className="text-sm text-destructive bg-destructive/10 px-3 py-2 rounded-md"> | |
| + {error} | |
| + </div> | |
| + )} | |
| + | |
| + <Button type="submit" className="w-full" disabled={isLoading}> | |
| + {isLoading ? ( | |
| + <> | |
| + <Loader2 className="mr-2 h-4 w-4 animate-spin" /> | |
| + {mode === 'signin' ? 'Signing in...' : 'Creating account...'} | |
| + </> | |
| + ) : mode === 'signin' ? ( | |
| + 'Sign In' | |
| + ) : ( | |
| + 'Create Account' | |
| + )} | |
| + </Button> | |
| + | |
| + <div className="text-center text-sm text-muted-foreground"> | |
| + {mode === 'signin' ? ( | |
| + <> | |
| + Don't have an account?{' '} | |
| + <button | |
| + type="button" | |
| + onClick={toggleMode} | |
| + className="text-primary hover:underline" | |
| + > | |
| + Sign up | |
| + </button> | |
| + </> | |
| + ) : ( | |
| + <> | |
| + Already have an account?{' '} | |
| + <button | |
| + type="button" | |
| + onClick={toggleMode} | |
| + className="text-primary hover:underline" | |
| + > | |
| + Sign in | |
| + </button> | |
| + </> | |
| + )} | |
| + </div> | |
| + </form> | |
| + </DialogContent> | |
| + </Dialog> | |
| + ); | |
| +} | |
| diff --git a/components/panels/SidePanel.tsx b/components/panels/SidePanel.tsx | |
| index 201bfde..31a27fd 100644 | |
| --- a/components/panels/SidePanel.tsx | |
| +++ b/components/panels/SidePanel.tsx | |
| @@ -1,10 +1,11 @@ | |
| 'use client'; | |
| -import { Layers, MapPin, Ruler } from 'lucide-react'; | |
| +import { Layers, MapPin, Ruler, Users } from 'lucide-react'; | |
| import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; | |
| import { LayersPanel } from '@/components/panels/LayersPanel'; | |
| import { PlacesPanel } from '@/components/panels/PlacesPanel'; | |
| import { MeasurePanel } from '@/components/panels/MeasurePanel'; | |
| +import { UsersPanel } from '@/components/panels/UsersPanel'; | |
| import { useGlobeStore } from '@/store'; | |
| import { cn } from '@/lib/utils'; | |
| import type { PanelTab } from '@/types'; | |
| @@ -28,18 +29,22 @@ export function SidePanel({ onEditPlace }: SidePanelProps) { | |
| onValueChange={(value) => setActiveTab(value as PanelTab)} | |
| className="flex flex-col h-full" | |
| > | |
| - <TabsList className="grid w-full grid-cols-3 rounded-none border-b bg-muted/50"> | |
| - <TabsTrigger value="layers" className="gap-2 rounded-none"> | |
| + <TabsList className="grid w-full grid-cols-4 rounded-none border-b bg-muted/50"> | |
| + <TabsTrigger value="layers" className="gap-1 rounded-none px-2"> | |
| <Layers className="h-4 w-4" /> | |
| - <span className="hidden sm:inline">Layers</span> | |
| + <span className="hidden lg:inline text-xs">Layers</span> | |
| </TabsTrigger> | |
| - <TabsTrigger value="places" className="gap-2 rounded-none"> | |
| + <TabsTrigger value="places" className="gap-1 rounded-none px-2"> | |
| <MapPin className="h-4 w-4" /> | |
| - <span className="hidden sm:inline">Places</span> | |
| + <span className="hidden lg:inline text-xs">Places</span> | |
| </TabsTrigger> | |
| - <TabsTrigger value="measure" className="gap-2 rounded-none"> | |
| + <TabsTrigger value="measure" className="gap-1 rounded-none px-2"> | |
| <Ruler className="h-4 w-4" /> | |
| - <span className="hidden sm:inline">Measure</span> | |
| + <span className="hidden lg:inline text-xs">Measure</span> | |
| + </TabsTrigger> | |
| + <TabsTrigger value="users" className="gap-1 rounded-none px-2"> | |
| + <Users className="h-4 w-4" /> | |
| + <span className="hidden lg:inline text-xs">Users</span> | |
| </TabsTrigger> | |
| </TabsList> | |
| @@ -53,6 +58,9 @@ export function SidePanel({ onEditPlace }: SidePanelProps) { | |
| <TabsContent value="measure" className="h-full m-0"> | |
| <MeasurePanel /> | |
| </TabsContent> | |
| + <TabsContent value="users" className="h-full m-0"> | |
| + <UsersPanel /> | |
| + </TabsContent> | |
| </div> | |
| </Tabs> | |
| </div> | |
| diff --git a/components/panels/UsersPanel.tsx b/components/panels/UsersPanel.tsx | |
| new file mode 100644 | |
| index 0000000..7cb9428 | |
| --- /dev/null | |
| +++ b/components/panels/UsersPanel.tsx | |
| @@ -0,0 +1,178 @@ | |
| +'use client'; | |
| + | |
| +import { useEffect } from 'react'; | |
| +import { Users, MapPin, RefreshCw, Loader2 } from 'lucide-react'; | |
| +import { Button } from '@/components/ui/button'; | |
| +import { ScrollArea } from '@/components/ui/scroll-area'; | |
| +import { useActiveUsersStore, useGlobeStore, useAuthStore } from '@/store'; | |
| +import { formatCoordinate } from '@/lib/formatting'; | |
| +import { cn } from '@/lib/utils'; | |
| + | |
| +export function UsersPanel() { | |
| + const { users, isLoading, error, fetchUsers, currentUserId } = useActiveUsersStore(); | |
| + const { globeRef } = useGlobeStore(); | |
| + const { user } = useAuthStore(); | |
| + | |
| + // Filter to only show online users | |
| + const onlineUsers = users.filter((u) => u.isOnline); | |
| + const offlineUsers = users.filter((u) => !u.isOnline); | |
| + | |
| + const handleFlyToUser = (latitude: number, longitude: number) => { | |
| + if (globeRef) { | |
| + globeRef.flyTo(latitude, longitude, 500000); | |
| + } | |
| + }; | |
| + | |
| + if (!user) { | |
| + return ( | |
| + <div className="p-4 text-center text-muted-foreground"> | |
| + <Users className="h-12 w-12 mx-auto mb-4 opacity-50" /> | |
| + <p className="text-sm">Sign in to see active users on the globe</p> | |
| + </div> | |
| + ); | |
| + } | |
| + | |
| + return ( | |
| + <div className="flex flex-col h-full"> | |
| + <div className="p-4 border-b border-border"> | |
| + <div className="flex items-center justify-between"> | |
| + <div className="flex items-center gap-2"> | |
| + <Users className="h-5 w-5" /> | |
| + <h3 className="font-medium">Active Users</h3> | |
| + </div> | |
| + <Button | |
| + variant="ghost" | |
| + size="icon" | |
| + onClick={fetchUsers} | |
| + disabled={isLoading} | |
| + > | |
| + {isLoading ? ( | |
| + <Loader2 className="h-4 w-4 animate-spin" /> | |
| + ) : ( | |
| + <RefreshCw className="h-4 w-4" /> | |
| + )} | |
| + </Button> | |
| + </div> | |
| + <p className="text-xs text-muted-foreground mt-1"> | |
| + {onlineUsers.length} online, {offlineUsers.length} offline | |
| + </p> | |
| + </div> | |
| + | |
| + {error && ( | |
| + <div className="p-4 text-sm text-destructive bg-destructive/10"> | |
| + {error} | |
| + </div> | |
| + )} | |
| + | |
| + <ScrollArea className="flex-1"> | |
| + <div className="p-2 space-y-1"> | |
| + {/* Online Users */} | |
| + {onlineUsers.length > 0 && ( | |
| + <> | |
| + <div className="px-2 py-1 text-xs font-medium text-muted-foreground uppercase"> | |
| + Online | |
| + </div> | |
| + {onlineUsers.map((activeUser) => ( | |
| + <UserItem | |
| + key={activeUser.id} | |
| + user={activeUser} | |
| + isCurrentUser={activeUser.id === currentUserId || activeUser.distinctId === currentUserId} | |
| + onFlyTo={handleFlyToUser} | |
| + /> | |
| + ))} | |
| + </> | |
| + )} | |
| + | |
| + {/* Offline Users */} | |
| + {offlineUsers.length > 0 && ( | |
| + <> | |
| + <div className="px-2 py-1 mt-4 text-xs font-medium text-muted-foreground uppercase"> | |
| + Recently Active | |
| + </div> | |
| + {offlineUsers.map((activeUser) => ( | |
| + <UserItem | |
| + key={activeUser.id} | |
| + user={activeUser} | |
| + isCurrentUser={activeUser.id === currentUserId || activeUser.distinctId === currentUserId} | |
| + onFlyTo={handleFlyToUser} | |
| + /> | |
| + ))} | |
| + </> | |
| + )} | |
| + | |
| + {users.length === 0 && !isLoading && ( | |
| + <div className="p-4 text-center text-muted-foreground"> | |
| + <p className="text-sm">No users found</p> | |
| + <p className="text-xs mt-1">Users appear here when they share their location</p> | |
| + </div> | |
| + )} | |
| + </div> | |
| + </ScrollArea> | |
| + </div> | |
| + ); | |
| +} | |
| + | |
| +interface UserItemProps { | |
| + user: { | |
| + id: string; | |
| + name?: string; | |
| + email?: string; | |
| + location: { latitude: number; longitude: number }; | |
| + lastSeen: string; | |
| + isOnline: boolean; | |
| + }; | |
| + isCurrentUser: boolean; | |
| + onFlyTo: (latitude: number, longitude: number) => void; | |
| +} | |
| + | |
| +function UserItem({ user, isCurrentUser, onFlyTo }: UserItemProps) { | |
| + const displayName = user.name || user.email?.split('@')[0] || 'Anonymous'; | |
| + | |
| + return ( | |
| + <button | |
| + className={cn( | |
| + 'w-full flex items-center gap-3 p-2 rounded-md text-left transition-colors', | |
| + 'hover:bg-accent hover:text-accent-foreground', | |
| + isCurrentUser && 'bg-primary/10' | |
| + )} | |
| + onClick={() => onFlyTo(user.location.latitude, user.location.longitude)} | |
| + > | |
| + <div | |
| + className={cn( | |
| + 'h-8 w-8 rounded-full flex items-center justify-center text-xs font-medium', | |
| + isCurrentUser | |
| + ? 'bg-green-500/20 text-green-500' | |
| + : user.isOnline | |
| + ? 'bg-purple-500/20 text-purple-500' | |
| + : 'bg-muted text-muted-foreground' | |
| + )} | |
| + > | |
| + {displayName.charAt(0).toUpperCase()} | |
| + </div> | |
| + | |
| + <div className="flex-1 min-w-0"> | |
| + <div className="flex items-center gap-1"> | |
| + <span className="text-sm font-medium truncate">{displayName}</span> | |
| + {isCurrentUser && ( | |
| + <span className="text-xs text-green-500">(You)</span> | |
| + )} | |
| + </div> | |
| + <div className="flex items-center gap-1 text-xs text-muted-foreground"> | |
| + <MapPin className="h-3 w-3" /> | |
| + <span> | |
| + {formatCoordinate(user.location.latitude, 'lat')},{' '} | |
| + {formatCoordinate(user.location.longitude, 'lon')} | |
| + </span> | |
| + </div> | |
| + </div> | |
| + | |
| + <div | |
| + className={cn( | |
| + 'h-2 w-2 rounded-full', | |
| + user.isOnline ? 'bg-green-500' : 'bg-gray-400' | |
| + )} | |
| + title={user.isOnline ? 'Online' : 'Offline'} | |
| + /> | |
| + </button> | |
| + ); | |
| +} | |
| diff --git a/components/providers/AnalyticsProvider.tsx b/components/providers/AnalyticsProvider.tsx | |
| new file mode 100644 | |
| index 0000000..151b6a4 | |
| --- /dev/null | |
| +++ b/components/providers/AnalyticsProvider.tsx | |
| @@ -0,0 +1,154 @@ | |
| +'use client'; | |
| + | |
| +import { useEffect, useRef, useCallback } from 'react'; | |
| +import { useAuthStore, useActiveUsersStore } from '@/store'; | |
| +import { | |
| + initPostHog, | |
| + identifyUser, | |
| + resetUser, | |
| + trackEvent, | |
| + setUserLocation, | |
| + getDistinctId, | |
| +} from '@/lib/posthog'; | |
| +import { getUserLocation, watchUserLocation, type LocationResult } from '@/lib/geolocation'; | |
| + | |
| +interface AnalyticsProviderProps { | |
| + children: React.ReactNode; | |
| +} | |
| + | |
| +// Interval for refreshing active users (30 seconds) | |
| +const ACTIVE_USERS_REFRESH_INTERVAL = 30000; | |
| + | |
| +// Interval for location updates to server (5 minutes) | |
| +const LOCATION_UPDATE_INTERVAL = 5 * 60 * 1000; | |
| + | |
| +export function AnalyticsProvider({ children }: AnalyticsProviderProps) { | |
| + const { user, isInitialized } = useAuthStore(); | |
| + const { fetchUsers, setCurrentUserId, addUser } = useActiveUsersStore(); | |
| + const locationWatcherRef = useRef<(() => void) | null>(null); | |
| + const lastLocationUpdateRef = useRef<number>(0); | |
| + | |
| + // Initialize PostHog on mount | |
| + useEffect(() => { | |
| + initPostHog(); | |
| + trackEvent('app_loaded', { source: 'initial_load' }); | |
| + }, []); | |
| + | |
| + // Handle location update to server | |
| + const handleLocationUpdate = useCallback( | |
| + async (location: LocationResult) => { | |
| + const distinctId = getDistinctId(); | |
| + if (!distinctId) return; | |
| + | |
| + // Rate limit server updates | |
| + const now = Date.now(); | |
| + if (now - lastLocationUpdateRef.current < LOCATION_UPDATE_INTERVAL) { | |
| + return; | |
| + } | |
| + lastLocationUpdateRef.current = now; | |
| + | |
| + // Update PostHog client-side | |
| + setUserLocation( | |
| + location.coordinates.latitude, | |
| + location.coordinates.longitude, | |
| + location.accuracy | |
| + ); | |
| + | |
| + // Track event | |
| + trackEvent('location_update', { | |
| + latitude: location.coordinates.latitude, | |
| + longitude: location.coordinates.longitude, | |
| + accuracy: location.accuracy, | |
| + source: location.source, | |
| + }); | |
| + | |
| + // Update server for active users visualization | |
| + try { | |
| + await fetch('/api/active-users', { | |
| + method: 'POST', | |
| + headers: { 'Content-Type': 'application/json' }, | |
| + body: JSON.stringify({ | |
| + distinctId, | |
| + latitude: location.coordinates.latitude, | |
| + longitude: location.coordinates.longitude, | |
| + accuracy: location.accuracy, | |
| + }), | |
| + }); | |
| + | |
| + // Update local store | |
| + addUser({ | |
| + id: distinctId, | |
| + distinctId, | |
| + email: user?.email, | |
| + name: user?.name, | |
| + location: location.coordinates, | |
| + lastSeen: new Date().toISOString(), | |
| + isOnline: true, | |
| + }); | |
| + } catch (error) { | |
| + console.error('Failed to update location on server:', error); | |
| + } | |
| + }, | |
| + [user, addUser] | |
| + ); | |
| + | |
| + // Identify user when authenticated | |
| + useEffect(() => { | |
| + if (!isInitialized) return; | |
| + | |
| + if (user) { | |
| + // Identify user in PostHog | |
| + identifyUser(user); | |
| + setCurrentUserId(user.id); | |
| + | |
| + // Get initial location | |
| + getUserLocation().then((result) => { | |
| + if (result.success) { | |
| + handleLocationUpdate(result); | |
| + } | |
| + }); | |
| + | |
| + // Start watching location for significant changes | |
| + locationWatcherRef.current = watchUserLocation( | |
| + (location) => { | |
| + handleLocationUpdate(location); | |
| + }, | |
| + (error) => { | |
| + console.warn('Location watch error:', error.error); | |
| + } | |
| + ); | |
| + } else { | |
| + // User logged out - reset PostHog identity | |
| + resetUser(); | |
| + setCurrentUserId(null); | |
| + | |
| + // Stop location watching | |
| + if (locationWatcherRef.current) { | |
| + locationWatcherRef.current(); | |
| + locationWatcherRef.current = null; | |
| + } | |
| + } | |
| + | |
| + return () => { | |
| + if (locationWatcherRef.current) { | |
| + locationWatcherRef.current(); | |
| + locationWatcherRef.current = null; | |
| + } | |
| + }; | |
| + }, [user, isInitialized, handleLocationUpdate, setCurrentUserId]); | |
| + | |
| + // Fetch active users periodically when authenticated | |
| + useEffect(() => { | |
| + if (!user) return; | |
| + | |
| + // Initial fetch | |
| + fetchUsers(); | |
| + | |
| + // Set up periodic refresh | |
| + const interval = setInterval(fetchUsers, ACTIVE_USERS_REFRESH_INTERVAL); | |
| + | |
| + return () => clearInterval(interval); | |
| + }, [user, fetchUsers]); | |
| + | |
| + return <>{children}</>; | |
| +} | |
| diff --git a/hooks/index.ts b/hooks/index.ts | |
| index 79b55ec..6d00b24 100644 | |
| --- a/hooks/index.ts | |
| +++ b/hooks/index.ts | |
| @@ -1,3 +1,4 @@ | |
| export { useDebounce, useDebouncedCallback } from './useDebounce'; | |
| export { useKeyboardShortcuts, KEYBOARD_SHORTCUTS } from './useKeyboardShortcuts'; | |
| export type { KeyboardShortcut } from './useKeyboardShortcuts'; | |
| +export { useAnalytics } from './useAnalytics'; | |
| diff --git a/hooks/useAnalytics.ts b/hooks/useAnalytics.ts | |
| new file mode 100644 | |
| index 0000000..97bdea3 | |
| --- /dev/null | |
| +++ b/hooks/useAnalytics.ts | |
| @@ -0,0 +1,107 @@ | |
| +import { useCallback } from 'react'; | |
| +import { useAuthStore } from '@/store'; | |
| +import { | |
| + trackEvent, | |
| + type TerraViewEvent, | |
| + type EventProperties, | |
| +} from '@/lib/posthog'; | |
| + | |
| +/** | |
| + * Custom hook for tracking analytics events | |
| + * Provides type-safe event tracking with automatic user context | |
| + */ | |
| +export function useAnalytics() { | |
| + const { user } = useAuthStore(); | |
| + | |
| + const track = useCallback( | |
| + <T extends TerraViewEvent>(event: T, properties?: EventProperties[T]) => { | |
| + // Only track if user is authenticated (to ensure PostHog identify has been called) | |
| + if (!user) { | |
| + return; | |
| + } | |
| + trackEvent(event, properties); | |
| + }, | |
| + [user] | |
| + ); | |
| + | |
| + // Convenience methods for common events | |
| + const trackGlobeInteraction = useCallback( | |
| + (action: EventProperties['globe_interaction']['action'], location?: { | |
| + latitude?: number; | |
| + longitude?: number; | |
| + altitude?: number; | |
| + }) => { | |
| + track('globe_interaction', { | |
| + action, | |
| + ...location, | |
| + }); | |
| + }, | |
| + [track] | |
| + ); | |
| + | |
| + const trackSearch = useCallback( | |
| + (query: string, resultsCount: number) => { | |
| + track('search_performed', { | |
| + query, | |
| + results_count: resultsCount, | |
| + }); | |
| + }, | |
| + [track] | |
| + ); | |
| + | |
| + const trackPlaceSaved = useCallback( | |
| + (placeId: string, latitude: number, longitude: number) => { | |
| + track('place_saved', { | |
| + place_id: placeId, | |
| + latitude, | |
| + longitude, | |
| + }); | |
| + }, | |
| + [track] | |
| + ); | |
| + | |
| + const trackPlaceDeleted = useCallback( | |
| + (placeId: string) => { | |
| + track('place_deleted', { | |
| + place_id: placeId, | |
| + }); | |
| + }, | |
| + [track] | |
| + ); | |
| + | |
| + const trackLayerChanged = useCallback( | |
| + (layerType: 'base' | 'overlay', layerName: string, enabled?: boolean) => { | |
| + track('layer_changed', { | |
| + layer_type: layerType, | |
| + layer_name: layerName, | |
| + enabled, | |
| + }); | |
| + }, | |
| + [track] | |
| + ); | |
| + | |
| + const trackMeasurementStarted = useCallback(() => { | |
| + track('measurement_started', {}); | |
| + }, [track]); | |
| + | |
| + const trackMeasurementCompleted = useCallback( | |
| + (pointsCount: number, totalDistanceKm: number) => { | |
| + track('measurement_completed', { | |
| + points_count: pointsCount, | |
| + total_distance_km: totalDistanceKm, | |
| + }); | |
| + }, | |
| + [track] | |
| + ); | |
| + | |
| + return { | |
| + track, | |
| + trackGlobeInteraction, | |
| + trackSearch, | |
| + trackPlaceSaved, | |
| + trackPlaceDeleted, | |
| + trackLayerChanged, | |
| + trackMeasurementStarted, | |
| + trackMeasurementCompleted, | |
| + }; | |
| +} | |
| diff --git a/lib/auth.ts b/lib/auth.ts | |
| new file mode 100644 | |
| index 0000000..e3059a4 | |
| --- /dev/null | |
| +++ b/lib/auth.ts | |
| @@ -0,0 +1,193 @@ | |
| +import { z } from 'zod'; | |
| +import { generateId } from './utils'; | |
| + | |
| +// User schema | |
| +export const UserSchema = z.object({ | |
| + id: z.string(), | |
| + email: z.string().email(), | |
| + name: z.string().optional(), | |
| + createdAt: z.string(), | |
| +}); | |
| + | |
| +export type User = z.infer<typeof UserSchema>; | |
| + | |
| +// Auth session schema | |
| +export const SessionSchema = z.object({ | |
| + user: UserSchema, | |
| + token: z.string(), | |
| + expiresAt: z.string(), | |
| +}); | |
| + | |
| +export type Session = z.infer<typeof SessionSchema>; | |
| + | |
| +// Auth state stored in localStorage | |
| +const AUTH_STORAGE_KEY = 'terraview-auth'; | |
| +const USERS_STORAGE_KEY = 'terraview-users'; | |
| + | |
| +// Session duration: 7 days | |
| +const SESSION_DURATION_MS = 7 * 24 * 60 * 60 * 1000; | |
| + | |
| +function getStoredUsers(): Map<string, User & { passwordHash: string }> { | |
| + if (typeof window === 'undefined') return new Map(); | |
| + | |
| + try { | |
| + const stored = localStorage.getItem(USERS_STORAGE_KEY); | |
| + if (!stored) return new Map(); | |
| + const users = JSON.parse(stored); | |
| + return new Map(Object.entries(users)); | |
| + } catch { | |
| + return new Map(); | |
| + } | |
| +} | |
| + | |
| +function saveUsers(users: Map<string, User & { passwordHash: string }>) { | |
| + if (typeof window === 'undefined') return; | |
| + localStorage.setItem(USERS_STORAGE_KEY, JSON.stringify(Object.fromEntries(users))); | |
| +} | |
| + | |
| +// Simple hash function for demo purposes (use bcrypt in production) | |
| +function hashPassword(password: string): string { | |
| + let hash = 0; | |
| + for (let i = 0; i < password.length; i++) { | |
| + const char = password.charCodeAt(i); | |
| + hash = ((hash << 5) - hash) + char; | |
| + hash = hash & hash; | |
| + } | |
| + return hash.toString(36) + password.length.toString(36); | |
| +} | |
| + | |
| +function verifyPassword(password: string, hash: string): boolean { | |
| + return hashPassword(password) === hash; | |
| +} | |
| + | |
| +export function getSession(): Session | null { | |
| + if (typeof window === 'undefined') return null; | |
| + | |
| + try { | |
| + const stored = localStorage.getItem(AUTH_STORAGE_KEY); | |
| + if (!stored) return null; | |
| + | |
| + const session = SessionSchema.parse(JSON.parse(stored)); | |
| + | |
| + // Check if session is expired | |
| + if (new Date(session.expiresAt) < new Date()) { | |
| + localStorage.removeItem(AUTH_STORAGE_KEY); | |
| + return null; | |
| + } | |
| + | |
| + return session; | |
| + } catch { | |
| + localStorage.removeItem(AUTH_STORAGE_KEY); | |
| + return null; | |
| + } | |
| +} | |
| + | |
| +export function saveSession(session: Session) { | |
| + if (typeof window === 'undefined') return; | |
| + localStorage.setItem(AUTH_STORAGE_KEY, JSON.stringify(session)); | |
| +} | |
| + | |
| +export function clearSession() { | |
| + if (typeof window === 'undefined') return; | |
| + localStorage.removeItem(AUTH_STORAGE_KEY); | |
| +} | |
| + | |
| +export async function signUp( | |
| + email: string, | |
| + password: string, | |
| + name?: string | |
| +): Promise<{ success: true; session: Session } | { success: false; error: string }> { | |
| + const users = getStoredUsers(); | |
| + | |
| + // Check if user already exists | |
| + const userValues = Array.from(users.values()); | |
| + for (const user of userValues) { | |
| + if (user.email.toLowerCase() === email.toLowerCase()) { | |
| + return { success: false, error: 'An account with this email already exists' }; | |
| + } | |
| + } | |
| + | |
| + // Validate email | |
| + const emailResult = z.string().email().safeParse(email); | |
| + if (!emailResult.success) { | |
| + return { success: false, error: 'Invalid email address' }; | |
| + } | |
| + | |
| + // Validate password | |
| + if (password.length < 6) { | |
| + return { success: false, error: 'Password must be at least 6 characters' }; | |
| + } | |
| + | |
| + // Create new user | |
| + const now = new Date().toISOString(); | |
| + const user: User & { passwordHash: string } = { | |
| + id: generateId(), | |
| + email: email.toLowerCase(), | |
| + name: name || email.split('@')[0], | |
| + createdAt: now, | |
| + passwordHash: hashPassword(password), | |
| + }; | |
| + | |
| + users.set(user.id, user); | |
| + saveUsers(users); | |
| + | |
| + // Create session | |
| + const session: Session = { | |
| + user: { | |
| + id: user.id, | |
| + email: user.email, | |
| + name: user.name, | |
| + createdAt: user.createdAt, | |
| + }, | |
| + token: generateId(), | |
| + expiresAt: new Date(Date.now() + SESSION_DURATION_MS).toISOString(), | |
| + }; | |
| + | |
| + saveSession(session); | |
| + return { success: true, session }; | |
| +} | |
| + | |
| +export async function signIn( | |
| + email: string, | |
| + password: string | |
| +): Promise<{ success: true; session: Session } | { success: false; error: string }> { | |
| + const users = getStoredUsers(); | |
| + | |
| + // Find user by email | |
| + let foundUser: (User & { passwordHash: string }) | null = null; | |
| + const userValues = Array.from(users.values()); | |
| + for (const user of userValues) { | |
| + if (user.email.toLowerCase() === email.toLowerCase()) { | |
| + foundUser = user; | |
| + break; | |
| + } | |
| + } | |
| + | |
| + if (!foundUser) { | |
| + return { success: false, error: 'Invalid email or password' }; | |
| + } | |
| + | |
| + // Verify password | |
| + if (!verifyPassword(password, foundUser.passwordHash)) { | |
| + return { success: false, error: 'Invalid email or password' }; | |
| + } | |
| + | |
| + // Create session | |
| + const session: Session = { | |
| + user: { | |
| + id: foundUser.id, | |
| + email: foundUser.email, | |
| + name: foundUser.name, | |
| + createdAt: foundUser.createdAt, | |
| + }, | |
| + token: generateId(), | |
| + expiresAt: new Date(Date.now() + SESSION_DURATION_MS).toISOString(), | |
| + }; | |
| + | |
| + saveSession(session); | |
| + return { success: true, session }; | |
| +} | |
| + | |
| +export function signOut() { | |
| + clearSession(); | |
| +} | |
| diff --git a/lib/composio.ts b/lib/composio.ts | |
| new file mode 100644 | |
| index 0000000..80dc59e | |
| --- /dev/null | |
| +++ b/lib/composio.ts | |
| @@ -0,0 +1,463 @@ | |
| +/** | |
| + * Composio Integration for PostHog Analytics | |
| + * | |
| + * This module provides server-side integration with PostHog through Composio. | |
| + * Composio is used to manage the PostHog connection and execute analytics operations. | |
| + * | |
| + * The integration supports: | |
| + * - Capturing events with user context | |
| + * - Updating user properties | |
| + * - Querying user data for visualization | |
| + */ | |
| + | |
| +import { Composio, OpenAIProvider } from '@composio/core'; | |
| +import OpenAI from 'openai'; | |
| +import type { Coordinates } from '@/types'; | |
| + | |
| +// Environment configuration | |
| +const COMPOSIO_API_KEY = process.env.COMPOSIO_API_KEY || ''; | |
| +const OPENAI_API_KEY = process.env.OPENAI_API_KEY || ''; | |
| +const POSTHOG_API_KEY = process.env.POSTHOG_API_KEY || ''; | |
| +const POSTHOG_PROJECT_ID = process.env.POSTHOG_PROJECT_ID || ''; | |
| +const POSTHOG_HOST = process.env.POSTHOG_HOST || 'https://us.i.posthog.com'; | |
| + | |
| +// Active user data structure | |
| +export interface ActiveUser { | |
| + id: string; | |
| + distinctId: string; | |
| + email?: string; | |
| + name?: string; | |
| + location: Coordinates; | |
| + lastSeen: string; | |
| + isOnline: boolean; | |
| +} | |
| + | |
| +// PostHog API response types | |
| +interface PostHogPerson { | |
| + distinct_ids: string[]; | |
| + properties: { | |
| + email?: string; | |
| + name?: string; | |
| + last_known_latitude?: number; | |
| + last_known_longitude?: number; | |
| + location_updated_at?: string; | |
| + $geoip_latitude?: number; | |
| + $geoip_longitude?: number; | |
| + }; | |
| +} | |
| + | |
| +interface PostHogPersonsResponse { | |
| + results: PostHogPerson[]; | |
| + next?: string; | |
| +} | |
| + | |
| +/** | |
| + * ComposioPostHogClient manages the connection to Composio and provides | |
| + * methods to interact with PostHog through Composio's tool system. | |
| + */ | |
| +export class ComposioPostHogClient { | |
| + private composio: Composio | null = null; | |
| + private openai: OpenAI | null = null; | |
| + private provider: OpenAIProvider | null = null; | |
| + private isInitialized = false; | |
| + | |
| + constructor() { | |
| + this.initializeClients(); | |
| + } | |
| + | |
| + private initializeClients() { | |
| + if (!COMPOSIO_API_KEY) { | |
| + console.warn('Composio API key not configured. Composio features will be disabled.'); | |
| + return; | |
| + } | |
| + | |
| + if (!OPENAI_API_KEY) { | |
| + console.warn('OpenAI API key not configured. AI-powered features will be disabled.'); | |
| + return; | |
| + } | |
| + | |
| + try { | |
| + // Initialize OpenAI client | |
| + this.openai = new OpenAI({ | |
| + apiKey: OPENAI_API_KEY, | |
| + }); | |
| + | |
| + // Initialize Composio with OpenAI provider from core | |
| + this.provider = new OpenAIProvider(); | |
| + this.composio = new Composio({ | |
| + apiKey: COMPOSIO_API_KEY, | |
| + provider: this.provider, | |
| + }); | |
| + | |
| + this.isInitialized = true; | |
| + } catch (error) { | |
| + console.error('Failed to initialize Composio client:', error); | |
| + } | |
| + } | |
| + | |
| + /** | |
| + * Get available PostHog tools from Composio | |
| + */ | |
| + async getPostHogTools(userId: string) { | |
| + if (!this.composio || !this.isInitialized) { | |
| + return []; | |
| + } | |
| + | |
| + try { | |
| + const tools = await this.composio.tools.get(userId, { | |
| + toolkits: ['posthog'], | |
| + }); | |
| + return tools; | |
| + } catch (error) { | |
| + console.error('Failed to get PostHog tools:', error); | |
| + return []; | |
| + } | |
| + } | |
| + | |
| + /** | |
| + * Execute a PostHog action using Composio and OpenAI | |
| + */ | |
| + async executePostHogAction( | |
| + userId: string, | |
| + action: string, | |
| + parameters: Record<string, unknown> | |
| + ): Promise<unknown> { | |
| + if (!this.composio || !this.openai || !this.provider || !this.isInitialized) { | |
| + console.warn('Composio not initialized, skipping action:', action); | |
| + return null; | |
| + } | |
| + | |
| + try { | |
| + // Get PostHog tools | |
| + const tools = await this.getPostHogTools(userId); | |
| + | |
| + if (tools.length === 0) { | |
| + console.warn('No PostHog tools available'); | |
| + return null; | |
| + } | |
| + | |
| + // Create a prompt for the action | |
| + const prompt = `Execute the PostHog action "${action}" with these parameters: ${JSON.stringify(parameters)}`; | |
| + | |
| + // Use OpenAI Chat Completions API with Composio tools | |
| + const response = await this.openai.chat.completions.create({ | |
| + model: 'gpt-4o-mini', | |
| + messages: [ | |
| + { | |
| + role: 'system', | |
| + content: 'You are an analytics assistant. Execute the requested PostHog action using the available tools.', | |
| + }, | |
| + { | |
| + role: 'user', | |
| + content: prompt, | |
| + }, | |
| + ], | |
| + tools: tools as unknown as OpenAI.ChatCompletionTool[], | |
| + tool_choice: 'auto', | |
| + }); | |
| + | |
| + // Handle tool calls if any | |
| + const toolCalls = response.choices[0]?.message?.tool_calls; | |
| + if (toolCalls && toolCalls.length > 0) { | |
| + // Execute each tool call using the composio SDK | |
| + const results = await Promise.all( | |
| + toolCalls.map(async (toolCall) => { | |
| + try { | |
| + // Use composio to execute the tool directly | |
| + const result = await this.composio!.tools.execute(toolCall.function.name, { | |
| + userId, | |
| + arguments: JSON.parse(toolCall.function.arguments), | |
| + dangerouslySkipVersionCheck: true, // For simplicity in this demo | |
| + }); | |
| + return result; | |
| + } catch (err) { | |
| + console.error('Tool execution error:', err); | |
| + return null; | |
| + } | |
| + }) | |
| + ); | |
| + return results; | |
| + } | |
| + | |
| + return response.choices[0]?.message?.content; | |
| + } catch (error) { | |
| + console.error('Failed to execute PostHog action:', error); | |
| + return null; | |
| + } | |
| + } | |
| + | |
| + /** | |
| + * Check if Composio is properly initialized | |
| + */ | |
| + isReady(): boolean { | |
| + return this.isInitialized; | |
| + } | |
| +} | |
| + | |
| +/** | |
| + * PostHogComposioService provides high-level methods for PostHog operations | |
| + * using the Composio client for tool management. | |
| + */ | |
| +export class PostHogComposioService { | |
| + private composioClient: ComposioPostHogClient; | |
| + private posthogApiKey: string; | |
| + private posthogHost: string; | |
| + private projectId: string; | |
| + | |
| + constructor() { | |
| + this.composioClient = new ComposioPostHogClient(); | |
| + this.posthogApiKey = POSTHOG_API_KEY; | |
| + this.posthogHost = POSTHOG_HOST; | |
| + this.projectId = POSTHOG_PROJECT_ID; | |
| + } | |
| + | |
| + /** | |
| + * Initialize the service for a specific user | |
| + */ | |
| + async initialize(userId: string): Promise<void> { | |
| + // Composio initializes lazily, nothing to do here | |
| + } | |
| + | |
| + /** | |
| + * Capture an event via Composio/PostHog | |
| + */ | |
| + async captureEvent( | |
| + distinctId: string, | |
| + event: string, | |
| + properties?: Record<string, unknown> | |
| + ): Promise<boolean> { | |
| + // First, try using Composio if available | |
| + if (this.composioClient.isReady()) { | |
| + const result = await this.composioClient.executePostHogAction( | |
| + distinctId, | |
| + 'capture_event', | |
| + { | |
| + distinct_id: distinctId, | |
| + event, | |
| + properties: { | |
| + ...properties, | |
| + $lib: 'composio-terraview', | |
| + timestamp: new Date().toISOString(), | |
| + }, | |
| + } | |
| + ); | |
| + | |
| + if (result !== null) { | |
| + return true; | |
| + } | |
| + } | |
| + | |
| + // Fallback to direct PostHog API | |
| + return this.captureEventDirect(distinctId, event, properties); | |
| + } | |
| + | |
| + /** | |
| + * Direct PostHog API call for event capture (fallback) | |
| + */ | |
| + private async captureEventDirect( | |
| + distinctId: string, | |
| + event: string, | |
| + properties?: Record<string, unknown> | |
| + ): Promise<boolean> { | |
| + if (!this.posthogApiKey) { | |
| + console.warn('PostHog API key not configured'); | |
| + return false; | |
| + } | |
| + | |
| + try { | |
| + const response = await fetch(`${this.posthogHost}/capture/`, { | |
| + method: 'POST', | |
| + headers: { | |
| + 'Content-Type': 'application/json', | |
| + }, | |
| + body: JSON.stringify({ | |
| + api_key: this.posthogApiKey, | |
| + distinct_id: distinctId, | |
| + event, | |
| + properties: { | |
| + ...properties, | |
| + $lib: 'composio-terraview', | |
| + timestamp: new Date().toISOString(), | |
| + }, | |
| + }), | |
| + }); | |
| + | |
| + return response.ok; | |
| + } catch (error) { | |
| + console.error('Failed to capture event:', error); | |
| + return false; | |
| + } | |
| + } | |
| + | |
| + /** | |
| + * Update user properties via Composio/PostHog | |
| + */ | |
| + async setUserProperties( | |
| + distinctId: string, | |
| + properties: Record<string, unknown> | |
| + ): Promise<boolean> { | |
| + // Try Composio if available | |
| + if (this.composioClient.isReady()) { | |
| + const result = await this.composioClient.executePostHogAction( | |
| + distinctId, | |
| + 'identify_user', | |
| + { | |
| + distinct_id: distinctId, | |
| + properties, | |
| + } | |
| + ); | |
| + | |
| + if (result !== null) { | |
| + return true; | |
| + } | |
| + } | |
| + | |
| + // Fallback to direct API | |
| + return this.setUserPropertiesDirect(distinctId, properties); | |
| + } | |
| + | |
| + /** | |
| + * Direct PostHog API call for setting user properties (fallback) | |
| + */ | |
| + private async setUserPropertiesDirect( | |
| + distinctId: string, | |
| + properties: Record<string, unknown> | |
| + ): Promise<boolean> { | |
| + if (!this.posthogApiKey) { | |
| + return false; | |
| + } | |
| + | |
| + try { | |
| + const response = await fetch(`${this.posthogHost}/capture/`, { | |
| + method: 'POST', | |
| + headers: { | |
| + 'Content-Type': 'application/json', | |
| + }, | |
| + body: JSON.stringify({ | |
| + api_key: this.posthogApiKey, | |
| + distinct_id: distinctId, | |
| + event: '$identify', | |
| + properties, | |
| + $set: properties, | |
| + }), | |
| + }); | |
| + | |
| + return response.ok; | |
| + } catch (error) { | |
| + console.error('Failed to set user properties:', error); | |
| + return false; | |
| + } | |
| + } | |
| + | |
| + /** | |
| + * Update user location via Composio/PostHog | |
| + */ | |
| + async updateUserLocation( | |
| + distinctId: string, | |
| + latitude: number, | |
| + longitude: number, | |
| + accuracy?: number | |
| + ): Promise<boolean> { | |
| + const locationProperties: Record<string, unknown> = { | |
| + last_known_latitude: latitude, | |
| + last_known_longitude: longitude, | |
| + location_updated_at: new Date().toISOString(), | |
| + }; | |
| + | |
| + if (accuracy !== undefined) { | |
| + locationProperties.location_accuracy_meters = accuracy; | |
| + } | |
| + | |
| + // Capture location event | |
| + await this.captureEvent(distinctId, 'location_update', { | |
| + latitude, | |
| + longitude, | |
| + accuracy, | |
| + source: 'browser_geolocation', | |
| + }); | |
| + | |
| + // Update user properties | |
| + return this.setUserProperties(distinctId, locationProperties); | |
| + } | |
| + | |
| + /** | |
| + * Fetch active users with their locations from PostHog | |
| + * This uses the PostHog API to query persons with recent location data | |
| + */ | |
| + async getActiveUsers(limit = 100): Promise<ActiveUser[]> { | |
| + if (!this.posthogApiKey || !this.projectId) { | |
| + console.warn('PostHog API key or project ID not configured'); | |
| + return []; | |
| + } | |
| + | |
| + try { | |
| + // Query persons with location data from PostHog | |
| + const response = await fetch( | |
| + `${this.posthogHost}/api/projects/${this.projectId}/persons/?properties=[{"key":"last_known_latitude","type":"person","operator":"is_set"}]&limit=${limit}`, | |
| + { | |
| + headers: { | |
| + Authorization: `Bearer ${this.posthogApiKey}`, | |
| + }, | |
| + } | |
| + ); | |
| + | |
| + if (!response.ok) { | |
| + throw new Error(`Failed to fetch persons: ${response.statusText}`); | |
| + } | |
| + | |
| + const data: PostHogPersonsResponse = await response.json(); | |
| + | |
| + // Transform to ActiveUser format | |
| + const activeUsers: ActiveUser[] = data.results | |
| + .filter((person) => { | |
| + const lat = | |
| + person.properties.last_known_latitude ?? | |
| + person.properties.$geoip_latitude; | |
| + const lon = | |
| + person.properties.last_known_longitude ?? | |
| + person.properties.$geoip_longitude; | |
| + return lat !== undefined && lon !== undefined; | |
| + }) | |
| + .map((person) => { | |
| + const lat = | |
| + person.properties.last_known_latitude ?? | |
| + person.properties.$geoip_latitude ?? | |
| + 0; | |
| + const lon = | |
| + person.properties.last_known_longitude ?? | |
| + person.properties.$geoip_longitude ?? | |
| + 0; | |
| + const lastSeen = person.properties.location_updated_at || new Date().toISOString(); | |
| + const hourAgo = new Date(Date.now() - 60 * 60 * 1000).toISOString(); | |
| + | |
| + return { | |
| + id: person.distinct_ids[0], | |
| + distinctId: person.distinct_ids[0], | |
| + email: person.properties.email, | |
| + name: person.properties.name, | |
| + location: { | |
| + latitude: lat, | |
| + longitude: lon, | |
| + }, | |
| + lastSeen, | |
| + isOnline: lastSeen > hourAgo, | |
| + }; | |
| + }); | |
| + | |
| + return activeUsers; | |
| + } catch (error) { | |
| + console.error('Failed to fetch active users:', error); | |
| + return []; | |
| + } | |
| + } | |
| +} | |
| + | |
| +// Singleton instance for the service | |
| +let serviceInstance: PostHogComposioService | null = null; | |
| + | |
| +export function getPostHogComposioService(): PostHogComposioService { | |
| + if (!serviceInstance) { | |
| + serviceInstance = new PostHogComposioService(); | |
| + } | |
| + return serviceInstance; | |
| +} | |
| diff --git a/lib/geolocation.ts b/lib/geolocation.ts | |
| new file mode 100644 | |
| index 0000000..bfff86b | |
| --- /dev/null | |
| +++ b/lib/geolocation.ts | |
| @@ -0,0 +1,293 @@ | |
| +import type { Coordinates } from '@/types'; | |
| + | |
| +// Location tracking configuration | |
| +const LOCATION_OPTIONS: PositionOptions = { | |
| + enableHighAccuracy: false, // Use low accuracy for better battery/privacy | |
| + timeout: 10000, | |
| + maximumAge: 300000, // Cache for 5 minutes | |
| +}; | |
| + | |
| +// Minimum distance change (in km) to trigger a location update | |
| +const MIN_DISTANCE_CHANGE_KM = 0.5; | |
| + | |
| +// Location result type | |
| +export interface LocationResult { | |
| + success: true; | |
| + coordinates: Coordinates; | |
| + accuracy: number; | |
| + source: 'geolocation' | 'ip_fallback'; | |
| +} | |
| + | |
| +export interface LocationError { | |
| + success: false; | |
| + error: string; | |
| + code: 'PERMISSION_DENIED' | 'POSITION_UNAVAILABLE' | 'TIMEOUT' | 'NOT_SUPPORTED'; | |
| +} | |
| + | |
| +export type LocationResponse = LocationResult | LocationError; | |
| + | |
| +// Cache for last known location | |
| +let lastKnownLocation: LocationResult | null = null; | |
| + | |
| +/** | |
| + * Calculate distance between two points using Haversine formula | |
| + */ | |
| +function calculateDistance( | |
| + lat1: number, | |
| + lon1: number, | |
| + lat2: number, | |
| + lon2: number | |
| +): number { | |
| + const R = 6371; // Earth's radius in km | |
| + const dLat = toRad(lat2 - lat1); | |
| + const dLon = toRad(lon2 - lon1); | |
| + const a = | |
| + Math.sin(dLat / 2) * Math.sin(dLat / 2) + | |
| + Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.sin(dLon / 2) * Math.sin(dLon / 2); | |
| + const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); | |
| + return R * c; | |
| +} | |
| + | |
| +function toRad(deg: number): number { | |
| + return deg * (Math.PI / 180); | |
| +} | |
| + | |
| +/** | |
| + * Check if geolocation is supported in the current browser | |
| + */ | |
| +export function isGeolocationSupported(): boolean { | |
| + return typeof navigator !== 'undefined' && 'geolocation' in navigator; | |
| +} | |
| + | |
| +/** | |
| + * Get current location using browser geolocation API | |
| + */ | |
| +export function getCurrentLocation(): Promise<LocationResponse> { | |
| + return new Promise((resolve) => { | |
| + if (!isGeolocationSupported()) { | |
| + resolve({ | |
| + success: false, | |
| + error: 'Geolocation is not supported by this browser', | |
| + code: 'NOT_SUPPORTED', | |
| + }); | |
| + return; | |
| + } | |
| + | |
| + navigator.geolocation.getCurrentPosition( | |
| + (position) => { | |
| + const result: LocationResult = { | |
| + success: true, | |
| + coordinates: { | |
| + latitude: position.coords.latitude, | |
| + longitude: position.coords.longitude, | |
| + }, | |
| + accuracy: position.coords.accuracy, | |
| + source: 'geolocation', | |
| + }; | |
| + lastKnownLocation = result; | |
| + resolve(result); | |
| + }, | |
| + (error) => { | |
| + let code: LocationError['code']; | |
| + let errorMessage: string; | |
| + | |
| + switch (error.code) { | |
| + case error.PERMISSION_DENIED: | |
| + code = 'PERMISSION_DENIED'; | |
| + errorMessage = 'Location permission denied'; | |
| + break; | |
| + case error.POSITION_UNAVAILABLE: | |
| + code = 'POSITION_UNAVAILABLE'; | |
| + errorMessage = 'Location information unavailable'; | |
| + break; | |
| + case error.TIMEOUT: | |
| + code = 'TIMEOUT'; | |
| + errorMessage = 'Location request timed out'; | |
| + break; | |
| + default: | |
| + code = 'POSITION_UNAVAILABLE'; | |
| + errorMessage = 'Unknown error occurred'; | |
| + } | |
| + | |
| + resolve({ | |
| + success: false, | |
| + error: errorMessage, | |
| + code, | |
| + }); | |
| + }, | |
| + LOCATION_OPTIONS | |
| + ); | |
| + }); | |
| +} | |
| + | |
| +/** | |
| + * Try to get location from IP-based geolocation as fallback | |
| + */ | |
| +export async function getLocationFromIP(): Promise<LocationResponse> { | |
| + try { | |
| + // Use ip-api.com for IP-based geolocation (free, no API key required) | |
| + const response = await fetch('http://ip-api.com/json/?fields=lat,lon,status,message'); | |
| + | |
| + if (!response.ok) { | |
| + throw new Error('IP geolocation request failed'); | |
| + } | |
| + | |
| + const data = await response.json(); | |
| + | |
| + if (data.status === 'fail') { | |
| + return { | |
| + success: false, | |
| + error: data.message || 'IP geolocation failed', | |
| + code: 'POSITION_UNAVAILABLE', | |
| + }; | |
| + } | |
| + | |
| + const result: LocationResult = { | |
| + success: true, | |
| + coordinates: { | |
| + latitude: data.lat, | |
| + longitude: data.lon, | |
| + }, | |
| + accuracy: 50000, // IP-based location is very approximate (~50km) | |
| + source: 'ip_fallback', | |
| + }; | |
| + | |
| + // Only update cache if we don't have a better location | |
| + if (!lastKnownLocation || lastKnownLocation.source === 'ip_fallback') { | |
| + lastKnownLocation = result; | |
| + } | |
| + | |
| + return result; | |
| + } catch (error) { | |
| + return { | |
| + success: false, | |
| + error: error instanceof Error ? error.message : 'IP geolocation failed', | |
| + code: 'POSITION_UNAVAILABLE', | |
| + }; | |
| + } | |
| +} | |
| + | |
| +/** | |
| + * Get user location with automatic fallback | |
| + * First tries browser geolocation, then falls back to IP-based location | |
| + */ | |
| +export async function getUserLocation(): Promise<LocationResponse> { | |
| + // Try browser geolocation first | |
| + const browserLocation = await getCurrentLocation(); | |
| + | |
| + if (browserLocation.success) { | |
| + return browserLocation; | |
| + } | |
| + | |
| + // If permission denied or not supported, try IP fallback | |
| + if ( | |
| + browserLocation.code === 'PERMISSION_DENIED' || | |
| + browserLocation.code === 'NOT_SUPPORTED' | |
| + ) { | |
| + return getLocationFromIP(); | |
| + } | |
| + | |
| + // For timeout or unavailable, still try IP but prefer browser result on retry | |
| + const ipLocation = await getLocationFromIP(); | |
| + | |
| + if (ipLocation.success) { | |
| + return ipLocation; | |
| + } | |
| + | |
| + // Return the original browser error if IP also failed | |
| + return browserLocation; | |
| +} | |
| + | |
| +/** | |
| + * Get the last known location (cached) | |
| + */ | |
| +export function getLastKnownLocation(): LocationResult | null { | |
| + return lastKnownLocation; | |
| +} | |
| + | |
| +/** | |
| + * Check if the location has changed significantly | |
| + */ | |
| +export function hasLocationChangedSignificantly(newCoords: Coordinates): boolean { | |
| + if (!lastKnownLocation) { | |
| + return true; | |
| + } | |
| + | |
| + const distance = calculateDistance( | |
| + lastKnownLocation.coordinates.latitude, | |
| + lastKnownLocation.coordinates.longitude, | |
| + newCoords.latitude, | |
| + newCoords.longitude | |
| + ); | |
| + | |
| + return distance >= MIN_DISTANCE_CHANGE_KM; | |
| +} | |
| + | |
| +/** | |
| + * Watch user position with callback on significant changes | |
| + * Returns a cleanup function to stop watching | |
| + */ | |
| +export function watchUserLocation( | |
| + onLocationChange: (location: LocationResult) => void, | |
| + onError?: (error: LocationError) => void | |
| +): () => void { | |
| + if (!isGeolocationSupported()) { | |
| + onError?.({ | |
| + success: false, | |
| + error: 'Geolocation not supported', | |
| + code: 'NOT_SUPPORTED', | |
| + }); | |
| + return () => {}; | |
| + } | |
| + | |
| + const watchId = navigator.geolocation.watchPosition( | |
| + (position) => { | |
| + const newCoords: Coordinates = { | |
| + latitude: position.coords.latitude, | |
| + longitude: position.coords.longitude, | |
| + }; | |
| + | |
| + // Only trigger callback on significant location change | |
| + if (hasLocationChangedSignificantly(newCoords)) { | |
| + const result: LocationResult = { | |
| + success: true, | |
| + coordinates: newCoords, | |
| + accuracy: position.coords.accuracy, | |
| + source: 'geolocation', | |
| + }; | |
| + lastKnownLocation = result; | |
| + onLocationChange(result); | |
| + } | |
| + }, | |
| + (error) => { | |
| + let code: LocationError['code']; | |
| + switch (error.code) { | |
| + case error.PERMISSION_DENIED: | |
| + code = 'PERMISSION_DENIED'; | |
| + break; | |
| + case error.POSITION_UNAVAILABLE: | |
| + code = 'POSITION_UNAVAILABLE'; | |
| + break; | |
| + case error.TIMEOUT: | |
| + code = 'TIMEOUT'; | |
| + break; | |
| + default: | |
| + code = 'POSITION_UNAVAILABLE'; | |
| + } | |
| + | |
| + onError?.({ | |
| + success: false, | |
| + error: error.message, | |
| + code, | |
| + }); | |
| + }, | |
| + { | |
| + ...LOCATION_OPTIONS, | |
| + maximumAge: 60000, // Refresh more frequently when watching | |
| + } | |
| + ); | |
| + | |
| + return () => { | |
| + navigator.geolocation.clearWatch(watchId); | |
| + }; | |
| +} | |
| diff --git a/lib/posthog.ts b/lib/posthog.ts | |
| new file mode 100644 | |
| index 0000000..0311022 | |
| --- /dev/null | |
| +++ b/lib/posthog.ts | |
| @@ -0,0 +1,174 @@ | |
| +import posthog from 'posthog-js'; | |
| +import type { User } from './auth'; | |
| + | |
| +// PostHog configuration | |
| +const POSTHOG_KEY = process.env.NEXT_PUBLIC_POSTHOG_KEY || ''; | |
| +const POSTHOG_HOST = process.env.NEXT_PUBLIC_POSTHOG_HOST || 'https://us.i.posthog.com'; | |
| + | |
| +let isInitialized = false; | |
| + | |
| +// Event types for type safety | |
| +export type TerraViewEvent = | |
| + | 'app_loaded' | |
| + | 'user_logged_in' | |
| + | 'user_signed_up' | |
| + | 'user_logged_out' | |
| + | 'globe_interaction' | |
| + | 'location_update' | |
| + | 'place_saved' | |
| + | 'place_deleted' | |
| + | 'search_performed' | |
| + | 'layer_changed' | |
| + | 'measurement_started' | |
| + | 'measurement_completed'; | |
| + | |
| +// Event properties type | |
| +export interface EventProperties { | |
| + app_loaded: { source?: string }; | |
| + user_logged_in: { method: string }; | |
| + user_signed_up: { method: string }; | |
| + user_logged_out: Record<string, never>; | |
| + globe_interaction: { | |
| + action: 'zoom_in' | 'zoom_out' | 'pan' | 'rotate' | 'tilt' | 'fly_to' | 'reset'; | |
| + latitude?: number; | |
| + longitude?: number; | |
| + altitude?: number; | |
| + }; | |
| + location_update: { | |
| + latitude: number; | |
| + longitude: number; | |
| + accuracy?: number; | |
| + source: 'geolocation' | 'ip_fallback'; | |
| + }; | |
| + place_saved: { | |
| + place_id: string; | |
| + latitude: number; | |
| + longitude: number; | |
| + }; | |
| + place_deleted: { | |
| + place_id: string; | |
| + }; | |
| + search_performed: { | |
| + query: string; | |
| + results_count: number; | |
| + }; | |
| + layer_changed: { | |
| + layer_type: 'base' | 'overlay'; | |
| + layer_name: string; | |
| + enabled?: boolean; | |
| + }; | |
| + measurement_started: Record<string, never>; | |
| + measurement_completed: { | |
| + points_count: number; | |
| + total_distance_km: number; | |
| + }; | |
| +} | |
| + | |
| +// Initialize PostHog on the client | |
| +export function initPostHog(): void { | |
| + if (typeof window === 'undefined') return; | |
| + if (isInitialized) return; | |
| + if (!POSTHOG_KEY) { | |
| + console.warn('PostHog key not configured. Analytics will be disabled.'); | |
| + return; | |
| + } | |
| + | |
| + posthog.init(POSTHOG_KEY, { | |
| + api_host: POSTHOG_HOST, | |
| + person_profiles: 'identified_only', | |
| + capture_pageview: false, // We'll handle this manually | |
| + capture_pageleave: true, | |
| + persistence: 'localStorage', | |
| + autocapture: false, // Disable autocapture for more control | |
| + loaded: (ph) => { | |
| + // Enable debug in development | |
| + if (process.env.NODE_ENV === 'development') { | |
| + ph.debug(); | |
| + } | |
| + }, | |
| + }); | |
| + | |
| + isInitialized = true; | |
| +} | |
| + | |
| +// Identify user after authentication | |
| +export function identifyUser(user: User): void { | |
| + if (typeof window === 'undefined' || !isInitialized) return; | |
| + | |
| + posthog.identify(user.id, { | |
| + email: user.email, | |
| + name: user.name, | |
| + created_at: user.createdAt, | |
| + }); | |
| +} | |
| + | |
| +// Reset user identity on logout | |
| +export function resetUser(): void { | |
| + if (typeof window === 'undefined' || !isInitialized) return; | |
| + posthog.reset(); | |
| +} | |
| + | |
| +// Track an event with type safety | |
| +export function trackEvent<T extends TerraViewEvent>( | |
| + event: T, | |
| + properties?: EventProperties[T] | |
| +): void { | |
| + if (typeof window === 'undefined' || !isInitialized) return; | |
| + | |
| + posthog.capture(event, { | |
| + ...properties, | |
| + timestamp: new Date().toISOString(), | |
| + }); | |
| +} | |
| + | |
| +// Update user properties (e.g., location) | |
| +export function setUserProperties(properties: Record<string, unknown>): void { | |
| + if (typeof window === 'undefined' || !isInitialized) return; | |
| + posthog.people.set(properties); | |
| +} | |
| + | |
| +// Set user location as a property | |
| +export function setUserLocation( | |
| + latitude: number, | |
| + longitude: number, | |
| + accuracy?: number | |
| +): void { | |
| + if (typeof window === 'undefined' || !isInitialized) return; | |
| + | |
| + const locationProps: Record<string, unknown> = { | |
| + '$geoip_latitude': latitude, | |
| + '$geoip_longitude': longitude, | |
| + 'last_known_latitude': latitude, | |
| + 'last_known_longitude': longitude, | |
| + 'location_updated_at': new Date().toISOString(), | |
| + }; | |
| + | |
| + if (accuracy !== undefined) { | |
| + locationProps['location_accuracy_meters'] = accuracy; | |
| + } | |
| + | |
| + posthog.people.set(locationProps); | |
| +} | |
| + | |
| +// Get PostHog instance for advanced usage | |
| +export function getPostHog() { | |
| + if (typeof window === 'undefined') return null; | |
| + return isInitialized ? posthog : null; | |
| +} | |
| + | |
| +// Check if PostHog is ready | |
| +export function isPostHogReady(): boolean { | |
| + return isInitialized && typeof window !== 'undefined'; | |
| +} | |
| + | |
| +// Feature flags support | |
| +export function isFeatureEnabled(flagKey: string): boolean { | |
| + if (typeof window === 'undefined' || !isInitialized) return false; | |
| + return posthog.isFeatureEnabled(flagKey) ?? false; | |
| +} | |
| + | |
| +// Get distinct ID for current user | |
| +export function getDistinctId(): string | null { | |
| + if (typeof window === 'undefined' || !isInitialized) return null; | |
| + return posthog.get_distinct_id(); | |
| +} | |
| diff --git a/package-lock.json b/package-lock.json | |
| index 43006b9..a4f69f3 100644 | |
| --- a/package-lock.json | |
| +++ b/package-lock.json | |
| @@ -8,6 +8,8 @@ | |
| "name": "terraview", | |
| "version": "1.0.0", | |
| "dependencies": { | |
| + "@composio/core": "^0.6.3", | |
| + "@composio/openai": "^0.6.3", | |
| "@radix-ui/react-dialog": "^1.1.2", | |
| "@radix-ui/react-dropdown-menu": "^2.1.2", | |
| "@radix-ui/react-label": "^2.1.0", | |
| @@ -23,6 +25,8 @@ | |
| "lucide-react": "^0.454.0", | |
| "next": "14.2.15", | |
| "next-themes": "^0.3.0", | |
| + "openai": "^4.77.0", | |
| + "posthog-js": "^1.194.4", | |
| "react": "18.2.0", | |
| "react-dom": "18.2.0", | |
| "tailwind-merge": "^2.5.4", | |
| @@ -46,6 +50,7 @@ | |
| "version": "5.2.0", | |
| "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", | |
| "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "engines": { | |
| "node": ">=10" | |
| @@ -105,6 +110,71 @@ | |
| "node": ">=20.19.0" | |
| } | |
| }, | |
| + "node_modules/@composio/client": { | |
| + "version": "0.1.0-alpha.56", | |
| + "resolved": "https://registry.npmjs.org/@composio/client/-/client-0.1.0-alpha.56.tgz", | |
| + "integrity": "sha512-hNgChB5uhdvT4QXNzzfUuvtG6vrfanQQFY2hPyKwbeR4x6mEmIGFiZ4y2qynErdUWldAZiB/7pY/MBMg6Q9E0g==", | |
| + "license": "Apache-2.0" | |
| + }, | |
| + "node_modules/@composio/core": { | |
| + "version": "0.6.3", | |
| + "resolved": "https://registry.npmjs.org/@composio/core/-/core-0.6.3.tgz", | |
| + "integrity": "sha512-PZm4LQGMaaDFHWUouMHqKPg5fNfgjM2l0zF0Vw/vfWJ34KYyo1ne6YjhGvBDmOIKPByT6Dal4/ff7AHpjedL/w==", | |
| + "license": "ISC", | |
| + "dependencies": { | |
| + "@composio/client": "0.1.0-alpha.56", | |
| + "@composio/json-schema-to-zod": "0.1.20", | |
| + "@types/json-schema": "^7.0.15", | |
| + "chalk": "^4.1.2", | |
| + "openai": "^6.16.0", | |
| + "pusher-js": "^8.4.0", | |
| + "semver": "^7.7.2", | |
| + "zod-to-json-schema": "^3.25.1" | |
| + }, | |
| + "peerDependencies": { | |
| + "zod": "^3.25 || ^4" | |
| + } | |
| + }, | |
| + "node_modules/@composio/core/node_modules/openai": { | |
| + "version": "6.17.0", | |
| + "resolved": "https://registry.npmjs.org/openai/-/openai-6.17.0.tgz", | |
| + "integrity": "sha512-NHRpPEUPzAvFOAFs9+9pC6+HCw/iWsYsKCMPXH5Kw7BpMxqd8g/A07/1o7Gx2TWtCnzevVRyKMRFqyiHyAlqcA==", | |
| + "license": "Apache-2.0", | |
| + "bin": { | |
| + "openai": "bin/cli" | |
| + }, | |
| + "peerDependencies": { | |
| + "ws": "^8.18.0", | |
| + "zod": "^3.25 || ^4.0" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "ws": { | |
| + "optional": true | |
| + }, | |
| + "zod": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/@composio/json-schema-to-zod": { | |
| + "version": "0.1.20", | |
| + "resolved": "https://registry.npmjs.org/@composio/json-schema-to-zod/-/json-schema-to-zod-0.1.20.tgz", | |
| + "integrity": "sha512-d4V34itLrUWG/VBh7ciznKcxF/T22MBLHmuEzHoX0zsBOHsUmjYz5qtDh20S2p3FE+HHvLZxpXiv8yfdd4yI+Q==", | |
| + "license": "ISC", | |
| + "peerDependencies": { | |
| + "zod": ">=3.25.76 <5" | |
| + } | |
| + }, | |
| + "node_modules/@composio/openai": { | |
| + "version": "0.6.3", | |
| + "resolved": "https://registry.npmjs.org/@composio/openai/-/openai-0.6.3.tgz", | |
| + "integrity": "sha512-AnhE6Fu2zzLDB2Bf9O73pTfyF3e0RmR1795o3HrR6SkRDXT+dX1Laquc4g3ioMbReZAYVrt8SWnlSsvs7WPEuA==", | |
| + "license": "ISC", | |
| + "peerDependencies": { | |
| + "@composio/core": "0.6.3", | |
| + "openai": "^6.16.0" | |
| + } | |
| + }, | |
| "node_modules/@emnapi/core": { | |
| "version": "1.8.1", | |
| "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.8.1.tgz", | |
| @@ -329,6 +399,7 @@ | |
| "version": "0.3.13", | |
| "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", | |
| "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "dependencies": { | |
| "@jridgewell/sourcemap-codec": "^1.5.0", | |
| @@ -339,6 +410,7 @@ | |
| "version": "3.1.2", | |
| "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", | |
| "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "engines": { | |
| "node": ">=6.0.0" | |
| @@ -348,12 +420,14 @@ | |
| "version": "1.5.5", | |
| "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", | |
| "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", | |
| + "dev": true, | |
| "license": "MIT" | |
| }, | |
| "node_modules/@jridgewell/trace-mapping": { | |
| "version": "0.3.31", | |
| "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", | |
| "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "dependencies": { | |
| "@jridgewell/resolve-uri": "^3.1.0", | |
| @@ -537,6 +611,7 @@ | |
| "version": "2.1.5", | |
| "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", | |
| "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "dependencies": { | |
| "@nodelib/fs.stat": "2.0.5", | |
| @@ -550,6 +625,7 @@ | |
| "version": "2.0.5", | |
| "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", | |
| "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "engines": { | |
| "node": ">= 8" | |
| @@ -559,6 +635,7 @@ | |
| "version": "1.2.8", | |
| "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", | |
| "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "dependencies": { | |
| "@nodelib/fs.scandir": "2.1.5", | |
| @@ -578,6 +655,276 @@ | |
| "node": ">=12.4.0" | |
| } | |
| }, | |
| + "node_modules/@opentelemetry/api": { | |
| + "version": "1.9.0", | |
| + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", | |
| + "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", | |
| + "license": "Apache-2.0", | |
| + "engines": { | |
| + "node": ">=8.0.0" | |
| + } | |
| + }, | |
| + "node_modules/@opentelemetry/api-logs": { | |
| + "version": "0.208.0", | |
| + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.208.0.tgz", | |
| + "integrity": "sha512-CjruKY9V6NMssL/T1kAFgzosF1v9o6oeN+aX5JB/C/xPNtmgIJqcXHG7fA82Ou1zCpWGl4lROQUKwUNE1pMCyg==", | |
| + "license": "Apache-2.0", | |
| + "dependencies": { | |
| + "@opentelemetry/api": "^1.3.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">=8.0.0" | |
| + } | |
| + }, | |
| + "node_modules/@opentelemetry/core": { | |
| + "version": "2.2.0", | |
| + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.2.0.tgz", | |
| + "integrity": "sha512-FuabnnUm8LflnieVxs6eP7Z383hgQU4W1e3KJS6aOG3RxWxcHyBxH8fDMHNgu/gFx/M2jvTOW/4/PHhLz6bjWw==", | |
| + "license": "Apache-2.0", | |
| + "dependencies": { | |
| + "@opentelemetry/semantic-conventions": "^1.29.0" | |
| + }, | |
| + "engines": { | |
| + "node": "^18.19.0 || >=20.6.0" | |
| + }, | |
| + "peerDependencies": { | |
| + "@opentelemetry/api": ">=1.0.0 <1.10.0" | |
| + } | |
| + }, | |
| + "node_modules/@opentelemetry/exporter-logs-otlp-http": { | |
| + "version": "0.208.0", | |
| + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-logs-otlp-http/-/exporter-logs-otlp-http-0.208.0.tgz", | |
| + "integrity": "sha512-jOv40Bs9jy9bZVLo/i8FwUiuCvbjWDI+ZW13wimJm4LjnlwJxGgB+N/VWOZUTpM+ah/awXeQqKdNlpLf2EjvYg==", | |
| + "license": "Apache-2.0", | |
| + "dependencies": { | |
| + "@opentelemetry/api-logs": "0.208.0", | |
| + "@opentelemetry/core": "2.2.0", | |
| + "@opentelemetry/otlp-exporter-base": "0.208.0", | |
| + "@opentelemetry/otlp-transformer": "0.208.0", | |
| + "@opentelemetry/sdk-logs": "0.208.0" | |
| + }, | |
| + "engines": { | |
| + "node": "^18.19.0 || >=20.6.0" | |
| + }, | |
| + "peerDependencies": { | |
| + "@opentelemetry/api": "^1.3.0" | |
| + } | |
| + }, | |
| + "node_modules/@opentelemetry/otlp-exporter-base": { | |
| + "version": "0.208.0", | |
| + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.208.0.tgz", | |
| + "integrity": "sha512-gMd39gIfVb2OgxldxUtOwGJYSH8P1kVFFlJLuut32L6KgUC4gl1dMhn+YC2mGn0bDOiQYSk/uHOdSjuKp58vvA==", | |
| + "license": "Apache-2.0", | |
| + "dependencies": { | |
| + "@opentelemetry/core": "2.2.0", | |
| + "@opentelemetry/otlp-transformer": "0.208.0" | |
| + }, | |
| + "engines": { | |
| + "node": "^18.19.0 || >=20.6.0" | |
| + }, | |
| + "peerDependencies": { | |
| + "@opentelemetry/api": "^1.3.0" | |
| + } | |
| + }, | |
| + "node_modules/@opentelemetry/otlp-transformer": { | |
| + "version": "0.208.0", | |
| + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.208.0.tgz", | |
| + "integrity": "sha512-DCFPY8C6lAQHUNkzcNT9R+qYExvsk6C5Bto2pbNxgicpcSWbe2WHShLxkOxIdNcBiYPdVHv/e7vH7K6TI+C+fQ==", | |
| + "license": "Apache-2.0", | |
| + "dependencies": { | |
| + "@opentelemetry/api-logs": "0.208.0", | |
| + "@opentelemetry/core": "2.2.0", | |
| + "@opentelemetry/resources": "2.2.0", | |
| + "@opentelemetry/sdk-logs": "0.208.0", | |
| + "@opentelemetry/sdk-metrics": "2.2.0", | |
| + "@opentelemetry/sdk-trace-base": "2.2.0", | |
| + "protobufjs": "^7.3.0" | |
| + }, | |
| + "engines": { | |
| + "node": "^18.19.0 || >=20.6.0" | |
| + }, | |
| + "peerDependencies": { | |
| + "@opentelemetry/api": "^1.3.0" | |
| + } | |
| + }, | |
| + "node_modules/@opentelemetry/otlp-transformer/node_modules/@opentelemetry/resources": { | |
| + "version": "2.2.0", | |
| + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.2.0.tgz", | |
| + "integrity": "sha512-1pNQf/JazQTMA0BiO5NINUzH0cbLbbl7mntLa4aJNmCCXSj0q03T5ZXXL0zw4G55TjdL9Tz32cznGClf+8zr5A==", | |
| + "license": "Apache-2.0", | |
| + "dependencies": { | |
| + "@opentelemetry/core": "2.2.0", | |
| + "@opentelemetry/semantic-conventions": "^1.29.0" | |
| + }, | |
| + "engines": { | |
| + "node": "^18.19.0 || >=20.6.0" | |
| + }, | |
| + "peerDependencies": { | |
| + "@opentelemetry/api": ">=1.3.0 <1.10.0" | |
| + } | |
| + }, | |
| + "node_modules/@opentelemetry/otlp-transformer/node_modules/protobufjs": { | |
| + "version": "7.5.4", | |
| + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.4.tgz", | |
| + "integrity": "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==", | |
| + "hasInstallScript": true, | |
| + "license": "BSD-3-Clause", | |
| + "dependencies": { | |
| + "@protobufjs/aspromise": "^1.1.2", | |
| + "@protobufjs/base64": "^1.1.2", | |
| + "@protobufjs/codegen": "^2.0.4", | |
| + "@protobufjs/eventemitter": "^1.1.0", | |
| + "@protobufjs/fetch": "^1.1.0", | |
| + "@protobufjs/float": "^1.0.2", | |
| + "@protobufjs/inquire": "^1.1.0", | |
| + "@protobufjs/path": "^1.1.2", | |
| + "@protobufjs/pool": "^1.1.0", | |
| + "@protobufjs/utf8": "^1.1.0", | |
| + "@types/node": ">=13.7.0", | |
| + "long": "^5.0.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">=12.0.0" | |
| + } | |
| + }, | |
| + "node_modules/@opentelemetry/resources": { | |
| + "version": "2.5.0", | |
| + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.5.0.tgz", | |
| + "integrity": "sha512-F8W52ApePshpoSrfsSk1H2yJn9aKjCrbpQF1M9Qii0GHzbfVeFUB+rc3X4aggyZD8x9Gu3Slua+s6krmq6Dt8g==", | |
| + "license": "Apache-2.0", | |
| + "dependencies": { | |
| + "@opentelemetry/core": "2.5.0", | |
| + "@opentelemetry/semantic-conventions": "^1.29.0" | |
| + }, | |
| + "engines": { | |
| + "node": "^18.19.0 || >=20.6.0" | |
| + }, | |
| + "peerDependencies": { | |
| + "@opentelemetry/api": ">=1.3.0 <1.10.0" | |
| + } | |
| + }, | |
| + "node_modules/@opentelemetry/resources/node_modules/@opentelemetry/core": { | |
| + "version": "2.5.0", | |
| + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.5.0.tgz", | |
| + "integrity": "sha512-ka4H8OM6+DlUhSAZpONu0cPBtPPTQKxbxVzC4CzVx5+K4JnroJVBtDzLAMx4/3CDTJXRvVFhpFjtl4SaiTNoyQ==", | |
| + "license": "Apache-2.0", | |
| + "dependencies": { | |
| + "@opentelemetry/semantic-conventions": "^1.29.0" | |
| + }, | |
| + "engines": { | |
| + "node": "^18.19.0 || >=20.6.0" | |
| + }, | |
| + "peerDependencies": { | |
| + "@opentelemetry/api": ">=1.0.0 <1.10.0" | |
| + } | |
| + }, | |
| + "node_modules/@opentelemetry/sdk-logs": { | |
| + "version": "0.208.0", | |
| + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.208.0.tgz", | |
| + "integrity": "sha512-QlAyL1jRpOeaqx7/leG1vJMp84g0xKP6gJmfELBpnI4O/9xPX+Hu5m1POk9Kl+veNkyth5t19hRlN6tNY1sjbA==", | |
| + "license": "Apache-2.0", | |
| + "dependencies": { | |
| + "@opentelemetry/api-logs": "0.208.0", | |
| + "@opentelemetry/core": "2.2.0", | |
| + "@opentelemetry/resources": "2.2.0" | |
| + }, | |
| + "engines": { | |
| + "node": "^18.19.0 || >=20.6.0" | |
| + }, | |
| + "peerDependencies": { | |
| + "@opentelemetry/api": ">=1.4.0 <1.10.0" | |
| + } | |
| + }, | |
| + "node_modules/@opentelemetry/sdk-logs/node_modules/@opentelemetry/resources": { | |
| + "version": "2.2.0", | |
| + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.2.0.tgz", | |
| + "integrity": "sha512-1pNQf/JazQTMA0BiO5NINUzH0cbLbbl7mntLa4aJNmCCXSj0q03T5ZXXL0zw4G55TjdL9Tz32cznGClf+8zr5A==", | |
| + "license": "Apache-2.0", | |
| + "dependencies": { | |
| + "@opentelemetry/core": "2.2.0", | |
| + "@opentelemetry/semantic-conventions": "^1.29.0" | |
| + }, | |
| + "engines": { | |
| + "node": "^18.19.0 || >=20.6.0" | |
| + }, | |
| + "peerDependencies": { | |
| + "@opentelemetry/api": ">=1.3.0 <1.10.0" | |
| + } | |
| + }, | |
| + "node_modules/@opentelemetry/sdk-metrics": { | |
| + "version": "2.2.0", | |
| + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.2.0.tgz", | |
| + "integrity": "sha512-G5KYP6+VJMZzpGipQw7Giif48h6SGQ2PFKEYCybeXJsOCB4fp8azqMAAzE5lnnHK3ZVwYQrgmFbsUJO/zOnwGw==", | |
| + "license": "Apache-2.0", | |
| + "dependencies": { | |
| + "@opentelemetry/core": "2.2.0", | |
| + "@opentelemetry/resources": "2.2.0" | |
| + }, | |
| + "engines": { | |
| + "node": "^18.19.0 || >=20.6.0" | |
| + }, | |
| + "peerDependencies": { | |
| + "@opentelemetry/api": ">=1.9.0 <1.10.0" | |
| + } | |
| + }, | |
| + "node_modules/@opentelemetry/sdk-metrics/node_modules/@opentelemetry/resources": { | |
| + "version": "2.2.0", | |
| + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.2.0.tgz", | |
| + "integrity": "sha512-1pNQf/JazQTMA0BiO5NINUzH0cbLbbl7mntLa4aJNmCCXSj0q03T5ZXXL0zw4G55TjdL9Tz32cznGClf+8zr5A==", | |
| + "license": "Apache-2.0", | |
| + "dependencies": { | |
| + "@opentelemetry/core": "2.2.0", | |
| + "@opentelemetry/semantic-conventions": "^1.29.0" | |
| + }, | |
| + "engines": { | |
| + "node": "^18.19.0 || >=20.6.0" | |
| + }, | |
| + "peerDependencies": { | |
| + "@opentelemetry/api": ">=1.3.0 <1.10.0" | |
| + } | |
| + }, | |
| + "node_modules/@opentelemetry/sdk-trace-base": { | |
| + "version": "2.2.0", | |
| + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.2.0.tgz", | |
| + "integrity": "sha512-xWQgL0Bmctsalg6PaXExmzdedSp3gyKV8mQBwK/j9VGdCDu2fmXIb2gAehBKbkXCpJ4HPkgv3QfoJWRT4dHWbw==", | |
| + "license": "Apache-2.0", | |
| + "dependencies": { | |
| + "@opentelemetry/core": "2.2.0", | |
| + "@opentelemetry/resources": "2.2.0", | |
| + "@opentelemetry/semantic-conventions": "^1.29.0" | |
| + }, | |
| + "engines": { | |
| + "node": "^18.19.0 || >=20.6.0" | |
| + }, | |
| + "peerDependencies": { | |
| + "@opentelemetry/api": ">=1.3.0 <1.10.0" | |
| + } | |
| + }, | |
| + "node_modules/@opentelemetry/sdk-trace-base/node_modules/@opentelemetry/resources": { | |
| + "version": "2.2.0", | |
| + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.2.0.tgz", | |
| + "integrity": "sha512-1pNQf/JazQTMA0BiO5NINUzH0cbLbbl7mntLa4aJNmCCXSj0q03T5ZXXL0zw4G55TjdL9Tz32cznGClf+8zr5A==", | |
| + "license": "Apache-2.0", | |
| + "dependencies": { | |
| + "@opentelemetry/core": "2.2.0", | |
| + "@opentelemetry/semantic-conventions": "^1.29.0" | |
| + }, | |
| + "engines": { | |
| + "node": "^18.19.0 || >=20.6.0" | |
| + }, | |
| + "peerDependencies": { | |
| + "@opentelemetry/api": ">=1.3.0 <1.10.0" | |
| + } | |
| + }, | |
| + "node_modules/@opentelemetry/semantic-conventions": { | |
| + "version": "1.39.0", | |
| + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.39.0.tgz", | |
| + "integrity": "sha512-R5R9tb2AXs2IRLNKLBJDynhkfmx7mX0vi8NkhZb3gUkPWHn6HXk5J8iQ/dql0U3ApfWym4kXXmBDRGO+oeOfjg==", | |
| + "license": "Apache-2.0", | |
| + "engines": { | |
| + "node": ">=14" | |
| + } | |
| + }, | |
| "node_modules/@pkgjs/parseargs": { | |
| "version": "0.11.0", | |
| "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", | |
| @@ -589,6 +936,21 @@ | |
| "node": ">=14" | |
| } | |
| }, | |
| + "node_modules/@posthog/core": { | |
| + "version": "1.20.0", | |
| + "resolved": "https://registry.npmjs.org/@posthog/core/-/core-1.20.0.tgz", | |
| + "integrity": "sha512-e/F20we0t6bPMuDOVOe53f908s23vuKEpFKNXmZcx4bSYsPkjRN49akIIHU621HBJdcsFx537vhJYKZxu8uS9w==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "cross-spawn": "^7.0.6" | |
| + } | |
| + }, | |
| + "node_modules/@posthog/types": { | |
| + "version": "1.341.0", | |
| + "resolved": "https://registry.npmjs.org/@posthog/types/-/types-1.341.0.tgz", | |
| + "integrity": "sha512-lIQzaPzfxdhonj2nXI2Nh3z45wyfb/e48cyy/+GawNDeRnkzqyhifpyAimVafBJIP7RR1lQqEnM8Xk55H7SRgQ==", | |
| + "license": "MIT" | |
| + }, | |
| "node_modules/@protobufjs/aspromise": { | |
| "version": "1.1.2", | |
| "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", | |
| @@ -1617,6 +1979,12 @@ | |
| "tslib": "^2.4.0" | |
| } | |
| }, | |
| + "node_modules/@types/json-schema": { | |
| + "version": "7.0.15", | |
| + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", | |
| + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", | |
| + "license": "MIT" | |
| + }, | |
| "node_modules/@types/json5": { | |
| "version": "0.0.29", | |
| "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", | |
| @@ -1633,18 +2001,28 @@ | |
| "undici-types": "~6.21.0" | |
| } | |
| }, | |
| + "node_modules/@types/node-fetch": { | |
| + "version": "2.6.13", | |
| + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.13.tgz", | |
| + "integrity": "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "@types/node": "*", | |
| + "form-data": "^4.0.4" | |
| + } | |
| + }, | |
| "node_modules/@types/prop-types": { | |
| "version": "15.7.15", | |
| "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", | |
| "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", | |
| - "devOptional": true, | |
| + "dev": true, | |
| "license": "MIT" | |
| }, | |
| "node_modules/@types/react": { | |
| "version": "18.3.27", | |
| "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.27.tgz", | |
| "integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==", | |
| - "devOptional": true, | |
| + "dev": true, | |
| "license": "MIT", | |
| "dependencies": { | |
| "@types/prop-types": "*", | |
| @@ -1655,7 +2033,7 @@ | |
| "version": "18.3.7", | |
| "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", | |
| "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", | |
| - "devOptional": true, | |
| + "dev": true, | |
| "license": "MIT", | |
| "peerDependencies": { | |
| "@types/react": "^18.0.0" | |
| @@ -2224,6 +2602,18 @@ | |
| "node": ">=18.0.0" | |
| } | |
| }, | |
| + "node_modules/abort-controller": { | |
| + "version": "3.0.0", | |
| + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", | |
| + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "event-target-shim": "^5.0.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">=6.5" | |
| + } | |
| + }, | |
| "node_modules/acorn": { | |
| "version": "8.15.0", | |
| "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", | |
| @@ -2247,6 +2637,18 @@ | |
| "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" | |
| } | |
| }, | |
| + "node_modules/agentkeepalive": { | |
| + "version": "4.6.0", | |
| + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", | |
| + "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "humanize-ms": "^1.2.1" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 8.0.0" | |
| + } | |
| + }, | |
| "node_modules/ajv": { | |
| "version": "6.12.6", | |
| "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", | |
| @@ -2278,7 +2680,6 @@ | |
| "version": "4.3.0", | |
| "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", | |
| "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", | |
| - "dev": true, | |
| "license": "MIT", | |
| "dependencies": { | |
| "color-convert": "^2.0.1" | |
| @@ -2294,12 +2695,14 @@ | |
| "version": "1.3.0", | |
| "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", | |
| "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", | |
| + "dev": true, | |
| "license": "MIT" | |
| }, | |
| "node_modules/anymatch": { | |
| "version": "3.1.3", | |
| "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", | |
| "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", | |
| + "dev": true, | |
| "license": "ISC", | |
| "dependencies": { | |
| "normalize-path": "^3.0.0", | |
| @@ -2313,6 +2716,7 @@ | |
| "version": "5.0.2", | |
| "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", | |
| "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", | |
| + "dev": true, | |
| "license": "MIT" | |
| }, | |
| "node_modules/argparse": { | |
| @@ -2521,6 +2925,12 @@ | |
| "node": ">= 0.4" | |
| } | |
| }, | |
| + "node_modules/asynckit": { | |
| + "version": "0.4.0", | |
| + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", | |
| + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", | |
| + "license": "MIT" | |
| + }, | |
| "node_modules/autolinker": { | |
| "version": "4.1.5", | |
| "resolved": "https://registry.npmjs.org/autolinker/-/autolinker-4.1.5.tgz", | |
| @@ -2627,6 +3037,7 @@ | |
| "version": "2.3.0", | |
| "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", | |
| "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "engines": { | |
| "node": ">=8" | |
| @@ -2656,6 +3067,7 @@ | |
| "version": "3.0.3", | |
| "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", | |
| "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "dependencies": { | |
| "fill-range": "^7.1.1" | |
| @@ -2732,7 +3144,6 @@ | |
| "version": "1.0.2", | |
| "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", | |
| "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", | |
| - "dev": true, | |
| "license": "MIT", | |
| "dependencies": { | |
| "es-errors": "^1.3.0", | |
| @@ -2773,6 +3184,7 @@ | |
| "version": "2.0.1", | |
| "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", | |
| "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "engines": { | |
| "node": ">= 6" | |
| @@ -2820,7 +3232,6 @@ | |
| "version": "4.1.2", | |
| "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", | |
| "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", | |
| - "dev": true, | |
| "license": "MIT", | |
| "dependencies": { | |
| "ansi-styles": "^4.1.0", | |
| @@ -2837,6 +3248,7 @@ | |
| "version": "3.6.0", | |
| "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", | |
| "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "dependencies": { | |
| "anymatch": "~3.1.2", | |
| @@ -2861,6 +3273,7 @@ | |
| "version": "5.1.2", | |
| "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", | |
| "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", | |
| + "dev": true, | |
| "license": "ISC", | |
| "dependencies": { | |
| "is-glob": "^4.0.1" | |
| @@ -2900,7 +3313,6 @@ | |
| "version": "2.0.1", | |
| "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", | |
| "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", | |
| - "dev": true, | |
| "license": "MIT", | |
| "dependencies": { | |
| "color-name": "~1.1.4" | |
| @@ -2913,13 +3325,25 @@ | |
| "version": "1.1.4", | |
| "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", | |
| "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", | |
| - "dev": true, | |
| "license": "MIT" | |
| }, | |
| + "node_modules/combined-stream": { | |
| + "version": "1.0.8", | |
| + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", | |
| + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "delayed-stream": "~1.0.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.8" | |
| + } | |
| + }, | |
| "node_modules/commander": { | |
| "version": "4.1.1", | |
| "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", | |
| "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "engines": { | |
| "node": ">= 6" | |
| @@ -2932,11 +3356,21 @@ | |
| "dev": true, | |
| "license": "MIT" | |
| }, | |
| + "node_modules/core-js": { | |
| + "version": "3.48.0", | |
| + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.48.0.tgz", | |
| + "integrity": "sha512-zpEHTy1fjTMZCKLHUZoVeylt9XrzaIN2rbPXEt0k+q7JE5CkCZdo6bNq55bn24a69CH7ErAVLKijxJja4fw+UQ==", | |
| + "hasInstallScript": true, | |
| + "license": "MIT", | |
| + "funding": { | |
| + "type": "opencollective", | |
| + "url": "https://opencollective.com/core-js" | |
| + } | |
| + }, | |
| "node_modules/cross-spawn": { | |
| "version": "7.0.6", | |
| "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", | |
| "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", | |
| - "dev": true, | |
| "license": "MIT", | |
| "dependencies": { | |
| "path-key": "^3.1.0", | |
| @@ -2951,6 +3385,7 @@ | |
| "version": "3.0.0", | |
| "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", | |
| "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "bin": { | |
| "cssesc": "bin/cssesc" | |
| @@ -2963,7 +3398,7 @@ | |
| "version": "3.2.3", | |
| "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", | |
| "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", | |
| - "devOptional": true, | |
| + "dev": true, | |
| "license": "MIT" | |
| }, | |
| "node_modules/damerau-levenshtein": { | |
| @@ -3088,6 +3523,15 @@ | |
| "url": "https://github.com/sponsors/ljharb" | |
| } | |
| }, | |
| + "node_modules/delayed-stream": { | |
| + "version": "1.0.0", | |
| + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", | |
| + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=0.4.0" | |
| + } | |
| + }, | |
| "node_modules/detect-node-es": { | |
| "version": "1.1.0", | |
| "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", | |
| @@ -3098,12 +3542,14 @@ | |
| "version": "1.2.2", | |
| "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", | |
| "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", | |
| + "dev": true, | |
| "license": "Apache-2.0" | |
| }, | |
| "node_modules/dlv": { | |
| "version": "1.1.3", | |
| "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", | |
| "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", | |
| + "dev": true, | |
| "license": "MIT" | |
| }, | |
| "node_modules/doctrine": { | |
| @@ -3138,7 +3584,6 @@ | |
| "version": "1.0.1", | |
| "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", | |
| "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", | |
| - "dev": true, | |
| "license": "MIT", | |
| "dependencies": { | |
| "call-bind-apply-helpers": "^1.0.1", | |
| @@ -3249,7 +3694,6 @@ | |
| "version": "1.0.1", | |
| "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", | |
| "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", | |
| - "dev": true, | |
| "license": "MIT", | |
| "engines": { | |
| "node": ">= 0.4" | |
| @@ -3259,7 +3703,6 @@ | |
| "version": "1.3.0", | |
| "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", | |
| "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", | |
| - "dev": true, | |
| "license": "MIT", | |
| "engines": { | |
| "node": ">= 0.4" | |
| @@ -3297,7 +3740,6 @@ | |
| "version": "1.1.1", | |
| "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", | |
| "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", | |
| - "dev": true, | |
| "license": "MIT", | |
| "dependencies": { | |
| "es-errors": "^1.3.0" | |
| @@ -3310,7 +3752,6 @@ | |
| "version": "2.1.0", | |
| "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", | |
| "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", | |
| - "dev": true, | |
| "license": "MIT", | |
| "dependencies": { | |
| "es-errors": "^1.3.0", | |
| @@ -3824,6 +4265,15 @@ | |
| "node": ">=0.10.0" | |
| } | |
| }, | |
| + "node_modules/event-target-shim": { | |
| + "version": "5.0.1", | |
| + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", | |
| + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=6" | |
| + } | |
| + }, | |
| "node_modules/fast-deep-equal": { | |
| "version": "3.1.3", | |
| "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", | |
| @@ -3835,6 +4285,7 @@ | |
| "version": "3.3.3", | |
| "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", | |
| "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "dependencies": { | |
| "@nodelib/fs.stat": "^2.0.2", | |
| @@ -3851,6 +4302,7 @@ | |
| "version": "5.1.2", | |
| "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", | |
| "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", | |
| + "dev": true, | |
| "license": "ISC", | |
| "dependencies": { | |
| "is-glob": "^4.0.1" | |
| @@ -3877,11 +4329,18 @@ | |
| "version": "1.20.1", | |
| "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", | |
| "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", | |
| + "dev": true, | |
| "license": "ISC", | |
| "dependencies": { | |
| "reusify": "^1.0.4" | |
| } | |
| }, | |
| + "node_modules/fflate": { | |
| + "version": "0.4.8", | |
| + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz", | |
| + "integrity": "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==", | |
| + "license": "MIT" | |
| + }, | |
| "node_modules/file-entry-cache": { | |
| "version": "6.0.1", | |
| "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", | |
| @@ -3899,6 +4358,7 @@ | |
| "version": "7.1.1", | |
| "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", | |
| "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "dependencies": { | |
| "to-regex-range": "^5.0.1" | |
| @@ -3979,6 +4439,41 @@ | |
| "url": "https://github.com/sponsors/isaacs" | |
| } | |
| }, | |
| + "node_modules/form-data": { | |
| + "version": "4.0.5", | |
| + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", | |
| + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "asynckit": "^0.4.0", | |
| + "combined-stream": "^1.0.8", | |
| + "es-set-tostringtag": "^2.1.0", | |
| + "hasown": "^2.0.2", | |
| + "mime-types": "^2.1.12" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 6" | |
| + } | |
| + }, | |
| + "node_modules/form-data-encoder": { | |
| + "version": "1.7.2", | |
| + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", | |
| + "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==", | |
| + "license": "MIT" | |
| + }, | |
| + "node_modules/formdata-node": { | |
| + "version": "4.4.1", | |
| + "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", | |
| + "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "node-domexception": "1.0.0", | |
| + "web-streams-polyfill": "4.0.0-beta.3" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 12.20" | |
| + } | |
| + }, | |
| "node_modules/fraction.js": { | |
| "version": "5.3.4", | |
| "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", | |
| @@ -4004,6 +4499,7 @@ | |
| "version": "2.3.3", | |
| "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", | |
| "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", | |
| + "dev": true, | |
| "hasInstallScript": true, | |
| "license": "MIT", | |
| "optional": true, | |
| @@ -4068,7 +4564,6 @@ | |
| "version": "1.3.0", | |
| "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", | |
| "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", | |
| - "dev": true, | |
| "license": "MIT", | |
| "dependencies": { | |
| "call-bind-apply-helpers": "^1.0.2", | |
| @@ -4102,7 +4597,6 @@ | |
| "version": "1.0.1", | |
| "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", | |
| "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", | |
| - "dev": true, | |
| "license": "MIT", | |
| "dependencies": { | |
| "dunder-proto": "^1.0.1", | |
| @@ -4170,6 +4664,7 @@ | |
| "version": "6.0.2", | |
| "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", | |
| "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", | |
| + "dev": true, | |
| "license": "ISC", | |
| "dependencies": { | |
| "is-glob": "^4.0.3" | |
| @@ -4241,7 +4736,6 @@ | |
| "version": "1.2.0", | |
| "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", | |
| "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", | |
| - "dev": true, | |
| "license": "MIT", | |
| "engines": { | |
| "node": ">= 0.4" | |
| @@ -4286,7 +4780,6 @@ | |
| "version": "4.0.0", | |
| "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", | |
| "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", | |
| - "dev": true, | |
| "license": "MIT", | |
| "engines": { | |
| "node": ">=8" | |
| @@ -4325,7 +4818,6 @@ | |
| "version": "1.1.0", | |
| "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", | |
| "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", | |
| - "dev": true, | |
| "license": "MIT", | |
| "engines": { | |
| "node": ">= 0.4" | |
| @@ -4338,7 +4830,6 @@ | |
| "version": "1.0.2", | |
| "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", | |
| "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", | |
| - "dev": true, | |
| "license": "MIT", | |
| "dependencies": { | |
| "has-symbols": "^1.0.3" | |
| @@ -4362,6 +4853,15 @@ | |
| "node": ">= 0.4" | |
| } | |
| }, | |
| + "node_modules/humanize-ms": { | |
| + "version": "1.2.1", | |
| + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", | |
| + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "ms": "^2.0.0" | |
| + } | |
| + }, | |
| "node_modules/ignore": { | |
| "version": "5.3.2", | |
| "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", | |
| @@ -4491,6 +4991,7 @@ | |
| "version": "2.1.0", | |
| "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", | |
| "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "dependencies": { | |
| "binary-extensions": "^2.0.0" | |
| @@ -4543,6 +5044,7 @@ | |
| "version": "2.16.1", | |
| "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", | |
| "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "dependencies": { | |
| "hasown": "^2.0.2" | |
| @@ -4593,6 +5095,7 @@ | |
| "version": "2.1.1", | |
| "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", | |
| "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "engines": { | |
| "node": ">=0.10.0" | |
| @@ -4648,6 +5151,7 @@ | |
| "version": "4.0.3", | |
| "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", | |
| "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "dependencies": { | |
| "is-extglob": "^2.1.1" | |
| @@ -4686,6 +5190,7 @@ | |
| "version": "7.0.0", | |
| "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", | |
| "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "engines": { | |
| "node": ">=0.12.0" | |
| @@ -4874,7 +5379,6 @@ | |
| "version": "2.0.0", | |
| "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", | |
| "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", | |
| - "dev": true, | |
| "license": "ISC" | |
| }, | |
| "node_modules/iterator.prototype": { | |
| @@ -4918,6 +5422,7 @@ | |
| "version": "1.21.7", | |
| "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", | |
| "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "bin": { | |
| "jiti": "bin/jiti.js" | |
| @@ -5067,6 +5572,7 @@ | |
| "version": "3.1.3", | |
| "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", | |
| "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "engines": { | |
| "node": ">=14" | |
| @@ -5079,6 +5585,7 @@ | |
| "version": "1.2.4", | |
| "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", | |
| "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", | |
| + "dev": true, | |
| "license": "MIT" | |
| }, | |
| "node_modules/locate-path": { | |
| @@ -5142,7 +5649,6 @@ | |
| "version": "1.1.0", | |
| "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", | |
| "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", | |
| - "dev": true, | |
| "license": "MIT", | |
| "engines": { | |
| "node": ">= 0.4" | |
| @@ -5152,6 +5658,7 @@ | |
| "version": "1.4.1", | |
| "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", | |
| "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "engines": { | |
| "node": ">= 8" | |
| @@ -5173,6 +5680,7 @@ | |
| "version": "4.0.8", | |
| "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", | |
| "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "dependencies": { | |
| "braces": "^3.0.3", | |
| @@ -5182,6 +5690,27 @@ | |
| "node": ">=8.6" | |
| } | |
| }, | |
| + "node_modules/mime-db": { | |
| + "version": "1.52.0", | |
| + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", | |
| + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">= 0.6" | |
| + } | |
| + }, | |
| + "node_modules/mime-types": { | |
| + "version": "2.1.35", | |
| + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", | |
| + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "mime-db": "1.52.0" | |
| + }, | |
| + "engines": { | |
| + "node": ">= 0.6" | |
| + } | |
| + }, | |
| "node_modules/minimatch": { | |
| "version": "3.1.2", | |
| "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", | |
| @@ -5219,13 +5748,13 @@ | |
| "version": "2.1.3", | |
| "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", | |
| "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", | |
| - "dev": true, | |
| "license": "MIT" | |
| }, | |
| "node_modules/mz": { | |
| "version": "2.7.0", | |
| "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", | |
| "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "dependencies": { | |
| "any-promise": "^1.0.0", | |
| @@ -5363,6 +5892,46 @@ | |
| "node": "^10 || ^12 || >=14" | |
| } | |
| }, | |
| + "node_modules/node-domexception": { | |
| + "version": "1.0.0", | |
| + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", | |
| + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", | |
| + "deprecated": "Use your platform's native DOMException instead", | |
| + "funding": [ | |
| + { | |
| + "type": "github", | |
| + "url": "https://github.com/sponsors/jimmywarting" | |
| + }, | |
| + { | |
| + "type": "github", | |
| + "url": "https://paypal.me/jimmywarting" | |
| + } | |
| + ], | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">=10.5.0" | |
| + } | |
| + }, | |
| + "node_modules/node-fetch": { | |
| + "version": "2.7.0", | |
| + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", | |
| + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "whatwg-url": "^5.0.0" | |
| + }, | |
| + "engines": { | |
| + "node": "4.x || >=6.0.0" | |
| + }, | |
| + "peerDependencies": { | |
| + "encoding": "^0.1.0" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "encoding": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| "node_modules/node-releases": { | |
| "version": "2.0.27", | |
| "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", | |
| @@ -5374,6 +5943,7 @@ | |
| "version": "3.0.0", | |
| "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", | |
| "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "engines": { | |
| "node": ">=0.10.0" | |
| @@ -5389,6 +5959,7 @@ | |
| "version": "4.1.1", | |
| "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", | |
| "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "engines": { | |
| "node": ">=0.10.0" | |
| @@ -5398,6 +5969,7 @@ | |
| "version": "3.0.0", | |
| "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", | |
| "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "engines": { | |
| "node": ">= 6" | |
| @@ -5526,6 +6098,51 @@ | |
| "wrappy": "1" | |
| } | |
| }, | |
| + "node_modules/openai": { | |
| + "version": "4.104.0", | |
| + "resolved": "https://registry.npmjs.org/openai/-/openai-4.104.0.tgz", | |
| + "integrity": "sha512-p99EFNsA/yX6UhVO93f5kJsDRLAg+CTA2RBqdHK4RtK8u5IJw32Hyb2dTGKbnnFmnuoBv5r7Z2CURI9sGZpSuA==", | |
| + "license": "Apache-2.0", | |
| + "dependencies": { | |
| + "@types/node": "^18.11.18", | |
| + "@types/node-fetch": "^2.6.4", | |
| + "abort-controller": "^3.0.0", | |
| + "agentkeepalive": "^4.2.1", | |
| + "form-data-encoder": "1.7.2", | |
| + "formdata-node": "^4.3.2", | |
| + "node-fetch": "^2.6.7" | |
| + }, | |
| + "bin": { | |
| + "openai": "bin/cli" | |
| + }, | |
| + "peerDependencies": { | |
| + "ws": "^8.18.0", | |
| + "zod": "^3.23.8" | |
| + }, | |
| + "peerDependenciesMeta": { | |
| + "ws": { | |
| + "optional": true | |
| + }, | |
| + "zod": { | |
| + "optional": true | |
| + } | |
| + } | |
| + }, | |
| + "node_modules/openai/node_modules/@types/node": { | |
| + "version": "18.19.130", | |
| + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.130.tgz", | |
| + "integrity": "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "undici-types": "~5.26.4" | |
| + } | |
| + }, | |
| + "node_modules/openai/node_modules/undici-types": { | |
| + "version": "5.26.5", | |
| + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", | |
| + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", | |
| + "license": "MIT" | |
| + }, | |
| "node_modules/optionator": { | |
| "version": "0.9.4", | |
| "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", | |
| @@ -5637,7 +6254,6 @@ | |
| "version": "3.1.1", | |
| "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", | |
| "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", | |
| - "dev": true, | |
| "license": "MIT", | |
| "engines": { | |
| "node": ">=8" | |
| @@ -5647,6 +6263,7 @@ | |
| "version": "1.0.7", | |
| "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", | |
| "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", | |
| + "dev": true, | |
| "license": "MIT" | |
| }, | |
| "node_modules/path-scurry": { | |
| @@ -5676,6 +6293,7 @@ | |
| "version": "2.3.1", | |
| "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", | |
| "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "engines": { | |
| "node": ">=8.6" | |
| @@ -5688,6 +6306,7 @@ | |
| "version": "2.3.0", | |
| "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", | |
| "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "engines": { | |
| "node": ">=0.10.0" | |
| @@ -5697,6 +6316,7 @@ | |
| "version": "4.0.7", | |
| "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", | |
| "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "engines": { | |
| "node": ">= 6" | |
| @@ -5716,6 +6336,7 @@ | |
| "version": "8.5.6", | |
| "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", | |
| "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", | |
| + "dev": true, | |
| "funding": [ | |
| { | |
| "type": "opencollective", | |
| @@ -5744,6 +6365,7 @@ | |
| "version": "15.1.0", | |
| "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", | |
| "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "dependencies": { | |
| "postcss-value-parser": "^4.0.0", | |
| @@ -5761,6 +6383,7 @@ | |
| "version": "4.1.0", | |
| "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", | |
| "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", | |
| + "dev": true, | |
| "funding": [ | |
| { | |
| "type": "opencollective", | |
| @@ -5786,6 +6409,7 @@ | |
| "version": "6.0.1", | |
| "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", | |
| "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", | |
| + "dev": true, | |
| "funding": [ | |
| { | |
| "type": "opencollective", | |
| @@ -5828,6 +6452,7 @@ | |
| "version": "6.2.0", | |
| "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", | |
| "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", | |
| + "dev": true, | |
| "funding": [ | |
| { | |
| "type": "opencollective", | |
| @@ -5853,6 +6478,7 @@ | |
| "version": "6.1.2", | |
| "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", | |
| "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "dependencies": { | |
| "cssesc": "^3.0.0", | |
| @@ -5866,8 +6492,40 @@ | |
| "version": "4.2.0", | |
| "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", | |
| "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", | |
| + "dev": true, | |
| "license": "MIT" | |
| }, | |
| + "node_modules/posthog-js": { | |
| + "version": "1.341.0", | |
| + "resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.341.0.tgz", | |
| + "integrity": "sha512-sWa/84yi93ar/SJrG0do5QshCGWqUH39cNLrngN/GqC8kA5JLxyUEBmFaK65aAxrSKJ1muGP11ofIKDCwQn98Q==", | |
| + "license": "SEE LICENSE IN LICENSE", | |
| + "dependencies": { | |
| + "@opentelemetry/api": "^1.9.0", | |
| + "@opentelemetry/api-logs": "^0.208.0", | |
| + "@opentelemetry/exporter-logs-otlp-http": "^0.208.0", | |
| + "@opentelemetry/resources": "^2.2.0", | |
| + "@opentelemetry/sdk-logs": "^0.208.0", | |
| + "@posthog/core": "1.20.0", | |
| + "@posthog/types": "1.341.0", | |
| + "core-js": "^3.38.1", | |
| + "dompurify": "^3.3.1", | |
| + "fflate": "^0.4.8", | |
| + "preact": "^10.28.2", | |
| + "query-selector-shadow-dom": "^1.0.1", | |
| + "web-vitals": "^5.1.0" | |
| + } | |
| + }, | |
| + "node_modules/preact": { | |
| + "version": "10.28.3", | |
| + "resolved": "https://registry.npmjs.org/preact/-/preact-10.28.3.tgz", | |
| + "integrity": "sha512-tCmoRkPQLpBeWzpmbhryairGnhW9tKV6c6gr/w+RhoRoKEJwsjzipwp//1oCpGPOchvSLaAPlpcJi9MwMmoPyA==", | |
| + "license": "MIT", | |
| + "funding": { | |
| + "type": "opencollective", | |
| + "url": "https://opencollective.com/preact" | |
| + } | |
| + }, | |
| "node_modules/prelude-ls": { | |
| "version": "1.2.1", | |
| "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", | |
| @@ -5924,10 +6582,26 @@ | |
| "node": ">=6" | |
| } | |
| }, | |
| + "node_modules/pusher-js": { | |
| + "version": "8.4.0", | |
| + "resolved": "https://registry.npmjs.org/pusher-js/-/pusher-js-8.4.0.tgz", | |
| + "integrity": "sha512-wp3HqIIUc1GRyu1XrP6m2dgyE9MoCsXVsWNlohj0rjSkLf+a0jLvEyVubdg58oMk7bhjBWnFClgp8jfAa6Ak4Q==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "tweetnacl": "^1.0.3" | |
| + } | |
| + }, | |
| + "node_modules/query-selector-shadow-dom": { | |
| + "version": "1.0.1", | |
| + "resolved": "https://registry.npmjs.org/query-selector-shadow-dom/-/query-selector-shadow-dom-1.0.1.tgz", | |
| + "integrity": "sha512-lT5yCqEBgfoMYpf3F2xQRK7zEr1rhIIZuceDK6+xRkJQ4NMbHTwXqk4NkwDwQMNqXgG9r9fyHnzwNVs6zV5KRw==", | |
| + "license": "MIT" | |
| + }, | |
| "node_modules/queue-microtask": { | |
| "version": "1.2.3", | |
| "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", | |
| "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", | |
| + "dev": true, | |
| "funding": [ | |
| { | |
| "type": "github", | |
| @@ -6064,6 +6738,7 @@ | |
| "version": "1.0.0", | |
| "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", | |
| "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "dependencies": { | |
| "pify": "^2.3.0" | |
| @@ -6073,6 +6748,7 @@ | |
| "version": "3.6.0", | |
| "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", | |
| "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "dependencies": { | |
| "picomatch": "^2.2.1" | |
| @@ -6129,6 +6805,7 @@ | |
| "version": "1.22.11", | |
| "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", | |
| "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "dependencies": { | |
| "is-core-module": "^2.16.1", | |
| @@ -6169,6 +6846,7 @@ | |
| "version": "1.1.0", | |
| "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", | |
| "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "engines": { | |
| "iojs": ">=1.0.0", | |
| @@ -6218,6 +6896,7 @@ | |
| "version": "1.2.0", | |
| "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", | |
| "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", | |
| + "dev": true, | |
| "funding": [ | |
| { | |
| "type": "github", | |
| @@ -6305,7 +6984,6 @@ | |
| "version": "7.7.3", | |
| "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", | |
| "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", | |
| - "dev": true, | |
| "license": "ISC", | |
| "bin": { | |
| "semver": "bin/semver.js" | |
| @@ -6367,7 +7045,6 @@ | |
| "version": "2.0.0", | |
| "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", | |
| "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", | |
| - "dev": true, | |
| "license": "MIT", | |
| "dependencies": { | |
| "shebang-regex": "^3.0.0" | |
| @@ -6380,7 +7057,6 @@ | |
| "version": "3.0.0", | |
| "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", | |
| "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", | |
| - "dev": true, | |
| "license": "MIT", | |
| "engines": { | |
| "node": ">=8" | |
| @@ -6773,6 +7449,7 @@ | |
| "version": "3.35.1", | |
| "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", | |
| "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "dependencies": { | |
| "@jridgewell/gen-mapping": "^0.3.2", | |
| @@ -6795,7 +7472,6 @@ | |
| "version": "7.2.0", | |
| "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", | |
| "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", | |
| - "dev": true, | |
| "license": "MIT", | |
| "dependencies": { | |
| "has-flag": "^4.0.0" | |
| @@ -6808,6 +7484,7 @@ | |
| "version": "1.0.0", | |
| "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", | |
| "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "engines": { | |
| "node": ">= 0.4" | |
| @@ -6830,6 +7507,7 @@ | |
| "version": "3.4.19", | |
| "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", | |
| "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "dependencies": { | |
| "@alloc/quick-lru": "^5.2.0", | |
| @@ -6883,6 +7561,7 @@ | |
| "version": "3.3.1", | |
| "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", | |
| "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "dependencies": { | |
| "any-promise": "^1.0.0" | |
| @@ -6892,6 +7571,7 @@ | |
| "version": "1.6.0", | |
| "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", | |
| "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "dependencies": { | |
| "thenify": ">= 3.1.0 < 4" | |
| @@ -6904,6 +7584,7 @@ | |
| "version": "0.2.15", | |
| "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", | |
| "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "dependencies": { | |
| "fdir": "^6.5.0", | |
| @@ -6920,6 +7601,7 @@ | |
| "version": "6.5.0", | |
| "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", | |
| "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "engines": { | |
| "node": ">=12.0.0" | |
| @@ -6937,6 +7619,7 @@ | |
| "version": "4.0.3", | |
| "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", | |
| "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "engines": { | |
| "node": ">=12" | |
| @@ -6949,6 +7632,7 @@ | |
| "version": "5.0.1", | |
| "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", | |
| "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", | |
| + "dev": true, | |
| "license": "MIT", | |
| "dependencies": { | |
| "is-number": "^7.0.0" | |
| @@ -6977,6 +7661,12 @@ | |
| "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", | |
| "license": "MIT" | |
| }, | |
| + "node_modules/tr46": { | |
| + "version": "0.0.3", | |
| + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", | |
| + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", | |
| + "license": "MIT" | |
| + }, | |
| "node_modules/ts-api-utils": { | |
| "version": "2.4.0", | |
| "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", | |
| @@ -6994,6 +7684,7 @@ | |
| "version": "0.1.13", | |
| "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", | |
| "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", | |
| + "dev": true, | |
| "license": "Apache-2.0" | |
| }, | |
| "node_modules/tsconfig-paths": { | |
| @@ -7015,6 +7706,12 @@ | |
| "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", | |
| "license": "0BSD" | |
| }, | |
| + "node_modules/tweetnacl": { | |
| + "version": "1.0.3", | |
| + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", | |
| + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", | |
| + "license": "Unlicense" | |
| + }, | |
| "node_modules/type-check": { | |
| "version": "0.4.0", | |
| "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", | |
| @@ -7287,13 +7984,44 @@ | |
| "version": "1.0.2", | |
| "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", | |
| "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", | |
| + "dev": true, | |
| "license": "MIT" | |
| }, | |
| + "node_modules/web-streams-polyfill": { | |
| + "version": "4.0.0-beta.3", | |
| + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", | |
| + "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", | |
| + "license": "MIT", | |
| + "engines": { | |
| + "node": ">= 14" | |
| + } | |
| + }, | |
| + "node_modules/web-vitals": { | |
| + "version": "5.1.0", | |
| + "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-5.1.0.tgz", | |
| + "integrity": "sha512-ArI3kx5jI0atlTtmV0fWU3fjpLmq/nD3Zr1iFFlJLaqa5wLBkUSzINwBPySCX/8jRyjlmy1Volw1kz1g9XE4Jg==", | |
| + "license": "Apache-2.0" | |
| + }, | |
| + "node_modules/webidl-conversions": { | |
| + "version": "3.0.1", | |
| + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", | |
| + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", | |
| + "license": "BSD-2-Clause" | |
| + }, | |
| + "node_modules/whatwg-url": { | |
| + "version": "5.0.0", | |
| + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", | |
| + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", | |
| + "license": "MIT", | |
| + "dependencies": { | |
| + "tr46": "~0.0.3", | |
| + "webidl-conversions": "^3.0.0" | |
| + } | |
| + }, | |
| "node_modules/which": { | |
| "version": "2.0.2", | |
| "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", | |
| "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", | |
| - "dev": true, | |
| "license": "ISC", | |
| "dependencies": { | |
| "isexe": "^2.0.0" | |
| @@ -7534,6 +8262,15 @@ | |
| "url": "https://github.com/sponsors/colinhacks" | |
| } | |
| }, | |
| + "node_modules/zod-to-json-schema": { | |
| + "version": "3.25.1", | |
| + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz", | |
| + "integrity": "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==", | |
| + "license": "ISC", | |
| + "peerDependencies": { | |
| + "zod": "^3.25 || ^4" | |
| + } | |
| + }, | |
| "node_modules/zustand": { | |
| "version": "5.0.11", | |
| "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.11.tgz", | |
| diff --git a/package.json b/package.json | |
| index cf8ea60..0de7ac6 100644 | |
| --- a/package.json | |
| +++ b/package.json | |
| @@ -22,9 +22,13 @@ | |
| "cesium": "^1.122.0", | |
| "class-variance-authority": "^0.7.0", | |
| "clsx": "^2.1.1", | |
| + "@composio/core": "^0.6.3", | |
| + "@composio/openai": "^0.6.3", | |
| + "openai": "^4.77.0", | |
| "lucide-react": "^0.454.0", | |
| "next": "14.2.15", | |
| "next-themes": "^0.3.0", | |
| + "posthog-js": "^1.194.4", | |
| "react": "18.2.0", | |
| "react-dom": "18.2.0", | |
| "tailwind-merge": "^2.5.4", | |
| diff --git a/store/index.ts b/store/index.ts | |
| index 5fc8b11..3d95d19 100644 | |
| --- a/store/index.ts | |
| +++ b/store/index.ts | |
| @@ -2,3 +2,5 @@ export { useGlobeStore } from './useGlobeStore'; | |
| export { usePlacesStore } from './usePlacesStore'; | |
| export { useLayersStore } from './useLayersStore'; | |
| export { useMeasureStore } from './useMeasureStore'; | |
| +export { useAuthStore } from './useAuthStore'; | |
| +export { useActiveUsersStore } from './useActiveUsersStore'; | |
| diff --git a/store/useActiveUsersStore.ts b/store/useActiveUsersStore.ts | |
| new file mode 100644 | |
| index 0000000..1e13e06 | |
| --- /dev/null | |
| +++ b/store/useActiveUsersStore.ts | |
| @@ -0,0 +1,96 @@ | |
| +import { create } from 'zustand'; | |
| +import type { Coordinates } from '@/types'; | |
| + | |
| +// Active user type for globe visualization | |
| +export interface ActiveUser { | |
| + id: string; | |
| + distinctId: string; | |
| + email?: string; | |
| + name?: string; | |
| + location: Coordinates; | |
| + lastSeen: string; | |
| + isOnline: boolean; | |
| +} | |
| + | |
| +interface ActiveUsersState { | |
| + users: ActiveUser[]; | |
| + isLoading: boolean; | |
| + lastFetched: string | null; | |
| + currentUserId: string | null; | |
| + error: string | null; | |
| + | |
| + setUsers: (users: ActiveUser[]) => void; | |
| + addUser: (user: ActiveUser) => void; | |
| + updateUserLocation: (userId: string, location: Coordinates) => void; | |
| + removeUser: (userId: string) => void; | |
| + setCurrentUserId: (userId: string | null) => void; | |
| + setLoading: (loading: boolean) => void; | |
| + setError: (error: string | null) => void; | |
| + fetchUsers: () => Promise<void>; | |
| +} | |
| + | |
| +// API endpoint for fetching active users | |
| +const ACTIVE_USERS_API = '/api/active-users'; | |
| + | |
| +export const useActiveUsersStore = create<ActiveUsersState>((set, get) => ({ | |
| + users: [], | |
| + isLoading: false, | |
| + lastFetched: null, | |
| + currentUserId: null, | |
| + error: null, | |
| + | |
| + setUsers: (users) => set({ users, lastFetched: new Date().toISOString() }), | |
| + | |
| + addUser: (user) => | |
| + set((state) => { | |
| + const existing = state.users.find((u) => u.id === user.id); | |
| + if (existing) { | |
| + return { | |
| + users: state.users.map((u) => (u.id === user.id ? user : u)), | |
| + }; | |
| + } | |
| + return { users: [...state.users, user] }; | |
| + }), | |
| + | |
| + updateUserLocation: (userId, location) => | |
| + set((state) => ({ | |
| + users: state.users.map((u) => | |
| + u.id === userId | |
| + ? { ...u, location, lastSeen: new Date().toISOString(), isOnline: true } | |
| + : u | |
| + ), | |
| + })), | |
| + | |
| + removeUser: (userId) => | |
| + set((state) => ({ | |
| + users: state.users.filter((u) => u.id !== userId), | |
| + })), | |
| + | |
| + setCurrentUserId: (userId) => set({ currentUserId: userId }), | |
| + | |
| + setLoading: (loading) => set({ isLoading: loading }), | |
| + | |
| + setError: (error) => set({ error }), | |
| + | |
| + fetchUsers: async () => { | |
| + const { setUsers, setLoading, setError } = get(); | |
| + setLoading(true); | |
| + setError(null); | |
| + | |
| + try { | |
| + const response = await fetch(ACTIVE_USERS_API); | |
| + | |
| + if (!response.ok) { | |
| + throw new Error('Failed to fetch active users'); | |
| + } | |
| + | |
| + const data = await response.json(); | |
| + setUsers(data.users || []); | |
| + } catch (error) { | |
| + console.error('Failed to fetch active users:', error); | |
| + setError(error instanceof Error ? error.message : 'Failed to fetch users'); | |
| + } finally { | |
| + setLoading(false); | |
| + } | |
| + }, | |
| +})); | |
| diff --git a/store/useAuthStore.ts b/store/useAuthStore.ts | |
| new file mode 100644 | |
| index 0000000..00c5841 | |
| --- /dev/null | |
| +++ b/store/useAuthStore.ts | |
| @@ -0,0 +1,86 @@ | |
| +import { create } from 'zustand'; | |
| +import type { User, Session } from '@/lib/auth'; | |
| +import { | |
| + getSession, | |
| + signIn as authSignIn, | |
| + signUp as authSignUp, | |
| + signOut as authSignOut, | |
| +} from '@/lib/auth'; | |
| + | |
| +interface AuthState { | |
| + user: User | null; | |
| + session: Session | null; | |
| + isLoading: boolean; | |
| + isInitialized: boolean; | |
| + | |
| + initialize: () => void; | |
| + signIn: ( | |
| + email: string, | |
| + password: string | |
| + ) => Promise<{ success: boolean; error?: string }>; | |
| + signUp: ( | |
| + email: string, | |
| + password: string, | |
| + name?: string | |
| + ) => Promise<{ success: boolean; error?: string }>; | |
| + signOut: () => void; | |
| +} | |
| + | |
| +export const useAuthStore = create<AuthState>((set, get) => ({ | |
| + user: null, | |
| + session: null, | |
| + isLoading: false, | |
| + isInitialized: false, | |
| + | |
| + initialize: () => { | |
| + if (get().isInitialized) return; | |
| + | |
| + const session = getSession(); | |
| + set({ | |
| + session, | |
| + user: session?.user ?? null, | |
| + isInitialized: true, | |
| + }); | |
| + }, | |
| + | |
| + signIn: async (email, password) => { | |
| + set({ isLoading: true }); | |
| + | |
| + const result = await authSignIn(email, password); | |
| + | |
| + if (result.success) { | |
| + set({ | |
| + session: result.session, | |
| + user: result.session.user, | |
| + isLoading: false, | |
| + }); | |
| + return { success: true }; | |
| + } | |
| + | |
| + set({ isLoading: false }); | |
| + return { success: false, error: result.error }; | |
| + }, | |
| + | |
| + signUp: async (email, password, name) => { | |
| + set({ isLoading: true }); | |
| + | |
| + const result = await authSignUp(email, password, name); | |
| + | |
| + if (result.success) { | |
| + set({ | |
| + session: result.session, | |
| + user: result.session.user, | |
| + isLoading: false, | |
| + }); | |
| + return { success: true }; | |
| + } | |
| + | |
| + set({ isLoading: false }); | |
| + return { success: false, error: result.error }; | |
| + }, | |
| + | |
| + signOut: () => { | |
| + authSignOut(); | |
| + set({ session: null, user: null }); | |
| + }, | |
| +})); | |
| diff --git a/types/index.ts b/types/index.ts | |
| index ac58bac..bfc047f 100644 | |
| --- a/types/index.ts | |
| +++ b/types/index.ts | |
| @@ -53,7 +53,7 @@ export interface LayerState { | |
| }; | |
| } | |
| -export type PanelTab = 'layers' | 'places' | 'measure'; | |
| +export type PanelTab = 'layers' | 'places' | 'measure' | 'users'; | |
| export interface CursorPosition extends Coordinates { | |
| height?: number; | |
| @@ -95,3 +95,14 @@ export const LayerStateSchema = z.object({ | |
| }); | |
| export type ThemeMode = 'light' | 'dark' | 'system'; | |
| + | |
| +// Active user for globe visualization | |
| +export interface ActiveUser { | |
| + id: string; | |
| + distinctId: string; | |
| + email?: string; | |
| + name?: string; | |
| + location: Coordinates; | |
| + lastSeen: string; | |
| + isOnline: boolean; | |
| +} | |
| -- | |
| 2.52.0 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment