├── .github └── workflows │ ├── build-test.yml │ └── docker-push.yml ├── .gitignore ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── SECURITY.md ├── cmd └── server │ ├── main.go │ └── router.go ├── docker-compose.prod.yml ├── docker-compose.yaml ├── go.mod ├── go.sum ├── internal ├── analytics │ ├── analytics.go │ └── tracker.go ├── api │ └── v1 │ │ ├── config.go │ │ ├── config_test.go │ │ ├── redirect.go │ │ ├── redirect_test.go │ │ ├── shorten.go │ │ └── shorten_test.go ├── db │ ├── db.go │ └── migrations.go ├── models │ └── url.go └── utils │ ├── urlgen.go │ ├── urlscan.go │ └── validation.go ├── migrations └── migrations.go ├── nginx.conf ├── package-lock.json ├── pkg ├── config │ └── config.go └── logger │ └── logger.go ├── supervisord.conf ├── version.yaml └── web ├── .gitignore ├── .npmrc ├── .prettierignore ├── .prettierrc ├── README.md ├── eslint.config.js ├── jsconfig.json ├── package-lock.json ├── package.json ├── postcss.config.js ├── src ├── app.css ├── app.html ├── components │ ├── Footer.svelte │ └── Main.svelte ├── lib │ ├── config.js │ └── index.js └── routes │ ├── +layout.js │ ├── +layout.server.js │ ├── +layout.svelte │ └── +page.svelte ├── static ├── banner.png └── favicon.png ├── svelte.config.js ├── tailwind.config.js └── vite.config.js /.github/workflows/build-test.yml: -------------------------------------------------------------------------------- 1 | name: 🛠️ Build, Test & Scan 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | build-go: 10 | name: 🐹 Build Go Project 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - name: 📥 Checkout Code 15 | uses: actions/checkout@v4 16 | 17 | - name: 🐹 Set Up Go 18 | uses: actions/setup-go@v5 19 | with: 20 | go-version: '1.22' 21 | 22 | - name: 🛠️ Build Go Project 23 | run: make build 24 | 25 | build-Svelte: 26 | name: 🌐 Build Svelte Project 27 | runs-on: ubuntu-latest 28 | 29 | steps: 30 | - name: 📥 Checkout Code 31 | uses: actions/checkout@v4 32 | 33 | - name: 🌐 Set Up Node.js 34 | uses: actions/setup-node@v4 35 | with: 36 | node-version: '20' 37 | 38 | - name: 📦 Install Svelte Dependencies 39 | run: | 40 | cd web 41 | npm install 42 | 43 | - name: 🖥️ Build Svelte Project 44 | run: | 45 | cd web 46 | npm run build 47 | 48 | test-go: 49 | name: ✅ Run Go Tests 50 | runs-on: ubuntu-latest 51 | 52 | steps: 53 | - name: 📥 Checkout Code 54 | uses: actions/checkout@v4 55 | 56 | - name: 🐹 Set Up Go 57 | uses: actions/setup-go@v5 58 | with: 59 | go-version: '1.22' 60 | 61 | - name: ✅ Run Go Tests 62 | run: make test 63 | 64 | - name: 📊 Upload Code Coverage Report 65 | uses: actions/upload-artifact@v4 66 | with: 67 | name: go-code-coverage 68 | path: coverage.out 69 | 70 | scan-vulnerabilities: 71 | name: 🔍 Scan for Vulnerabilities 72 | runs-on: ubuntu-latest 73 | 74 | steps: 75 | - name: 📥 Checkout Code 76 | uses: actions/checkout@v4 77 | 78 | - name: 🐹 Set Up Go 79 | uses: actions/setup-go@v5 80 | with: 81 | go-version: '1.22' 82 | 83 | - name: 🔍 Run Golang Security Scanner 84 | uses: securego/gosec@v2.21.4 85 | with: 86 | args: '-no-fail -fmt sarif -out results.sarif ./...' 87 | 88 | - name: 📝 Upload SARIF Results 89 | uses: github/codeql-action/upload-sarif@v3 90 | with: 91 | sarif_file: results.sarif 92 | 93 | - name: 🌐 Set Up Node.js 94 | uses: actions/setup-node@v4 95 | with: 96 | node-version: '20' 97 | 98 | - name: 📦 Install Svelte Dependencies 99 | run: | 100 | cd web 101 | npm install 102 | 103 | - name: 🔍 Run NPM Audit 104 | run: | 105 | cd web 106 | npm audit --audit-level=high || true 107 | -------------------------------------------------------------------------------- /.github/workflows/docker-push.yml: -------------------------------------------------------------------------------- 1 | name: 🐳 Build and Push Docker Images 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | workflow_dispatch: 11 | 12 | permissions: 13 | contents: read 14 | packages: write 15 | 16 | jobs: 17 | build-backend: 18 | name: 🛠️ Build and Push 19 | runs-on: ubuntu-latest 20 | steps: 21 | - name: 🚀 Checkout Code 22 | uses: actions/checkout@v4 23 | 24 | # Get version from version.yaml 25 | - name: 📁 Get version 26 | run: | 27 | echo "VERSION=$(cat version.yaml | sed -n 's/version: //p')" >> $GITHUB_ENV 28 | echo $VERSION 29 | 30 | # Set build tags based on branch 31 | - name: 🏗️ Set Build tags 32 | run: | 33 | if [ $GITHUB_REF = 'refs/heads/main' ]; then 34 | echo "IMAGE_TAGS=$VERSION" >> $GITHUB_ENV 35 | else 36 | echo "IMAGE_TAGS=rc-$VERSION-$GITHUB_RUN_NUMBER" >> $GITHUB_ENV 37 | fi 38 | 39 | - name: 🛠️ Set up Docker Buildx 40 | uses: docker/setup-buildx-action@v2 41 | 42 | # Login to GitHub Container Registry 43 | - name: 🔐 Login to GitHub Container Registry 44 | uses: docker/login-action@v2 45 | with: 46 | registry: ghcr.io 47 | username: ${{ github.actor }} 48 | password: ${{ secrets.TOKEN }} 49 | 50 | # Login to Docker Hub 51 | - name: 🔐 Login to Docker Hub 52 | if: github.ref == 'refs/heads/main' 53 | uses: docker/login-action@v2 54 | with: 55 | username: ${{ secrets.DOCKERHUB_USERNAME }} 56 | password: ${{ secrets.DOCKERHUB_TOKEN }} 57 | 58 | - name: 📦 Build and Push Image to GHCR (PR) 59 | if: github.event_name == 'pull_request' 60 | uses: docker/build-push-action@v4 61 | with: 62 | context: . 63 | file: ./Dockerfile 64 | push: true 65 | tags: ghcr.io/kek-sec/goshort:${{ env.IMAGE_TAGS }} 66 | annotations: | 67 | org.opencontainers.image.description=goshort, url shortener 68 | build-args: | 69 | VERSION=${{ env.VERSION }} 70 | labels: | 71 | org.opencontainers.image.source=https://github.com/kek-sec/goshort 72 | cache-from: type=registry,ref=ghcr.io/kek-sec/goshort:latest 73 | cache-to: type=registry,ref=ghcr.io/kek-sec/goshort:latest 74 | 75 | - name: 📦 Build and Push Image to GHCR and Docker Hub (Main) 76 | if: github.ref == 'refs/heads/main' 77 | uses: docker/build-push-action@v4 78 | with: 79 | context: . 80 | file: ./Dockerfile 81 | push: true 82 | tags: | 83 | ghcr.io/kek-sec/goshort:${{ env.IMAGE_TAGS }} 84 | petrakisg/goshort:${{ env.IMAGE_TAGS }} 85 | annotations: | 86 | org.opencontainers.image.description=goshort, a secure one-time secret sharing service 87 | build-args: | 88 | VERSION=${{ env.VERSION }} 89 | labels: | 90 | org.opencontainers.image.source=https://github.com/kek-sec/goshort 91 | cache-from: type=registry,ref=ghcr.io/kek-sec/goshort:latest 92 | cache-to: type=registry,ref=ghcr.io/kek-sec/goshort:latest -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Stage 1: Build the Go application 2 | FROM golang:1.22.4 AS builder 3 | 4 | ARG VERSION=dev 5 | ENV VERSION=${VERSION} 6 | 7 | # Set working directory 8 | WORKDIR /app 9 | 10 | # Copy go.mod and go.sum for dependency resolution 11 | COPY go.mod go.sum ./ 12 | 13 | # Download dependencies 14 | RUN go mod download 15 | 16 | # Copy the rest of the application code 17 | COPY . . 18 | 19 | # Build the Go application 20 | RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -X main.version=${VERSION}" -o goshort ./cmd/server 21 | 22 | # Stage 2: Build the SvelteKit web application 23 | FROM node:18 AS web-builder 24 | 25 | # Set working directory 26 | WORKDIR /web 27 | 28 | # Copy the SvelteKit project files 29 | COPY web/package.json web/package-lock.json ./ 30 | COPY web/ ./ 31 | 32 | # Install dependencies and build the web app 33 | RUN npm install 34 | RUN npm run build 35 | 36 | # Stage 3: Production 37 | FROM alpine:latest AS production 38 | 39 | # Install Nginx and Supervisord 40 | RUN apk add --no-cache nginx supervisor 41 | 42 | # Set up working directories 43 | WORKDIR /app 44 | 45 | # Copy the Go application binary 46 | COPY --from=builder /app/goshort /app/goshort 47 | 48 | # Copy the SvelteKit build output to Nginx HTML folder 49 | COPY --from=web-builder /web/build /usr/share/nginx/html 50 | 51 | # Copy Nginx configuration 52 | COPY nginx.conf /etc/nginx/nginx.conf 53 | 54 | # Copy supervisord configuration 55 | COPY supervisord.conf /etc/supervisord.conf 56 | 57 | # Set environment variables with default values that can be overridden 58 | ENV BRAND_TITLE="GoShort - URL Shortener" \ 59 | BRAND_DESCRIPTION="GoShort is a powerful and user-friendly URL shortener. Simplify, manage, and track your links with ease." \ 60 | BRAND_KEYWORDS="URL shortener, GoShort, link management, shorten URLs, track links" \ 61 | BRAND_AUTHOR="GoShort Team" \ 62 | BRAND_THEME_COLOR="#4caf50" \ 63 | BRAND_LOGO_TEXT="GoShort" \ 64 | BRAND_PRIMARY_COLOR="#3b82f6" \ 65 | BRAND_SECONDARY_COLOR="#10b981" \ 66 | BRAND_HEADER_TITLE="GoShort - URL Shortener" \ 67 | BRAND_FOOTER_TEXT="View the project on" \ 68 | BRAND_FOOTER_LINK="https://github.com/kek-Sec/GoShort" 69 | 70 | # Expose ports 71 | EXPOSE 80 8080 72 | 73 | # Command to run both Nginx and the Go application 74 | CMD ["supervisord", "-c", "/etc/supervisord.conf"] 75 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [2024] [Petrakis Georgios] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Project variables 2 | APP_NAME := goshort 3 | BIN_DIR := bin 4 | BUILD_DIR := $(BIN_DIR)/$(APP_NAME) 5 | PKG_LIST := $(shell go list ./... | grep -v /tests) 6 | 7 | # Commands 8 | GOCMD := go 9 | GOBUILD := $(GOCMD) build 10 | GOTEST := $(GOCMD) test 11 | GOLINT := golangci-lint 12 | GOFMT := gofmt 13 | GOMODTIDY := $(GOCMD) mod tidy 14 | DOCKER_COMPOSE := docker compose 15 | 16 | # Build variables 17 | BUILD_FLAGS := -ldflags "-s -w" 18 | 19 | # Targets 20 | .PHONY: all build test lint fmt run clean docker-up docker-down docker-build help 21 | 22 | all: build ## Build the application 23 | 24 | build: clean ## Build the application binaries 25 | @echo "Building the $(APP_NAME)..." 26 | $(GOBUILD) $(BUILD_FLAGS) -o $(BUILD_DIR) ./cmd/server 27 | @echo "Build completed." 28 | 29 | test: ## Run unit tests 30 | @echo "Running tests..." 31 | $(GOTEST) -v -race ./... 32 | @echo "Tests completed." 33 | 34 | lint: ## Run lint checks 35 | @echo "Running lint checks..." 36 | $(GOLINT) run ./... 37 | @echo "Linting completed." 38 | 39 | fmt: ## Format the code 40 | @echo "Formatting code..." 41 | $(GOFMT) -s -w $(PKG_LIST) 42 | @echo "Code formatted." 43 | 44 | run: build ## Build and run the application 45 | @echo "Running the application..." 46 | $(BUILD_DIR) 47 | 48 | clean: ## Clean up build artifacts 49 | @echo "Cleaning up..." 50 | rm -rf $(BIN_DIR) 51 | @echo "Cleanup completed." 52 | 53 | docker-up: ## Start Docker containers (app and database) 54 | @echo "Starting Docker containers..." 55 | $(DOCKER_COMPOSE) up -d 56 | @echo "Docker containers started." 57 | 58 | docker-down: ## Stop Docker containers (app and database) 59 | @echo "Stopping Docker containers..." 60 | $(DOCKER_COMPOSE) down 61 | @echo "Docker containers stopped." 62 | 63 | docker-build: ## Build Docker images for the application 64 | @echo "Building Docker images..." 65 | $(DOCKER_COMPOSE) build 66 | @echo "Docker images built." 67 | 68 | help: ## Display this help message 69 | @echo "Available targets:" 70 | @grep -E '^[a-zA-Z0-9_-]+:.*?##' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "} {printf " %-15s %s\n", $$1, $$2}' 71 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ✂️ **GoShort** - Fast and customizable URL shortener 2 | 3 | ![Docker Image Version](https://img.shields.io/docker/v/petrakisg/goshort?sort=semver&label=Docker%20Image%20Version&logo=docker) 4 | ![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/kek-Sec/GoShort) 5 | 6 | 7 | ### Demo: [https://x.yup.gr](http://x.yup.gr) 8 | ### DockerHub Image: [petrakisg/goshort](https://hub.docker.com/r/petrakisg/goshort) 9 | 10 | GoShort is a fast and customizable URL shortener built with Go, Svelte and TailwindCSS. It is designed to be self-hosted and easy to deploy. 11 | 12 | ![GoShort](web/static/banner.png) 13 | 14 | --- 15 | 16 | ## 📋 **Table of Contents** 17 | 18 | 1. [Features](#-features) 19 | 2. [Installation](#-installation) 20 | 3. [Customization](#-customization) 21 | 4. [Contributing](#-contributing) 22 | 5. [License](#-license) 23 | 6. [Security](#-security) 24 | --- 25 | 26 | ## 🚀 **Features** 27 | 28 | - **Fast**: GoShort is built with Go and is blazing fast. 29 | - **Customizable**: GoShort is built with Svelte and TailwindCSS, making it easy to customize. 30 | - **Self-hosted**: You own your data and can deploy GoShort on your own server. 31 | - **Custom URLs**: You can set custom URLs for your short links. 32 | - **Expiration**: You can set expiration for your short links. 33 | - **White-labeling**: Customize branding elements without rebuilding the Docker image. 34 | 35 | --- 36 | 37 | ## 🛠️ **Installation** 38 | 39 | > Checkout docker-compose.prod.yml for a sample production setup. 40 | 41 | --- 42 | 43 | ## 🎨 **Customization** 44 | 45 | GoShort supports customizing the branding and appearance through environment variables, making it easy to white-label without rebuilding the Docker image. 46 | 47 | ### Available Customization Options 48 | 49 | You can customize the following aspects of the UI by setting these environment variables: 50 | 51 | | Environment Variable | Description | Default Value | 52 | |---------------------|-------------|---------------| 53 | | BRAND_TITLE | Browser tab title | GoShort - URL Shortener | 54 | | BRAND_DESCRIPTION | Meta description for SEO | GoShort is a powerful and user-friendly URL shortener... | 55 | | BRAND_KEYWORDS | Meta keywords for SEO | URL shortener, GoShort, link management... | 56 | | BRAND_AUTHOR | Author meta tag | GoShort Team | 57 | | BRAND_THEME_COLOR | Browser theme color | #4caf50 | 58 | | BRAND_LOGO_TEXT | Text logo displayed in the header | GoShort | 59 | | BRAND_PRIMARY_COLOR | Main accent color (buttons, links) | #3b82f6 | 60 | | BRAND_SECONDARY_COLOR | Secondary accent color | #10b981 | 61 | | BRAND_HEADER_TITLE | Main heading on the page | GoShort - URL Shortener | 62 | | BRAND_FOOTER_TEXT | Text shown in the footer | View the project on | 63 | | BRAND_FOOTER_LINK | URL for the footer link | https://github.com/kek-Sec/GoShort | 64 | 65 | ### Usage Example 66 | 67 | Here's how to customize the branding in your docker-compose file: 68 | 69 | ```yaml 70 | services: 71 | goshort: 72 | image: petrakisg/goshort:1.0.1 73 | environment: 74 | # Database configuration 75 | DATABASE_URL: postgres://user:password@db:5432/goshort 76 | 77 | # Branding customization 78 | BRAND_TITLE: "MyCompany URL Shortener" 79 | BRAND_LOGO_TEXT: "MyShort" 80 | BRAND_PRIMARY_COLOR: "#ff5722" 81 | BRAND_SECONDARY_COLOR: "#2196f3" 82 | BRAND_HEADER_TITLE: "MyCompany Link Shortener" 83 | BRAND_FOOTER_TEXT: "Powered by" 84 | BRAND_FOOTER_LINK: "https://mycompany.com" 85 | ``` 86 | 87 | --- 88 | 89 | ## 🤝 **Contributing** 90 | 91 | 1. Fork the repository. 92 | 2. Create a new branch: `git checkout -b my-feature-branch` 93 | 3. Make your changes and add tests. 94 | 4. Submit a pull request. 95 | 96 | --- 97 | 98 | ## 📄 **License** 99 | 100 | GoShort is licensed under the MIT License. See the [LICENSE](LICENSE) file for more information. 101 | 102 | --- 103 | 104 | ## 🔒 **Security** 105 | 106 | We take security seriously and appreciate your efforts to responsibly disclose vulnerabilities. Checkout [SECURITY.md](SECURITY.md) for more information. -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | | Version | Supported | 6 | | ------- | ------------------ | 7 | | 1.0.x | :white_check_mark: | 8 | | < 1.0.0 | :x: | 9 | 10 | ## Reporting a Vulnerability 11 | 12 | We take security seriously and appreciate your efforts to responsibly disclose vulnerabilities. If you discover a security issue in **GoShort**, please report it through GitHub’s security advisories: 13 | 14 | 1. **Go to the Repository**: Visit the [GoShort repository](https://github.com/kek-Sec/goshort). 15 | 16 | 2. **Report a Vulnerability**: 17 | - Click on **"Security"** in the top navigation bar. 18 | - Select **"Report a vulnerability"**. 19 | - Fill in the details of the vulnerability, including: 20 | - Steps to reproduce the issue. 21 | - Potential impact or severity. 22 | - Any relevant code snippets, screenshots, or logs. 23 | 24 | ### What to Expect 25 | 26 | - **Acknowledgment**: We will acknowledge your report within **48 hours**. 27 | - **Initial Assessment**: We aim to provide an initial assessment within **5 business days**. 28 | - **Updates**: You will receive regular updates as we investigate and resolve the issue. 29 | - **Resolution**: Once resolved, we will notify you and credit you in the release notes unless you wish to remain anonymous. 30 | 31 | ### Responsible Disclosure 32 | 33 | Please **do not publicly disclose** the vulnerability until we have addressed it. We are committed to resolving security issues promptly and responsibly. 34 | 35 | --- 36 | 37 | Thank you for helping us keep **GoShort** secure! 38 | -------------------------------------------------------------------------------- /cmd/server/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "GoShort/pkg/config" 5 | "GoShort/pkg/logger" 6 | "GoShort/internal/db" 7 | "log" 8 | "net/http" 9 | ) 10 | 11 | var version = "dev" 12 | 13 | func main() { 14 | // Load configuration 15 | config.Load() 16 | 17 | // Initialize logger 18 | logger.Init() 19 | 20 | // Initialize database 21 | db.InitDB() 22 | 23 | // Set up HTTP server 24 | router := setupRouter() 25 | 26 | // Start the server 27 | log.Println("Starting GoShort server on port 8080...") 28 | log.Printf("Version: %s\n", version) 29 | if err := http.ListenAndServe(":8080", router); err != nil { 30 | log.Fatalf("Server failed to start: %v", err) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /cmd/server/router.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | v1 "GoShort/internal/api/v1" 5 | 6 | "github.com/gorilla/mux" 7 | ) 8 | 9 | // setupRouter initializes the HTTP router and routes 10 | func setupRouter() *mux.Router { 11 | router := mux.NewRouter() 12 | 13 | // V1 Routes 14 | apiV1 := router.PathPrefix("/v1").Subrouter() 15 | apiV1.HandleFunc("/shorten", v1.ShortenURL).Methods("POST") 16 | apiV1.HandleFunc("/config", v1.GetConfig).Methods("GET") // Add config endpoint 17 | 18 | // Redirect Route (catch-all) 19 | router.HandleFunc("/{shortURL}", v1.RedirectURL).Methods("GET") 20 | 21 | return router 22 | } 23 | -------------------------------------------------------------------------------- /docker-compose.prod.yml: -------------------------------------------------------------------------------- 1 | services: 2 | goshort-db: 3 | image: postgres:17-alpine 4 | container_name: goshort_db 5 | environment: 6 | POSTGRES_USER: goshort 7 | POSTGRES_PASSWORD: goshort_password 8 | POSTGRES_DB: goshort 9 | volumes: 10 | - ./postgres_data:/var/lib/postgresql/data 11 | healthcheck: 12 | test: ["CMD-SHELL", "pg_isready -U goshort -d goshort"] 13 | interval: 10s 14 | timeout: 5s 15 | retries: 5 16 | networks: 17 | - goshort_net 18 | 19 | goshort: 20 | image: petrakisg/goshort:1.0.1 21 | container_name: goshort_app 22 | environment: 23 | DATABASE_URL: postgres://goshort:goshort_password@goshort-db:5432/goshort?sslmode=disable 24 | # Branding customization (uncomment and modify as needed) 25 | # BRAND_TITLE: "MyShort - URL Shortener" 26 | # BRAND_DESCRIPTION: "A fast and customizable URL shortener for your organization" 27 | # BRAND_AUTHOR: "Your Company Name" 28 | # BRAND_THEME_COLOR: "#2563eb" 29 | # BRAND_LOGO_TEXT: "MyShort" 30 | # BRAND_PRIMARY_COLOR: "#2563eb" 31 | # BRAND_SECONDARY_COLOR: "#10b981" 32 | # BRAND_HEADER_TITLE: "MyShort - Simplify Your URLs" 33 | # BRAND_FOOTER_TEXT: "Powered by" 34 | # BRAND_FOOTER_LINK: "https://yourcompany.com" 35 | depends_on: 36 | goshort-db: 37 | condition: service_healthy 38 | ports: 39 | - 8081:80 40 | networks: 41 | - goshort_net 42 | 43 | networks: 44 | goshort_net: 45 | external: true 46 | -------------------------------------------------------------------------------- /docker-compose.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | goshort: 3 | build: 4 | context: . 5 | dockerfile: Dockerfile 6 | container_name: goshort 7 | ports: 8 | - "8081:80" # Frontend 9 | environment: 10 | DATABASE_URL: postgres://goshort:goshort_password@database:5432/goshort?sslmode=disable 11 | # Branding customization (optional) 12 | BRAND_TITLE: "GoShort - URL Shortener" 13 | BRAND_DESCRIPTION: "A fast and customizable URL shortener" 14 | BRAND_THEME_COLOR: "#4caf50" 15 | BRAND_PRIMARY_COLOR: "#3b82f6" 16 | BRAND_SECONDARY_COLOR: "#10b981" 17 | BRAND_HEADER_TITLE: "GoShort - URL Shortener" 18 | depends_on: 19 | database: 20 | condition: service_healthy 21 | 22 | database: 23 | image: postgres:17-bullseye 24 | container_name: goshort_db 25 | restart: always 26 | environment: 27 | POSTGRES_USER: goshort 28 | POSTGRES_PASSWORD: goshort_password 29 | POSTGRES_DB: goshort 30 | ports: 31 | - "5432:5432" 32 | volumes: 33 | - postgres_data:/var/lib/postgresql/data 34 | healthcheck: 35 | test: ["CMD-SHELL", "pg_isready -U goshort -d goshort"] 36 | interval: 10s 37 | timeout: 5s 38 | retries: 5 39 | 40 | volumes: 41 | postgres_data: 42 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module GoShort 2 | 3 | go 1.22.4 4 | 5 | require ( 6 | github.com/golang-jwt/jwt/v5 v5.2.1 7 | github.com/gorilla/mux v1.8.1 8 | github.com/joho/godotenv v1.5.1 9 | github.com/sirupsen/logrus v1.9.3 10 | github.com/stretchr/testify v1.10.0 11 | gorm.io/driver/postgres v1.5.11 12 | gorm.io/gorm v1.25.12 13 | ) 14 | 15 | require ( 16 | github.com/davecgh/go-spew v1.1.1 // indirect 17 | github.com/jackc/pgpassfile v1.0.0 // indirect 18 | github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect 19 | github.com/jackc/pgx/v5 v5.7.2 // indirect 20 | github.com/jackc/puddle/v2 v2.2.2 // indirect 21 | github.com/jinzhu/inflection v1.0.0 // indirect 22 | github.com/jinzhu/now v1.1.5 // indirect 23 | github.com/kr/text v0.2.0 // indirect 24 | github.com/pmezard/go-difflib v1.0.0 // indirect 25 | github.com/rogpeppe/go-internal v1.13.1 // indirect 26 | golang.org/x/crypto v0.31.0 // indirect 27 | golang.org/x/sync v0.10.0 // indirect 28 | golang.org/x/sys v0.28.0 // indirect 29 | golang.org/x/text v0.21.0 // indirect 30 | gopkg.in/yaml.v3 v3.0.1 // indirect 31 | ) 32 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 2 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 4 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 5 | github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= 6 | github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= 7 | github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= 8 | github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= 9 | github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= 10 | github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= 11 | github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= 12 | github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= 13 | github.com/jackc/pgx/v5 v5.7.2 h1:mLoDLV6sonKlvjIEsV56SkWNCnuNv531l94GaIzO+XI= 14 | github.com/jackc/pgx/v5 v5.7.2/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ= 15 | github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= 16 | github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= 17 | github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= 18 | github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= 19 | github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= 20 | github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= 21 | github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= 22 | github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= 23 | github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= 24 | github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= 25 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 26 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 27 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 28 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 29 | github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= 30 | github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= 31 | github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= 32 | github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= 33 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 34 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 35 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 36 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 37 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 38 | golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= 39 | golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= 40 | golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= 41 | golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 42 | golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 43 | golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= 44 | golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 45 | golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= 46 | golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= 47 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 48 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 49 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 50 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 51 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 52 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 53 | gorm.io/driver/postgres v1.5.11 h1:ubBVAfbKEUld/twyKZ0IYn9rSQh448EdelLYk9Mv314= 54 | gorm.io/driver/postgres v1.5.11/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI= 55 | gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8= 56 | gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= 57 | -------------------------------------------------------------------------------- /internal/analytics/analytics.go: -------------------------------------------------------------------------------- 1 | package analytics 2 | 3 | import ( 4 | "log" 5 | "time" 6 | ) 7 | 8 | // StartCleanupTask starts a periodic cleanup task to remove old analytics data 9 | func StartCleanupTask(tracker *AnalyticsTracker, interval time.Duration, cutoff time.Duration) { 10 | go func() { 11 | for { 12 | time.Sleep(interval) 13 | 14 | log.Println("Running analytics cleanup task...") 15 | tracker.CleanupOldStats(time.Now().Add(-cutoff)) 16 | log.Println("Analytics cleanup task completed.") 17 | } 18 | }() 19 | } 20 | -------------------------------------------------------------------------------- /internal/analytics/tracker.go: -------------------------------------------------------------------------------- 1 | package analytics 2 | 3 | import ( 4 | "sync" 5 | "time" 6 | ) 7 | 8 | // AnalyticsTracker is a thread-safe structure to track and store URL usage statistics 9 | type AnalyticsTracker struct { 10 | mu sync.RWMutex 11 | statistics map[string]*URLStats 12 | } 13 | 14 | // URLStats holds analytics data for a specific URL 15 | type URLStats struct { 16 | ClickCount int 17 | LastAccessed time.Time 18 | Referrers map[string]int 19 | Geolocations map[string]int 20 | } 21 | 22 | // NewAnalyticsTracker creates and initializes a new AnalyticsTracker 23 | func NewAnalyticsTracker() *AnalyticsTracker { 24 | return &AnalyticsTracker{ 25 | statistics: make(map[string]*URLStats), 26 | } 27 | } 28 | 29 | // RecordClick increments the click count for the given shortURL and tracks metadata 30 | func (at *AnalyticsTracker) RecordClick(shortURL, referrer, geolocation string) { 31 | at.mu.Lock() 32 | defer at.mu.Unlock() 33 | 34 | if _, exists := at.statistics[shortURL]; !exists { 35 | at.statistics[shortURL] = &URLStats{ 36 | Referrers: make(map[string]int), 37 | Geolocations: make(map[string]int), 38 | } 39 | } 40 | 41 | stats := at.statistics[shortURL] 42 | stats.ClickCount++ 43 | stats.LastAccessed = time.Now() 44 | stats.Referrers[referrer]++ 45 | stats.Geolocations[geolocation]++ 46 | } 47 | 48 | // GetStats retrieves statistics for the given shortURL 49 | func (at *AnalyticsTracker) GetStats(shortURL string) (*URLStats, bool) { 50 | at.mu.RLock() 51 | defer at.mu.RUnlock() 52 | 53 | stats, exists := at.statistics[shortURL] 54 | return stats, exists 55 | } 56 | 57 | // CleanupOldStats removes analytics data for URLs not accessed since the provided cutoff time 58 | func (at *AnalyticsTracker) CleanupOldStats(cutoff time.Time) { 59 | at.mu.Lock() 60 | defer at.mu.Unlock() 61 | 62 | for shortURL, stats := range at.statistics { 63 | if stats.LastAccessed.Before(cutoff) { 64 | delete(at.statistics, shortURL) 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /internal/api/v1/config.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "encoding/json" 5 | "net/http" 6 | "os" 7 | ) 8 | 9 | // Config represents the frontend configuration 10 | type Config struct { 11 | Title string `json:"title,omitempty"` 12 | Description string `json:"description,omitempty"` 13 | Keywords string `json:"keywords,omitempty"` 14 | Author string `json:"author,omitempty"` 15 | ThemeColor string `json:"themeColor,omitempty"` 16 | LogoText string `json:"logoText,omitempty"` 17 | PrimaryColor string `json:"primaryColor,omitempty"` 18 | SecondaryColor string `json:"secondaryColor,omitempty"` 19 | HeaderTitle string `json:"headerTitle,omitempty"` 20 | FooterText string `json:"footerText,omitempty"` 21 | FooterLink string `json:"footerLink,omitempty"` 22 | } 23 | 24 | // GetConfig returns the frontend configuration 25 | func GetConfig(w http.ResponseWriter, r *http.Request) { 26 | config := Config{} 27 | 28 | // Load config from environment variables 29 | envVars := map[string]*string{ 30 | "BRAND_TITLE": &config.Title, 31 | "BRAND_DESCRIPTION": &config.Description, 32 | "BRAND_KEYWORDS": &config.Keywords, 33 | "BRAND_AUTHOR": &config.Author, 34 | "BRAND_THEME_COLOR": &config.ThemeColor, 35 | "BRAND_LOGO_TEXT": &config.LogoText, 36 | "BRAND_PRIMARY_COLOR": &config.PrimaryColor, 37 | "BRAND_SECONDARY_COLOR": &config.SecondaryColor, 38 | "BRAND_HEADER_TITLE": &config.HeaderTitle, 39 | "BRAND_FOOTER_TEXT": &config.FooterText, 40 | "BRAND_FOOTER_LINK": &config.FooterLink, 41 | } 42 | 43 | for envVar, field := range envVars { 44 | if value := os.Getenv(envVar); value != "" { 45 | *field = value 46 | } 47 | } 48 | 49 | // Set response headers 50 | w.Header().Set("Content-Type", "application/json") 51 | w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") // Prevent caching 52 | 53 | // Encode config as JSON and send response with error handling 54 | if err := json.NewEncoder(w).Encode(config); err != nil { 55 | http.Error(w, "Failed to encode response", http.StatusInternalServerError) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /internal/api/v1/config_test.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "encoding/json" 5 | "net/http" 6 | "net/http/httptest" 7 | "os" 8 | "testing" 9 | 10 | "github.com/stretchr/testify/assert" 11 | ) 12 | 13 | func TestGetConfig(t *testing.T) { 14 | // Test cases 15 | tests := []struct { 16 | name string 17 | envVars map[string]string 18 | expectedKey string 19 | expectedVal string 20 | }{ 21 | { 22 | name: "Default Config Returns Empty When No Env Vars", 23 | // No env vars set 24 | expectedKey: "", 25 | expectedVal: "", 26 | }, 27 | { 28 | name: "Returns Title From Environment", 29 | envVars: map[string]string{ 30 | "BRAND_TITLE": "Custom Title", 31 | }, 32 | expectedKey: "title", 33 | expectedVal: "Custom Title", 34 | }, 35 | { 36 | name: "Returns Primary Color From Environment", 37 | envVars: map[string]string{ 38 | "BRAND_PRIMARY_COLOR": "#ff0000", 39 | }, 40 | expectedKey: "primaryColor", 41 | expectedVal: "#ff0000", 42 | }, 43 | { 44 | name: "Returns Multiple Config Values", 45 | envVars: map[string]string{ 46 | "BRAND_TITLE": "Custom Title", 47 | "BRAND_DESCRIPTION": "Custom Description", 48 | "BRAND_PRIMARY_COLOR": "#ff0000", 49 | "BRAND_HEADER_TITLE": "Custom Header", 50 | "BRAND_SECONDARY_COLOR": "#00ff00", 51 | }, 52 | expectedKey: "headerTitle", // We'll check just this one 53 | expectedVal: "Custom Header", 54 | }, 55 | } 56 | 57 | // Run tests 58 | for _, tt := range tests { 59 | t.Run(tt.name, func(t *testing.T) { 60 | // Clear environment variables 61 | os.Clearenv() 62 | 63 | // Set environment variables for this test 64 | for k, v := range tt.envVars { 65 | os.Setenv(k, v) 66 | } 67 | 68 | // Create request 69 | req, err := http.NewRequest("GET", "/v1/config", nil) 70 | if err != nil { 71 | t.Fatal(err) 72 | } 73 | 74 | // Create response recorder 75 | rr := httptest.NewRecorder() 76 | handler := http.HandlerFunc(GetConfig) 77 | 78 | // Serve request 79 | handler.ServeHTTP(rr, req) 80 | 81 | // Check status code 82 | assert.Equal(t, http.StatusOK, rr.Code) 83 | 84 | // Check Content-Type 85 | assert.Equal(t, "application/json", rr.Header().Get("Content-Type")) 86 | assert.Equal(t, "no-cache, no-store, must-revalidate", rr.Header().Get("Cache-Control")) 87 | 88 | // If we're not expecting any specific value, just verify it's valid JSON 89 | if tt.expectedKey == "" { 90 | var result map[string]interface{} 91 | err = json.Unmarshal(rr.Body.Bytes(), &result) 92 | assert.NoError(t, err, "Response should be valid JSON") 93 | return 94 | } 95 | 96 | // Parse the response 97 | var result Config 98 | err = json.Unmarshal(rr.Body.Bytes(), &result) 99 | assert.NoError(t, err) 100 | 101 | // Check the specific field we're testing for 102 | switch tt.expectedKey { 103 | case "title": 104 | assert.Equal(t, tt.expectedVal, result.Title) 105 | case "description": 106 | assert.Equal(t, tt.expectedVal, result.Description) 107 | case "keywords": 108 | assert.Equal(t, tt.expectedVal, result.Keywords) 109 | case "author": 110 | assert.Equal(t, tt.expectedVal, result.Author) 111 | case "themeColor": 112 | assert.Equal(t, tt.expectedVal, result.ThemeColor) 113 | case "logoText": 114 | assert.Equal(t, tt.expectedVal, result.LogoText) 115 | case "primaryColor": 116 | assert.Equal(t, tt.expectedVal, result.PrimaryColor) 117 | case "secondaryColor": 118 | assert.Equal(t, tt.expectedVal, result.SecondaryColor) 119 | case "headerTitle": 120 | assert.Equal(t, tt.expectedVal, result.HeaderTitle) 121 | case "footerText": 122 | assert.Equal(t, tt.expectedVal, result.FooterText) 123 | case "footerLink": 124 | assert.Equal(t, tt.expectedVal, result.FooterLink) 125 | } 126 | }) 127 | } 128 | } 129 | 130 | func TestGetConfigMultipleValues(t *testing.T) { 131 | // Clear environment variables 132 | os.Clearenv() 133 | 134 | // Set multiple environment variables 135 | os.Setenv("BRAND_TITLE", "Test Title") 136 | os.Setenv("BRAND_PRIMARY_COLOR", "#ff0000") 137 | os.Setenv("BRAND_SECONDARY_COLOR", "#00ff00") 138 | os.Setenv("BRAND_FOOTER_TEXT", "Custom Footer") 139 | 140 | // Create request 141 | req, err := http.NewRequest("GET", "/v1/config", nil) 142 | if err != nil { 143 | t.Fatal(err) 144 | } 145 | 146 | // Create response recorder 147 | rr := httptest.NewRecorder() 148 | handler := http.HandlerFunc(GetConfig) 149 | 150 | // Serve request 151 | handler.ServeHTTP(rr, req) 152 | 153 | // Check status code 154 | assert.Equal(t, http.StatusOK, rr.Code) 155 | 156 | // Parse the response 157 | var result Config 158 | err = json.Unmarshal(rr.Body.Bytes(), &result) 159 | assert.NoError(t, err) 160 | 161 | // Check all expected values 162 | assert.Equal(t, "Test Title", result.Title) 163 | assert.Equal(t, "#ff0000", result.PrimaryColor) 164 | assert.Equal(t, "#00ff00", result.SecondaryColor) 165 | assert.Equal(t, "Custom Footer", result.FooterText) 166 | 167 | // Check that others are empty 168 | assert.Empty(t, result.Description) 169 | assert.Empty(t, result.Keywords) 170 | } 171 | -------------------------------------------------------------------------------- /internal/api/v1/redirect.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "GoShort/internal/db" 5 | "GoShort/internal/models" 6 | "net/http" 7 | "time" 8 | ) 9 | 10 | // RedirectURL handles redirecting a short URL to its original URL 11 | func RedirectURL(w http.ResponseWriter, r *http.Request) { 12 | shortURL := r.URL.Path[1:] // Extract the short URL from the path 13 | 14 | var url models.URL 15 | if err := db.DB.Where("short_url = ?", shortURL).First(&url).Error; err != nil { 16 | http.NotFound(w, r) 17 | return 18 | } 19 | 20 | // Check for expiration 21 | if url.Expiry != nil && time.Now().After(*url.Expiry) { 22 | http.Error(w, "URL has expired", http.StatusGone) 23 | return 24 | } 25 | 26 | // Redirect to the original URL 27 | http.Redirect(w, r, url.LongURL, http.StatusFound) 28 | } 29 | -------------------------------------------------------------------------------- /internal/api/v1/redirect_test.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "GoShort/internal/models" 5 | "net/http" 6 | "net/http/httptest" 7 | "testing" 8 | "time" 9 | 10 | "github.com/stretchr/testify/assert" 11 | ) 12 | 13 | func mockRedirectURL(shortToURLMap map[string]*models.URL) http.HandlerFunc { 14 | return func(w http.ResponseWriter, r *http.Request) { 15 | shortURL := r.URL.Path[1:] // Extract the short URL from the path 16 | 17 | url, exists := shortToURLMap[shortURL] 18 | if !exists { 19 | http.NotFound(w, r) 20 | return 21 | } 22 | 23 | // Check for expiration 24 | if url.Expiry != nil && time.Now().After(*url.Expiry) { 25 | http.Error(w, "URL has expired", http.StatusGone) 26 | return 27 | } 28 | 29 | // Redirect to the original URL 30 | http.Redirect(w, r, url.LongURL, http.StatusFound) 31 | } 32 | } 33 | 34 | func TestRedirectURL(t *testing.T) { 35 | tests := []struct { 36 | name string 37 | shortURL string 38 | mockData map[string]*models.URL 39 | expectedCode int 40 | expectedHeader string 41 | }{ 42 | { 43 | name: "Valid short URL", 44 | shortURL: "short123", 45 | mockData: map[string]*models.URL{ 46 | "short123": { 47 | ShortURL: "short123", 48 | LongURL: "https://example.com", 49 | }, 50 | }, 51 | expectedCode: http.StatusFound, 52 | expectedHeader: "https://example.com", 53 | }, 54 | { 55 | name: "Short URL not found", 56 | shortURL: "unknown123", 57 | mockData: map[string]*models.URL{}, 58 | expectedCode: http.StatusNotFound, 59 | }, 60 | { 61 | name: "Expired short URL", 62 | shortURL: "expired123", 63 | mockData: map[string]*models.URL{ 64 | "expired123": { 65 | ShortURL: "expired123", 66 | LongURL: "https://example.com", 67 | Expiry: func() *time.Time { t := time.Now().Add(-time.Hour); return &t }(), 68 | }, 69 | }, 70 | expectedCode: http.StatusGone, 71 | }, 72 | } 73 | 74 | for _, tt := range tests { 75 | t.Run(tt.name, func(t *testing.T) { 76 | // Create mock handler 77 | handler := mockRedirectURL(tt.mockData) 78 | 79 | // Create HTTP request and recorder 80 | req := httptest.NewRequest(http.MethodGet, "/"+tt.shortURL, nil) 81 | w := httptest.NewRecorder() 82 | 83 | // Call the mock handler 84 | handler(w, req) 85 | 86 | // Assert response code 87 | res := w.Result() 88 | assert.Equal(t, tt.expectedCode, res.StatusCode) 89 | 90 | // Assert Location header if applicable 91 | if tt.expectedHeader != "" { 92 | header := res.Header.Get("Location") 93 | assert.Equal(t, tt.expectedHeader, header) 94 | } 95 | }) 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /internal/api/v1/shorten.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "GoShort/internal/db" 5 | "GoShort/internal/models" 6 | "GoShort/internal/utils" 7 | "encoding/json" 8 | "net/http" 9 | "regexp" 10 | "time" 11 | ) 12 | 13 | // ShortenRequest represents the request payload for URL shortening 14 | type ShortenRequest struct { 15 | LongURL string `json:"long_url"` 16 | CustomURL string `json:"custom_url,omitempty"` 17 | Expiry string `json:"expiry,omitempty"` // Optional expiry date 18 | } 19 | 20 | // ShortenResponse represents the response payload for URL shortening 21 | type ShortenResponse struct { 22 | ShortURL string `json:"short_url"` 23 | } 24 | 25 | // validateCustomURL ensures the custom URL does not contain spaces or illegal characters 26 | func validateCustomURL(customURL string) bool { 27 | // Define a regex for allowed characters (alphanumeric and dashes/underscores only) 28 | validURLPattern := `^[a-zA-Z0-9_-]+$` 29 | re := regexp.MustCompile(validURLPattern) 30 | return re.MatchString(customURL) 31 | } 32 | 33 | // ShortenURL handles the URL shortening request 34 | func ShortenURL(w http.ResponseWriter, r *http.Request) { 35 | var req ShortenRequest 36 | if err := json.NewDecoder(r.Body).Decode(&req); err != nil { 37 | http.Error(w, "Invalid request payload", http.StatusBadRequest) 38 | return 39 | } 40 | 41 | // Validate the long URL 42 | if !utils.ValidateURL(req.LongURL) { 43 | http.Error(w, "Invalid URL format", http.StatusBadRequest) 44 | return 45 | } 46 | 47 | // Use custom URL if provided, otherwise generate a new one 48 | shortURL := req.CustomURL 49 | if shortURL != "" { 50 | if !validateCustomURL(shortURL) { 51 | http.Error(w, "Custom URL contains invalid characters", http.StatusBadRequest) 52 | return 53 | } 54 | // Check if the custom URL already exists 55 | var existingURL models.URL 56 | if err := db.DB.Where("short_url = ?", shortURL).First(&existingURL).Error; err == nil { 57 | http.Error(w, "Custom URL is already taken", http.StatusConflict) 58 | return 59 | } 60 | } else { 61 | shortURL = utils.GenerateShortURL() 62 | } 63 | 64 | // Parse expiry if provided 65 | var expiry *time.Time 66 | if req.Expiry != "" { 67 | parsedExpiry, err := time.Parse(time.RFC3339, req.Expiry) 68 | if err != nil { 69 | http.Error(w, "Invalid expiry format", http.StatusBadRequest) 70 | return 71 | } 72 | expiry = &parsedExpiry 73 | } 74 | 75 | // Save the URL to the database 76 | url := models.URL{ 77 | LongURL: req.LongURL, 78 | ShortURL: shortURL, 79 | Expiry: expiry, 80 | } 81 | if err := db.DB.Create(&url).Error; err != nil { 82 | http.Error(w, "Failed to save URL", http.StatusInternalServerError) 83 | return 84 | } 85 | 86 | // Return the shortened URL 87 | resp := ShortenResponse{ 88 | ShortURL: shortURL, 89 | } 90 | w.Header().Set("Content-Type", "application/json") 91 | json.NewEncoder(w).Encode(resp) 92 | } 93 | -------------------------------------------------------------------------------- /internal/api/v1/shorten_test.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "GoShort/internal/utils" 5 | "testing" 6 | "time" 7 | 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestValidateURL(t *testing.T) { 12 | validURL := "https://example.com" 13 | invalidURL := "invalid-url" 14 | 15 | assert.True(t, utils.ValidateURL(validURL), "Expected valid URL to pass validation") 16 | assert.False(t, utils.ValidateURL(invalidURL), "Expected invalid URL to fail validation") 17 | } 18 | 19 | func TestGenerateShortURL(t *testing.T) { 20 | shortURL := utils.GenerateShortURL() 21 | assert.NotEmpty(t, shortURL, "Expected generated short URL to be non-empty") 22 | assert.Len(t, shortURL, 8, "Expected generated short URL to have length 8") 23 | } 24 | 25 | func TestParseExpiry(t *testing.T) { 26 | validExpiry := "2025-01-01T12:00:00Z" 27 | invalidExpiry := "not-a-date" 28 | 29 | parsedTime, err := time.Parse(time.RFC3339, validExpiry) 30 | assert.NoError(t, err, "Expected valid expiry to parse without error") 31 | assert.Equal(t, parsedTime.Format(time.RFC3339), validExpiry, "Expected parsed expiry to match input") 32 | 33 | _, err = time.Parse(time.RFC3339, invalidExpiry) 34 | assert.Error(t, err, "Expected invalid expiry to return an error") 35 | } 36 | -------------------------------------------------------------------------------- /internal/db/db.go: -------------------------------------------------------------------------------- 1 | package db 2 | 3 | import ( 4 | "GoShort/internal/models" 5 | "GoShort/pkg/config" 6 | "log" 7 | 8 | "gorm.io/driver/postgres" 9 | "gorm.io/gorm" 10 | ) 11 | 12 | var DB *gorm.DB 13 | 14 | // InitDB initializes the database connection and applies migrations 15 | func InitDB() { 16 | // Load the database connection string from environment variables 17 | dsn := config.Get("DATABASE_URL") 18 | 19 | // Connect to the database 20 | var err error 21 | DB, err = gorm.Open(postgres.Open(dsn), &gorm.Config{}) 22 | if err != nil { 23 | log.Fatalf("Failed to connect to the database: %v", err) 24 | } 25 | 26 | // Apply migrations 27 | log.Println("Running migrations...") 28 | if err := DB.AutoMigrate(&models.URL{}); err != nil { 29 | log.Fatalf("Failed to migrate URL schema: %v", err) 30 | } 31 | log.Println("Migrations completed successfully.") 32 | 33 | log.Println("Database connection initialized successfully.") 34 | } 35 | -------------------------------------------------------------------------------- /internal/db/migrations.go: -------------------------------------------------------------------------------- 1 | package db 2 | 3 | import ( 4 | "log" 5 | ) 6 | 7 | // RunMigrations manually runs any pending database migrations 8 | func RunMigrations() { 9 | if err := DB.Migrator().AutoMigrate(); err != nil { 10 | log.Fatalf("Failed to run migrations: %v", err) 11 | } 12 | log.Println("Database migrations completed successfully.") 13 | } 14 | -------------------------------------------------------------------------------- /internal/models/url.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import "time" 4 | 5 | // URL represents the structure of a shortened URL 6 | type URL struct { 7 | ID uint `gorm:"primaryKey"` 8 | LongURL string `gorm:"not null"` 9 | ShortURL string `gorm:"uniqueIndex;not null"` 10 | CreatedAt time.Time `gorm:"autoCreateTime"` 11 | Expiry *time.Time `gorm:"type:timestamp"` // Optional expiry date 12 | Clicks int `gorm:"default:0"` 13 | } 14 | -------------------------------------------------------------------------------- /internal/utils/urlgen.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "math/rand" 5 | "time" 6 | ) 7 | 8 | const shortURLEncoding = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" 9 | 10 | // GenerateShortURL generates a random short URL path 11 | func GenerateShortURL() string { 12 | length := 8 13 | random := rand.New(rand.NewSource(time.Now().UnixNano())) 14 | result := make([]byte, length) 15 | for i := range result { 16 | result[i] = shortURLEncoding[random.Intn(len(shortURLEncoding))] 17 | } 18 | return string(result) 19 | } 20 | -------------------------------------------------------------------------------- /internal/utils/urlscan.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "errors" 7 | "net/http" 8 | "time" 9 | ) 10 | 11 | // URLScanResponse represents the response from a URL scanning API 12 | type URLScanResponse struct { 13 | Safe bool `json:"safe"` 14 | } 15 | 16 | // CheckMaliciousURL uses an external API to check if a URL is malicious 17 | func CheckMaliciousURL(apiEndpoint, apiKey, urlToScan string) (bool, error) { 18 | client := &http.Client{Timeout: 10 * time.Second} 19 | 20 | // Prepare JSON payload 21 | payload := map[string]string{"url": urlToScan} 22 | payloadBytes, err := json.Marshal(payload) 23 | if err != nil { 24 | return false, err 25 | } 26 | 27 | // Create HTTP request 28 | req, err := http.NewRequest("POST", apiEndpoint, bytes.NewBuffer(payloadBytes)) 29 | if err != nil { 30 | return false, err 31 | } 32 | req.Header.Set("Authorization", "Bearer "+apiKey) 33 | req.Header.Set("Content-Type", "application/json") 34 | 35 | // Send the request 36 | resp, err := client.Do(req) 37 | if err != nil { 38 | return false, err 39 | } 40 | defer resp.Body.Close() 41 | 42 | if resp.StatusCode != http.StatusOK { 43 | return false, errors.New("failed to scan URL: non-200 response") 44 | } 45 | 46 | // Parse the response 47 | var result URLScanResponse 48 | if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { 49 | return false, err 50 | } 51 | 52 | return result.Safe, nil 53 | } 54 | -------------------------------------------------------------------------------- /internal/utils/validation.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "net/url" 5 | "regexp" 6 | ) 7 | 8 | // ValidateURL checks if a given string is a valid URL 9 | func ValidateURL(u string) bool { 10 | parsedURL, err := url.ParseRequestURI(u) 11 | if err != nil || parsedURL.Scheme == "" || parsedURL.Host == "" { 12 | return false 13 | } 14 | return true 15 | } 16 | 17 | // ValidateCustomShortURL checks if the custom short URL path is alphanumeric 18 | func ValidateCustomShortURL(shortURL string) bool { 19 | re := regexp.MustCompile("^[a-zA-Z0-9_-]+$") 20 | return re.MatchString(shortURL) 21 | } 22 | -------------------------------------------------------------------------------- /migrations/migrations.go: -------------------------------------------------------------------------------- 1 | package migrations 2 | 3 | import ( 4 | "GoShort/internal/db" 5 | "log" 6 | 7 | "gorm.io/gorm" 8 | ) 9 | 10 | // Migration defines a structure for database migrations 11 | type Migration struct { 12 | ID string 13 | Migrate func(tx *gorm.DB) error 14 | } 15 | 16 | var migrations = []Migration{ 17 | { 18 | ID: "20240101_create_urls_table", 19 | Migrate: func(tx *gorm.DB) error { 20 | return tx.Exec(` 21 | CREATE TABLE IF NOT EXISTS urls ( 22 | id SERIAL PRIMARY KEY, 23 | long_url TEXT NOT NULL, 24 | short_url TEXT UNIQUE NOT NULL, 25 | created_at TIMESTAMP NOT NULL DEFAULT NOW(), 26 | expiry TIMESTAMP, 27 | user_id INT REFERENCES users(id) ON DELETE CASCADE, 28 | clicks INT NOT NULL DEFAULT 0 29 | ); 30 | `).Error 31 | }, 32 | }, 33 | } 34 | 35 | // RunMigrations applies all pending migrations 36 | func RunMigrations() { 37 | for _, migration := range migrations { 38 | if err := applyMigration(migration); err != nil { 39 | log.Fatalf("Migration failed (ID: %s): %v", migration.ID, err) 40 | } 41 | log.Printf("Migration applied successfully: %s", migration.ID) 42 | } 43 | } 44 | 45 | func applyMigration(migration Migration) error { 46 | log.Printf("Applying migration: %s", migration.ID) 47 | return db.DB.Transaction(migration.Migrate) 48 | } 49 | -------------------------------------------------------------------------------- /nginx.conf: -------------------------------------------------------------------------------- 1 | events { 2 | worker_connections 1024; 3 | } 4 | 5 | http { 6 | include /etc/nginx/mime.types; 7 | default_type application/octet-stream; 8 | 9 | server { 10 | listen 80; 11 | server_name localhost; 12 | 13 | root /usr/share/nginx/html; 14 | index index.html; 15 | 16 | # Serve the frontend 17 | location / { 18 | try_files $uri /index.html; 19 | } 20 | 21 | # Proxy API requests to the backend service 22 | location /api/ { 23 | proxy_pass http://goshort:8080/; 24 | proxy_set_header Host $host; 25 | proxy_set_header X-Real-IP $remote_addr; 26 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 27 | proxy_set_header X-Forwarded-Proto $scheme; 28 | proxy_cache off; 29 | proxy_no_cache 1; 30 | proxy_cache_bypass 1; 31 | } 32 | 33 | # Proxy all other paths (assume they are short URLs) to the backend service 34 | location ~ ^/[a-zA-Z0-9_-]+$ { 35 | proxy_pass http://goshort:8080; 36 | proxy_set_header Host $host; 37 | proxy_set_header X-Real-IP $remote_addr; 38 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 39 | proxy_set_header X-Forwarded-Proto $scheme; 40 | proxy_cache off; 41 | proxy_no_cache 1; 42 | proxy_cache_bypass 1; 43 | } 44 | 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "GoShort", 3 | "lockfileVersion": 3, 4 | "requires": true, 5 | "packages": {} 6 | } 7 | -------------------------------------------------------------------------------- /pkg/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "log" 5 | "os" 6 | 7 | "github.com/joho/godotenv" 8 | ) 9 | 10 | var configMap map[string]string 11 | 12 | // Load loads environment variables from a `.env` file 13 | func Load() { 14 | if err := godotenv.Load(); err != nil { 15 | log.Println("No .env file found, falling back to system environment variables") 16 | } 17 | 18 | configMap = map[string]string{ 19 | "DATABASE_URL": os.Getenv("DATABASE_URL"), 20 | "PORT": os.Getenv("PORT"), 21 | } 22 | } 23 | 24 | // Get retrieves a configuration value by key 25 | func Get(key string) string { 26 | value, exists := configMap[key] 27 | if !exists { 28 | log.Fatalf("Configuration key %s not found", key) 29 | } 30 | return value 31 | } 32 | -------------------------------------------------------------------------------- /pkg/logger/logger.go: -------------------------------------------------------------------------------- 1 | package logger 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/sirupsen/logrus" 7 | ) 8 | 9 | var log *logrus.Logger 10 | 11 | // Init initializes the logger 12 | func Init() { 13 | log = logrus.New() 14 | log.SetOutput(os.Stdout) 15 | log.SetLevel(logrus.InfoLevel) 16 | log.SetFormatter(&logrus.TextFormatter{ 17 | FullTimestamp: true, 18 | }) 19 | } 20 | 21 | // Info logs an informational message 22 | func Info(message string, fields map[string]interface{}) { 23 | if fields != nil { 24 | log.WithFields(fields).Info(message) 25 | } else { 26 | log.Info(message) 27 | } 28 | } 29 | 30 | // Error logs an error message 31 | func Error(message string, fields map[string]interface{}) { 32 | if fields != nil { 33 | log.WithFields(fields).Error(message) 34 | } else { 35 | log.Error(message) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /supervisord.conf: -------------------------------------------------------------------------------- 1 | [supervisord] 2 | nodaemon=true 3 | user=root 4 | logfile=/var/log/supervisord.log 5 | logfile_maxbytes=50MB 6 | logfile_backups=10 7 | loglevel=info 8 | pidfile=/var/run/supervisord.pid 9 | identifier=supervisor 10 | 11 | [program:goshort] 12 | command=/app/goshort 13 | directory=/app 14 | environment=APP_ENV=production,APP_LOG_LEVEL=info 15 | autorestart=true 16 | startsecs=3 17 | stdout_logfile=/var/log/goshort_stdout.log 18 | stderr_logfile=/var/log/goshort_stderr.log 19 | stdout_logfile_maxbytes=10MB 20 | stderr_logfile_maxbytes=10MB 21 | stdout_logfile_backups=5 22 | stderr_logfile_backups=5 23 | user=nobody 24 | umask=022 25 | stopsignal=TERM 26 | 27 | [program:nginx] 28 | command=nginx -g "daemon off;" 29 | autorestart=true 30 | startsecs=3 31 | stdout_logfile=/var/log/nginx_stdout.log 32 | stderr_logfile=/var/log/nginx_stderr.log 33 | stdout_logfile_maxbytes=10MB 34 | stderr_logfile_maxbytes=10MB 35 | stdout_logfile_backups=5 36 | stderr_logfile_backups=5 37 | user=nginx 38 | stopsignal=QUIT 39 | -------------------------------------------------------------------------------- /version.yaml: -------------------------------------------------------------------------------- 1 | #Application version following https://semver.org/ 2 | version: 1.0.2 -------------------------------------------------------------------------------- /web/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | # Output 4 | .output 5 | .vercel 6 | .netlify 7 | .wrangler 8 | /.svelte-kit 9 | /build 10 | 11 | # OS 12 | .DS_Store 13 | Thumbs.db 14 | 15 | # Env 16 | .env 17 | .env.* 18 | !.env.example 19 | !.env.test 20 | 21 | # Vite 22 | vite.config.js.timestamp-* 23 | vite.config.ts.timestamp-* 24 | -------------------------------------------------------------------------------- /web/.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /web/.prettierignore: -------------------------------------------------------------------------------- 1 | # Package Managers 2 | package-lock.json 3 | pnpm-lock.yaml 4 | yarn.lock 5 | -------------------------------------------------------------------------------- /web/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": true, 3 | "singleQuote": true, 4 | "trailingComma": "none", 5 | "printWidth": 100, 6 | "plugins": ["prettier-plugin-svelte"], 7 | "overrides": [ 8 | { 9 | "files": "*.svelte", 10 | "options": { 11 | "parser": "svelte" 12 | } 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /web/README.md: -------------------------------------------------------------------------------- 1 | ## Developing 2 | 3 | Once you've clone the project and installed dependencies with `npm install` , start a development server: 4 | 5 | ```bash 6 | npm run dev 7 | 8 | # or start the server and open the app in a new browser tab 9 | npm run dev -- --open 10 | ``` 11 | 12 | ## Building 13 | 14 | To create a production version of your app: 15 | 16 | ```bash 17 | npm run build 18 | ``` 19 | 20 | You can preview the production build with `npm run preview`. 21 | -------------------------------------------------------------------------------- /web/eslint.config.js: -------------------------------------------------------------------------------- 1 | import prettier from 'eslint-config-prettier'; 2 | import js from '@eslint/js'; 3 | import { includeIgnoreFile } from '@eslint/compat'; 4 | import svelte from 'eslint-plugin-svelte'; 5 | import globals from 'globals'; 6 | import { fileURLToPath } from 'node:url'; 7 | const gitignorePath = fileURLToPath(new URL('./.gitignore', import.meta.url)); 8 | 9 | /** @type {import('eslint').Linter.Config[]} */ 10 | export default [ 11 | includeIgnoreFile(gitignorePath), 12 | js.configs.recommended, 13 | ...svelte.configs['flat/recommended'], 14 | prettier, 15 | ...svelte.configs['flat/prettier'], 16 | { 17 | languageOptions: { 18 | globals: { 19 | ...globals.browser, 20 | ...globals.node 21 | } 22 | } 23 | } 24 | ]; 25 | -------------------------------------------------------------------------------- /web/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.svelte-kit/tsconfig.json", 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "checkJs": false, 6 | "moduleResolution": "bundler" 7 | } 8 | // Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias 9 | // except $lib which is handled by https://svelte.dev/docs/kit/configuration#files 10 | // 11 | // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes 12 | // from the referenced tsconfig.json - TypeScript does not merge them in 13 | } 14 | -------------------------------------------------------------------------------- /web/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "web", 3 | "version": "0.0.1", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "web", 9 | "version": "0.0.1", 10 | "dependencies": { 11 | "@tailwindcss/container-queries": "^0.1.1", 12 | "@tailwindcss/forms": "^0.5.9", 13 | "@tailwindcss/typography": "^0.5.15" 14 | }, 15 | "devDependencies": { 16 | "@eslint/compat": "^1.2.3", 17 | "@sveltejs/adapter-auto": "^3.0.0", 18 | "@sveltejs/adapter-static": "^3.0.8", 19 | "@sveltejs/kit": "^2.0.0", 20 | "@sveltejs/vite-plugin-svelte": "^5.0.3", 21 | "autoprefixer": "^10.4.20", 22 | "eslint": "^9.7.0", 23 | "eslint-config-prettier": "^9.1.0", 24 | "eslint-plugin-svelte": "^2.36.0", 25 | "globals": "^15.0.0", 26 | "prettier": "^3.3.2", 27 | "prettier-plugin-svelte": "^3.2.6", 28 | "svelte": "^5.0.0", 29 | "tailwindcss": "^3.4.9", 30 | "vite": "^6.2.2" 31 | } 32 | }, 33 | "node_modules/@alloc/quick-lru": { 34 | "version": "5.2.0", 35 | "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", 36 | "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", 37 | "engines": { 38 | "node": ">=10" 39 | }, 40 | "funding": { 41 | "url": "https://github.com/sponsors/sindresorhus" 42 | } 43 | }, 44 | "node_modules/@ampproject/remapping": { 45 | "version": "2.3.0", 46 | "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", 47 | "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", 48 | "dev": true, 49 | "dependencies": { 50 | "@jridgewell/gen-mapping": "^0.3.5", 51 | "@jridgewell/trace-mapping": "^0.3.24" 52 | }, 53 | "engines": { 54 | "node": ">=6.0.0" 55 | } 56 | }, 57 | "node_modules/@esbuild/aix-ppc64": { 58 | "version": "0.25.1", 59 | "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.1.tgz", 60 | "integrity": "sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==", 61 | "cpu": [ 62 | "ppc64" 63 | ], 64 | "dev": true, 65 | "license": "MIT", 66 | "optional": true, 67 | "os": [ 68 | "aix" 69 | ], 70 | "engines": { 71 | "node": ">=18" 72 | } 73 | }, 74 | "node_modules/@esbuild/android-arm": { 75 | "version": "0.25.1", 76 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.1.tgz", 77 | "integrity": "sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q==", 78 | "cpu": [ 79 | "arm" 80 | ], 81 | "dev": true, 82 | "license": "MIT", 83 | "optional": true, 84 | "os": [ 85 | "android" 86 | ], 87 | "engines": { 88 | "node": ">=18" 89 | } 90 | }, 91 | "node_modules/@esbuild/android-arm64": { 92 | "version": "0.25.1", 93 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.1.tgz", 94 | "integrity": "sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA==", 95 | "cpu": [ 96 | "arm64" 97 | ], 98 | "dev": true, 99 | "license": "MIT", 100 | "optional": true, 101 | "os": [ 102 | "android" 103 | ], 104 | "engines": { 105 | "node": ">=18" 106 | } 107 | }, 108 | "node_modules/@esbuild/android-x64": { 109 | "version": "0.25.1", 110 | "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.1.tgz", 111 | "integrity": "sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw==", 112 | "cpu": [ 113 | "x64" 114 | ], 115 | "dev": true, 116 | "license": "MIT", 117 | "optional": true, 118 | "os": [ 119 | "android" 120 | ], 121 | "engines": { 122 | "node": ">=18" 123 | } 124 | }, 125 | "node_modules/@esbuild/darwin-arm64": { 126 | "version": "0.25.1", 127 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.1.tgz", 128 | "integrity": "sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==", 129 | "cpu": [ 130 | "arm64" 131 | ], 132 | "dev": true, 133 | "license": "MIT", 134 | "optional": true, 135 | "os": [ 136 | "darwin" 137 | ], 138 | "engines": { 139 | "node": ">=18" 140 | } 141 | }, 142 | "node_modules/@esbuild/darwin-x64": { 143 | "version": "0.25.1", 144 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.1.tgz", 145 | "integrity": "sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA==", 146 | "cpu": [ 147 | "x64" 148 | ], 149 | "dev": true, 150 | "license": "MIT", 151 | "optional": true, 152 | "os": [ 153 | "darwin" 154 | ], 155 | "engines": { 156 | "node": ">=18" 157 | } 158 | }, 159 | "node_modules/@esbuild/freebsd-arm64": { 160 | "version": "0.25.1", 161 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.1.tgz", 162 | "integrity": "sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A==", 163 | "cpu": [ 164 | "arm64" 165 | ], 166 | "dev": true, 167 | "license": "MIT", 168 | "optional": true, 169 | "os": [ 170 | "freebsd" 171 | ], 172 | "engines": { 173 | "node": ">=18" 174 | } 175 | }, 176 | "node_modules/@esbuild/freebsd-x64": { 177 | "version": "0.25.1", 178 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.1.tgz", 179 | "integrity": "sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww==", 180 | "cpu": [ 181 | "x64" 182 | ], 183 | "dev": true, 184 | "license": "MIT", 185 | "optional": true, 186 | "os": [ 187 | "freebsd" 188 | ], 189 | "engines": { 190 | "node": ">=18" 191 | } 192 | }, 193 | "node_modules/@esbuild/linux-arm": { 194 | "version": "0.25.1", 195 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.1.tgz", 196 | "integrity": "sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ==", 197 | "cpu": [ 198 | "arm" 199 | ], 200 | "dev": true, 201 | "license": "MIT", 202 | "optional": true, 203 | "os": [ 204 | "linux" 205 | ], 206 | "engines": { 207 | "node": ">=18" 208 | } 209 | }, 210 | "node_modules/@esbuild/linux-arm64": { 211 | "version": "0.25.1", 212 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.1.tgz", 213 | "integrity": "sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ==", 214 | "cpu": [ 215 | "arm64" 216 | ], 217 | "dev": true, 218 | "license": "MIT", 219 | "optional": true, 220 | "os": [ 221 | "linux" 222 | ], 223 | "engines": { 224 | "node": ">=18" 225 | } 226 | }, 227 | "node_modules/@esbuild/linux-ia32": { 228 | "version": "0.25.1", 229 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.1.tgz", 230 | "integrity": "sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ==", 231 | "cpu": [ 232 | "ia32" 233 | ], 234 | "dev": true, 235 | "license": "MIT", 236 | "optional": true, 237 | "os": [ 238 | "linux" 239 | ], 240 | "engines": { 241 | "node": ">=18" 242 | } 243 | }, 244 | "node_modules/@esbuild/linux-loong64": { 245 | "version": "0.25.1", 246 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.1.tgz", 247 | "integrity": "sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg==", 248 | "cpu": [ 249 | "loong64" 250 | ], 251 | "dev": true, 252 | "license": "MIT", 253 | "optional": true, 254 | "os": [ 255 | "linux" 256 | ], 257 | "engines": { 258 | "node": ">=18" 259 | } 260 | }, 261 | "node_modules/@esbuild/linux-mips64el": { 262 | "version": "0.25.1", 263 | "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.1.tgz", 264 | "integrity": "sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg==", 265 | "cpu": [ 266 | "mips64el" 267 | ], 268 | "dev": true, 269 | "license": "MIT", 270 | "optional": true, 271 | "os": [ 272 | "linux" 273 | ], 274 | "engines": { 275 | "node": ">=18" 276 | } 277 | }, 278 | "node_modules/@esbuild/linux-ppc64": { 279 | "version": "0.25.1", 280 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.1.tgz", 281 | "integrity": "sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg==", 282 | "cpu": [ 283 | "ppc64" 284 | ], 285 | "dev": true, 286 | "license": "MIT", 287 | "optional": true, 288 | "os": [ 289 | "linux" 290 | ], 291 | "engines": { 292 | "node": ">=18" 293 | } 294 | }, 295 | "node_modules/@esbuild/linux-riscv64": { 296 | "version": "0.25.1", 297 | "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.1.tgz", 298 | "integrity": "sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==", 299 | "cpu": [ 300 | "riscv64" 301 | ], 302 | "dev": true, 303 | "license": "MIT", 304 | "optional": true, 305 | "os": [ 306 | "linux" 307 | ], 308 | "engines": { 309 | "node": ">=18" 310 | } 311 | }, 312 | "node_modules/@esbuild/linux-s390x": { 313 | "version": "0.25.1", 314 | "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.1.tgz", 315 | "integrity": "sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==", 316 | "cpu": [ 317 | "s390x" 318 | ], 319 | "dev": true, 320 | "license": "MIT", 321 | "optional": true, 322 | "os": [ 323 | "linux" 324 | ], 325 | "engines": { 326 | "node": ">=18" 327 | } 328 | }, 329 | "node_modules/@esbuild/linux-x64": { 330 | "version": "0.25.1", 331 | "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.1.tgz", 332 | "integrity": "sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==", 333 | "cpu": [ 334 | "x64" 335 | ], 336 | "dev": true, 337 | "license": "MIT", 338 | "optional": true, 339 | "os": [ 340 | "linux" 341 | ], 342 | "engines": { 343 | "node": ">=18" 344 | } 345 | }, 346 | "node_modules/@esbuild/netbsd-arm64": { 347 | "version": "0.25.1", 348 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.1.tgz", 349 | "integrity": "sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g==", 350 | "cpu": [ 351 | "arm64" 352 | ], 353 | "dev": true, 354 | "license": "MIT", 355 | "optional": true, 356 | "os": [ 357 | "netbsd" 358 | ], 359 | "engines": { 360 | "node": ">=18" 361 | } 362 | }, 363 | "node_modules/@esbuild/netbsd-x64": { 364 | "version": "0.25.1", 365 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.1.tgz", 366 | "integrity": "sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA==", 367 | "cpu": [ 368 | "x64" 369 | ], 370 | "dev": true, 371 | "license": "MIT", 372 | "optional": true, 373 | "os": [ 374 | "netbsd" 375 | ], 376 | "engines": { 377 | "node": ">=18" 378 | } 379 | }, 380 | "node_modules/@esbuild/openbsd-arm64": { 381 | "version": "0.25.1", 382 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.1.tgz", 383 | "integrity": "sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg==", 384 | "cpu": [ 385 | "arm64" 386 | ], 387 | "dev": true, 388 | "license": "MIT", 389 | "optional": true, 390 | "os": [ 391 | "openbsd" 392 | ], 393 | "engines": { 394 | "node": ">=18" 395 | } 396 | }, 397 | "node_modules/@esbuild/openbsd-x64": { 398 | "version": "0.25.1", 399 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.1.tgz", 400 | "integrity": "sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw==", 401 | "cpu": [ 402 | "x64" 403 | ], 404 | "dev": true, 405 | "license": "MIT", 406 | "optional": true, 407 | "os": [ 408 | "openbsd" 409 | ], 410 | "engines": { 411 | "node": ">=18" 412 | } 413 | }, 414 | "node_modules/@esbuild/sunos-x64": { 415 | "version": "0.25.1", 416 | "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.1.tgz", 417 | "integrity": "sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg==", 418 | "cpu": [ 419 | "x64" 420 | ], 421 | "dev": true, 422 | "license": "MIT", 423 | "optional": true, 424 | "os": [ 425 | "sunos" 426 | ], 427 | "engines": { 428 | "node": ">=18" 429 | } 430 | }, 431 | "node_modules/@esbuild/win32-arm64": { 432 | "version": "0.25.1", 433 | "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.1.tgz", 434 | "integrity": "sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ==", 435 | "cpu": [ 436 | "arm64" 437 | ], 438 | "dev": true, 439 | "license": "MIT", 440 | "optional": true, 441 | "os": [ 442 | "win32" 443 | ], 444 | "engines": { 445 | "node": ">=18" 446 | } 447 | }, 448 | "node_modules/@esbuild/win32-ia32": { 449 | "version": "0.25.1", 450 | "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.1.tgz", 451 | "integrity": "sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A==", 452 | "cpu": [ 453 | "ia32" 454 | ], 455 | "dev": true, 456 | "license": "MIT", 457 | "optional": true, 458 | "os": [ 459 | "win32" 460 | ], 461 | "engines": { 462 | "node": ">=18" 463 | } 464 | }, 465 | "node_modules/@esbuild/win32-x64": { 466 | "version": "0.25.1", 467 | "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.1.tgz", 468 | "integrity": "sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg==", 469 | "cpu": [ 470 | "x64" 471 | ], 472 | "dev": true, 473 | "license": "MIT", 474 | "optional": true, 475 | "os": [ 476 | "win32" 477 | ], 478 | "engines": { 479 | "node": ">=18" 480 | } 481 | }, 482 | "node_modules/@eslint-community/eslint-utils": { 483 | "version": "4.4.1", 484 | "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", 485 | "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", 486 | "dev": true, 487 | "dependencies": { 488 | "eslint-visitor-keys": "^3.4.3" 489 | }, 490 | "engines": { 491 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 492 | }, 493 | "funding": { 494 | "url": "https://opencollective.com/eslint" 495 | }, 496 | "peerDependencies": { 497 | "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" 498 | } 499 | }, 500 | "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { 501 | "version": "3.4.3", 502 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", 503 | "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", 504 | "dev": true, 505 | "engines": { 506 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 507 | }, 508 | "funding": { 509 | "url": "https://opencollective.com/eslint" 510 | } 511 | }, 512 | "node_modules/@eslint-community/regexpp": { 513 | "version": "4.12.1", 514 | "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", 515 | "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", 516 | "dev": true, 517 | "engines": { 518 | "node": "^12.0.0 || ^14.0.0 || >=16.0.0" 519 | } 520 | }, 521 | "node_modules/@eslint/compat": { 522 | "version": "1.2.4", 523 | "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.2.4.tgz", 524 | "integrity": "sha512-S8ZdQj/N69YAtuqFt7653jwcvuUj131+6qGLUyDqfDg1OIoBQ66OCuXC473YQfO2AaxITTutiRQiDwoo7ZLYyg==", 525 | "dev": true, 526 | "engines": { 527 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 528 | }, 529 | "peerDependencies": { 530 | "eslint": "^9.10.0" 531 | }, 532 | "peerDependenciesMeta": { 533 | "eslint": { 534 | "optional": true 535 | } 536 | } 537 | }, 538 | "node_modules/@eslint/config-array": { 539 | "version": "0.19.1", 540 | "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.1.tgz", 541 | "integrity": "sha512-fo6Mtm5mWyKjA/Chy1BYTdn5mGJoDNjC7C64ug20ADsRDGrA85bN3uK3MaKbeRkRuuIEAR5N33Jr1pbm411/PA==", 542 | "dev": true, 543 | "dependencies": { 544 | "@eslint/object-schema": "^2.1.5", 545 | "debug": "^4.3.1", 546 | "minimatch": "^3.1.2" 547 | }, 548 | "engines": { 549 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 550 | } 551 | }, 552 | "node_modules/@eslint/core": { 553 | "version": "0.9.1", 554 | "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.9.1.tgz", 555 | "integrity": "sha512-GuUdqkyyzQI5RMIWkHhvTWLCyLo1jNK3vzkSyaExH5kHPDHcuL2VOpHjmMY+y3+NC69qAKToBqldTBgYeLSr9Q==", 556 | "dev": true, 557 | "dependencies": { 558 | "@types/json-schema": "^7.0.15" 559 | }, 560 | "engines": { 561 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 562 | } 563 | }, 564 | "node_modules/@eslint/eslintrc": { 565 | "version": "3.2.0", 566 | "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", 567 | "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", 568 | "dev": true, 569 | "dependencies": { 570 | "ajv": "^6.12.4", 571 | "debug": "^4.3.2", 572 | "espree": "^10.0.1", 573 | "globals": "^14.0.0", 574 | "ignore": "^5.2.0", 575 | "import-fresh": "^3.2.1", 576 | "js-yaml": "^4.1.0", 577 | "minimatch": "^3.1.2", 578 | "strip-json-comments": "^3.1.1" 579 | }, 580 | "engines": { 581 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 582 | }, 583 | "funding": { 584 | "url": "https://opencollective.com/eslint" 585 | } 586 | }, 587 | "node_modules/@eslint/eslintrc/node_modules/globals": { 588 | "version": "14.0.0", 589 | "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", 590 | "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", 591 | "dev": true, 592 | "engines": { 593 | "node": ">=18" 594 | }, 595 | "funding": { 596 | "url": "https://github.com/sponsors/sindresorhus" 597 | } 598 | }, 599 | "node_modules/@eslint/js": { 600 | "version": "9.17.0", 601 | "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.17.0.tgz", 602 | "integrity": "sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==", 603 | "dev": true, 604 | "engines": { 605 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 606 | } 607 | }, 608 | "node_modules/@eslint/object-schema": { 609 | "version": "2.1.5", 610 | "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.5.tgz", 611 | "integrity": "sha512-o0bhxnL89h5Bae5T318nFoFzGy+YE5i/gGkoPAgkmTVdRKTiv3p8JHevPiPaMwoloKfEiiaHlawCqaZMqRm+XQ==", 612 | "dev": true, 613 | "engines": { 614 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 615 | } 616 | }, 617 | "node_modules/@eslint/plugin-kit": { 618 | "version": "0.2.4", 619 | "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.4.tgz", 620 | "integrity": "sha512-zSkKow6H5Kdm0ZUQUB2kV5JIXqoG0+uH5YADhaEHswm664N9Db8dXSi0nMJpacpMf+MyyglF1vnZohpEg5yUtg==", 621 | "dev": true, 622 | "dependencies": { 623 | "levn": "^0.4.1" 624 | }, 625 | "engines": { 626 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 627 | } 628 | }, 629 | "node_modules/@humanfs/core": { 630 | "version": "0.19.1", 631 | "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", 632 | "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", 633 | "dev": true, 634 | "engines": { 635 | "node": ">=18.18.0" 636 | } 637 | }, 638 | "node_modules/@humanfs/node": { 639 | "version": "0.16.6", 640 | "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", 641 | "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", 642 | "dev": true, 643 | "dependencies": { 644 | "@humanfs/core": "^0.19.1", 645 | "@humanwhocodes/retry": "^0.3.0" 646 | }, 647 | "engines": { 648 | "node": ">=18.18.0" 649 | } 650 | }, 651 | "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { 652 | "version": "0.3.1", 653 | "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", 654 | "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", 655 | "dev": true, 656 | "engines": { 657 | "node": ">=18.18" 658 | }, 659 | "funding": { 660 | "type": "github", 661 | "url": "https://github.com/sponsors/nzakas" 662 | } 663 | }, 664 | "node_modules/@humanwhocodes/module-importer": { 665 | "version": "1.0.1", 666 | "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", 667 | "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", 668 | "dev": true, 669 | "engines": { 670 | "node": ">=12.22" 671 | }, 672 | "funding": { 673 | "type": "github", 674 | "url": "https://github.com/sponsors/nzakas" 675 | } 676 | }, 677 | "node_modules/@humanwhocodes/retry": { 678 | "version": "0.4.1", 679 | "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz", 680 | "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", 681 | "dev": true, 682 | "engines": { 683 | "node": ">=18.18" 684 | }, 685 | "funding": { 686 | "type": "github", 687 | "url": "https://github.com/sponsors/nzakas" 688 | } 689 | }, 690 | "node_modules/@isaacs/cliui": { 691 | "version": "8.0.2", 692 | "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", 693 | "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", 694 | "dependencies": { 695 | "string-width": "^5.1.2", 696 | "string-width-cjs": "npm:string-width@^4.2.0", 697 | "strip-ansi": "^7.0.1", 698 | "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", 699 | "wrap-ansi": "^8.1.0", 700 | "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" 701 | }, 702 | "engines": { 703 | "node": ">=12" 704 | } 705 | }, 706 | "node_modules/@jridgewell/gen-mapping": { 707 | "version": "0.3.8", 708 | "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", 709 | "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", 710 | "dependencies": { 711 | "@jridgewell/set-array": "^1.2.1", 712 | "@jridgewell/sourcemap-codec": "^1.4.10", 713 | "@jridgewell/trace-mapping": "^0.3.24" 714 | }, 715 | "engines": { 716 | "node": ">=6.0.0" 717 | } 718 | }, 719 | "node_modules/@jridgewell/resolve-uri": { 720 | "version": "3.1.2", 721 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", 722 | "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", 723 | "engines": { 724 | "node": ">=6.0.0" 725 | } 726 | }, 727 | "node_modules/@jridgewell/set-array": { 728 | "version": "1.2.1", 729 | "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", 730 | "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", 731 | "engines": { 732 | "node": ">=6.0.0" 733 | } 734 | }, 735 | "node_modules/@jridgewell/sourcemap-codec": { 736 | "version": "1.5.0", 737 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", 738 | "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" 739 | }, 740 | "node_modules/@jridgewell/trace-mapping": { 741 | "version": "0.3.25", 742 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", 743 | "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", 744 | "dependencies": { 745 | "@jridgewell/resolve-uri": "^3.1.0", 746 | "@jridgewell/sourcemap-codec": "^1.4.14" 747 | } 748 | }, 749 | "node_modules/@nodelib/fs.scandir": { 750 | "version": "2.1.5", 751 | "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", 752 | "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", 753 | "dependencies": { 754 | "@nodelib/fs.stat": "2.0.5", 755 | "run-parallel": "^1.1.9" 756 | }, 757 | "engines": { 758 | "node": ">= 8" 759 | } 760 | }, 761 | "node_modules/@nodelib/fs.stat": { 762 | "version": "2.0.5", 763 | "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", 764 | "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", 765 | "engines": { 766 | "node": ">= 8" 767 | } 768 | }, 769 | "node_modules/@nodelib/fs.walk": { 770 | "version": "1.2.8", 771 | "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", 772 | "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", 773 | "dependencies": { 774 | "@nodelib/fs.scandir": "2.1.5", 775 | "fastq": "^1.6.0" 776 | }, 777 | "engines": { 778 | "node": ">= 8" 779 | } 780 | }, 781 | "node_modules/@pkgjs/parseargs": { 782 | "version": "0.11.0", 783 | "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", 784 | "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", 785 | "optional": true, 786 | "engines": { 787 | "node": ">=14" 788 | } 789 | }, 790 | "node_modules/@polka/url": { 791 | "version": "1.0.0-next.28", 792 | "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.28.tgz", 793 | "integrity": "sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==", 794 | "dev": true 795 | }, 796 | "node_modules/@rollup/rollup-android-arm-eabi": { 797 | "version": "4.35.0", 798 | "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.35.0.tgz", 799 | "integrity": "sha512-uYQ2WfPaqz5QtVgMxfN6NpLD+no0MYHDBywl7itPYd3K5TjjSghNKmX8ic9S8NU8w81NVhJv/XojcHptRly7qQ==", 800 | "cpu": [ 801 | "arm" 802 | ], 803 | "dev": true, 804 | "license": "MIT", 805 | "optional": true, 806 | "os": [ 807 | "android" 808 | ] 809 | }, 810 | "node_modules/@rollup/rollup-android-arm64": { 811 | "version": "4.35.0", 812 | "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.35.0.tgz", 813 | "integrity": "sha512-FtKddj9XZudurLhdJnBl9fl6BwCJ3ky8riCXjEw3/UIbjmIY58ppWwPEvU3fNu+W7FUsAsB1CdH+7EQE6CXAPA==", 814 | "cpu": [ 815 | "arm64" 816 | ], 817 | "dev": true, 818 | "license": "MIT", 819 | "optional": true, 820 | "os": [ 821 | "android" 822 | ] 823 | }, 824 | "node_modules/@rollup/rollup-darwin-arm64": { 825 | "version": "4.35.0", 826 | "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.35.0.tgz", 827 | "integrity": "sha512-Uk+GjOJR6CY844/q6r5DR/6lkPFOw0hjfOIzVx22THJXMxktXG6CbejseJFznU8vHcEBLpiXKY3/6xc+cBm65Q==", 828 | "cpu": [ 829 | "arm64" 830 | ], 831 | "dev": true, 832 | "license": "MIT", 833 | "optional": true, 834 | "os": [ 835 | "darwin" 836 | ] 837 | }, 838 | "node_modules/@rollup/rollup-darwin-x64": { 839 | "version": "4.35.0", 840 | "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.35.0.tgz", 841 | "integrity": "sha512-3IrHjfAS6Vkp+5bISNQnPogRAW5GAV1n+bNCrDwXmfMHbPl5EhTmWtfmwlJxFRUCBZ+tZ/OxDyU08aF6NI/N5Q==", 842 | "cpu": [ 843 | "x64" 844 | ], 845 | "dev": true, 846 | "license": "MIT", 847 | "optional": true, 848 | "os": [ 849 | "darwin" 850 | ] 851 | }, 852 | "node_modules/@rollup/rollup-freebsd-arm64": { 853 | "version": "4.35.0", 854 | "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.35.0.tgz", 855 | "integrity": "sha512-sxjoD/6F9cDLSELuLNnY0fOrM9WA0KrM0vWm57XhrIMf5FGiN8D0l7fn+bpUeBSU7dCgPV2oX4zHAsAXyHFGcQ==", 856 | "cpu": [ 857 | "arm64" 858 | ], 859 | "dev": true, 860 | "license": "MIT", 861 | "optional": true, 862 | "os": [ 863 | "freebsd" 864 | ] 865 | }, 866 | "node_modules/@rollup/rollup-freebsd-x64": { 867 | "version": "4.35.0", 868 | "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.35.0.tgz", 869 | "integrity": "sha512-2mpHCeRuD1u/2kruUiHSsnjWtHjqVbzhBkNVQ1aVD63CcexKVcQGwJ2g5VphOd84GvxfSvnnlEyBtQCE5hxVVw==", 870 | "cpu": [ 871 | "x64" 872 | ], 873 | "dev": true, 874 | "license": "MIT", 875 | "optional": true, 876 | "os": [ 877 | "freebsd" 878 | ] 879 | }, 880 | "node_modules/@rollup/rollup-linux-arm-gnueabihf": { 881 | "version": "4.35.0", 882 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.35.0.tgz", 883 | "integrity": "sha512-mrA0v3QMy6ZSvEuLs0dMxcO2LnaCONs1Z73GUDBHWbY8tFFocM6yl7YyMu7rz4zS81NDSqhrUuolyZXGi8TEqg==", 884 | "cpu": [ 885 | "arm" 886 | ], 887 | "dev": true, 888 | "license": "MIT", 889 | "optional": true, 890 | "os": [ 891 | "linux" 892 | ] 893 | }, 894 | "node_modules/@rollup/rollup-linux-arm-musleabihf": { 895 | "version": "4.35.0", 896 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.35.0.tgz", 897 | "integrity": "sha512-DnYhhzcvTAKNexIql8pFajr0PiDGrIsBYPRvCKlA5ixSS3uwo/CWNZxB09jhIapEIg945KOzcYEAGGSmTSpk7A==", 898 | "cpu": [ 899 | "arm" 900 | ], 901 | "dev": true, 902 | "license": "MIT", 903 | "optional": true, 904 | "os": [ 905 | "linux" 906 | ] 907 | }, 908 | "node_modules/@rollup/rollup-linux-arm64-gnu": { 909 | "version": "4.35.0", 910 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.35.0.tgz", 911 | "integrity": "sha512-uagpnH2M2g2b5iLsCTZ35CL1FgyuzzJQ8L9VtlJ+FckBXroTwNOaD0z0/UF+k5K3aNQjbm8LIVpxykUOQt1m/A==", 912 | "cpu": [ 913 | "arm64" 914 | ], 915 | "dev": true, 916 | "license": "MIT", 917 | "optional": true, 918 | "os": [ 919 | "linux" 920 | ] 921 | }, 922 | "node_modules/@rollup/rollup-linux-arm64-musl": { 923 | "version": "4.35.0", 924 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.35.0.tgz", 925 | "integrity": "sha512-XQxVOCd6VJeHQA/7YcqyV0/88N6ysSVzRjJ9I9UA/xXpEsjvAgDTgH3wQYz5bmr7SPtVK2TsP2fQ2N9L4ukoUg==", 926 | "cpu": [ 927 | "arm64" 928 | ], 929 | "dev": true, 930 | "license": "MIT", 931 | "optional": true, 932 | "os": [ 933 | "linux" 934 | ] 935 | }, 936 | "node_modules/@rollup/rollup-linux-loongarch64-gnu": { 937 | "version": "4.35.0", 938 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.35.0.tgz", 939 | "integrity": "sha512-5pMT5PzfgwcXEwOaSrqVsz/LvjDZt+vQ8RT/70yhPU06PTuq8WaHhfT1LW+cdD7mW6i/J5/XIkX/1tCAkh1W6g==", 940 | "cpu": [ 941 | "loong64" 942 | ], 943 | "dev": true, 944 | "license": "MIT", 945 | "optional": true, 946 | "os": [ 947 | "linux" 948 | ] 949 | }, 950 | "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { 951 | "version": "4.35.0", 952 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.35.0.tgz", 953 | "integrity": "sha512-c+zkcvbhbXF98f4CtEIP1EBA/lCic5xB0lToneZYvMeKu5Kamq3O8gqrxiYYLzlZH6E3Aq+TSW86E4ay8iD8EA==", 954 | "cpu": [ 955 | "ppc64" 956 | ], 957 | "dev": true, 958 | "license": "MIT", 959 | "optional": true, 960 | "os": [ 961 | "linux" 962 | ] 963 | }, 964 | "node_modules/@rollup/rollup-linux-riscv64-gnu": { 965 | "version": "4.35.0", 966 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.35.0.tgz", 967 | "integrity": "sha512-s91fuAHdOwH/Tad2tzTtPX7UZyytHIRR6V4+2IGlV0Cej5rkG0R61SX4l4y9sh0JBibMiploZx3oHKPnQBKe4g==", 968 | "cpu": [ 969 | "riscv64" 970 | ], 971 | "dev": true, 972 | "license": "MIT", 973 | "optional": true, 974 | "os": [ 975 | "linux" 976 | ] 977 | }, 978 | "node_modules/@rollup/rollup-linux-s390x-gnu": { 979 | "version": "4.35.0", 980 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.35.0.tgz", 981 | "integrity": "sha512-hQRkPQPLYJZYGP+Hj4fR9dDBMIM7zrzJDWFEMPdTnTy95Ljnv0/4w/ixFw3pTBMEuuEuoqtBINYND4M7ujcuQw==", 982 | "cpu": [ 983 | "s390x" 984 | ], 985 | "dev": true, 986 | "license": "MIT", 987 | "optional": true, 988 | "os": [ 989 | "linux" 990 | ] 991 | }, 992 | "node_modules/@rollup/rollup-linux-x64-gnu": { 993 | "version": "4.35.0", 994 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.35.0.tgz", 995 | "integrity": "sha512-Pim1T8rXOri+0HmV4CdKSGrqcBWX0d1HoPnQ0uw0bdp1aP5SdQVNBy8LjYncvnLgu3fnnCt17xjWGd4cqh8/hA==", 996 | "cpu": [ 997 | "x64" 998 | ], 999 | "dev": true, 1000 | "license": "MIT", 1001 | "optional": true, 1002 | "os": [ 1003 | "linux" 1004 | ] 1005 | }, 1006 | "node_modules/@rollup/rollup-linux-x64-musl": { 1007 | "version": "4.35.0", 1008 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.35.0.tgz", 1009 | "integrity": "sha512-QysqXzYiDvQWfUiTm8XmJNO2zm9yC9P/2Gkrwg2dH9cxotQzunBHYr6jk4SujCTqnfGxduOmQcI7c2ryuW8XVg==", 1010 | "cpu": [ 1011 | "x64" 1012 | ], 1013 | "dev": true, 1014 | "license": "MIT", 1015 | "optional": true, 1016 | "os": [ 1017 | "linux" 1018 | ] 1019 | }, 1020 | "node_modules/@rollup/rollup-win32-arm64-msvc": { 1021 | "version": "4.35.0", 1022 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.35.0.tgz", 1023 | "integrity": "sha512-OUOlGqPkVJCdJETKOCEf1mw848ZyJ5w50/rZ/3IBQVdLfR5jk/6Sr5m3iO2tdPgwo0x7VcncYuOvMhBWZq8ayg==", 1024 | "cpu": [ 1025 | "arm64" 1026 | ], 1027 | "dev": true, 1028 | "license": "MIT", 1029 | "optional": true, 1030 | "os": [ 1031 | "win32" 1032 | ] 1033 | }, 1034 | "node_modules/@rollup/rollup-win32-ia32-msvc": { 1035 | "version": "4.35.0", 1036 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.35.0.tgz", 1037 | "integrity": "sha512-2/lsgejMrtwQe44glq7AFFHLfJBPafpsTa6JvP2NGef/ifOa4KBoglVf7AKN7EV9o32evBPRqfg96fEHzWo5kw==", 1038 | "cpu": [ 1039 | "ia32" 1040 | ], 1041 | "dev": true, 1042 | "license": "MIT", 1043 | "optional": true, 1044 | "os": [ 1045 | "win32" 1046 | ] 1047 | }, 1048 | "node_modules/@rollup/rollup-win32-x64-msvc": { 1049 | "version": "4.35.0", 1050 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.35.0.tgz", 1051 | "integrity": "sha512-PIQeY5XDkrOysbQblSW7v3l1MDZzkTEzAfTPkj5VAu3FW8fS4ynyLg2sINp0fp3SjZ8xkRYpLqoKcYqAkhU1dw==", 1052 | "cpu": [ 1053 | "x64" 1054 | ], 1055 | "dev": true, 1056 | "license": "MIT", 1057 | "optional": true, 1058 | "os": [ 1059 | "win32" 1060 | ] 1061 | }, 1062 | "node_modules/@sveltejs/adapter-auto": { 1063 | "version": "3.3.1", 1064 | "resolved": "https://registry.npmjs.org/@sveltejs/adapter-auto/-/adapter-auto-3.3.1.tgz", 1065 | "integrity": "sha512-5Sc7WAxYdL6q9j/+D0jJKjGREGlfIevDyHSQ2eNETHcB1TKlQWHcAo8AS8H1QdjNvSXpvOwNjykDUHPEAyGgdQ==", 1066 | "dev": true, 1067 | "dependencies": { 1068 | "import-meta-resolve": "^4.1.0" 1069 | }, 1070 | "peerDependencies": { 1071 | "@sveltejs/kit": "^2.0.0" 1072 | } 1073 | }, 1074 | "node_modules/@sveltejs/adapter-static": { 1075 | "version": "3.0.8", 1076 | "resolved": "https://registry.npmjs.org/@sveltejs/adapter-static/-/adapter-static-3.0.8.tgz", 1077 | "integrity": "sha512-YaDrquRpZwfcXbnlDsSrBQNCChVOT9MGuSg+dMAyfsAa1SmiAhrA5jUYUiIMC59G92kIbY/AaQOWcBdq+lh+zg==", 1078 | "dev": true, 1079 | "peerDependencies": { 1080 | "@sveltejs/kit": "^2.0.0" 1081 | } 1082 | }, 1083 | "node_modules/@sveltejs/kit": { 1084 | "version": "2.15.1", 1085 | "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.15.1.tgz", 1086 | "integrity": "sha512-8t7D3hQHbUDMiaQ2RVnjJJ/+Ur4Fn/tkeySJCsHtX346Q9cp3LAnav8xXdfuqYNJwpUGX0x3BqF1uvbmXQw93A==", 1087 | "dev": true, 1088 | "hasInstallScript": true, 1089 | "dependencies": { 1090 | "@types/cookie": "^0.6.0", 1091 | "cookie": "^0.6.0", 1092 | "devalue": "^5.1.0", 1093 | "esm-env": "^1.2.1", 1094 | "import-meta-resolve": "^4.1.0", 1095 | "kleur": "^4.1.5", 1096 | "magic-string": "^0.30.5", 1097 | "mrmime": "^2.0.0", 1098 | "sade": "^1.8.1", 1099 | "set-cookie-parser": "^2.6.0", 1100 | "sirv": "^3.0.0", 1101 | "tiny-glob": "^0.2.9" 1102 | }, 1103 | "bin": { 1104 | "svelte-kit": "svelte-kit.js" 1105 | }, 1106 | "engines": { 1107 | "node": ">=18.13" 1108 | }, 1109 | "peerDependencies": { 1110 | "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0", 1111 | "svelte": "^4.0.0 || ^5.0.0-next.0", 1112 | "vite": "^5.0.3 || ^6.0.0" 1113 | } 1114 | }, 1115 | "node_modules/@sveltejs/vite-plugin-svelte": { 1116 | "version": "5.0.3", 1117 | "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-5.0.3.tgz", 1118 | "integrity": "sha512-MCFS6CrQDu1yGwspm4qtli0e63vaPCehf6V7pIMP15AsWgMKrqDGCPFF/0kn4SP0ii4aySu4Pa62+fIRGFMjgw==", 1119 | "dev": true, 1120 | "license": "MIT", 1121 | "dependencies": { 1122 | "@sveltejs/vite-plugin-svelte-inspector": "^4.0.1", 1123 | "debug": "^4.4.0", 1124 | "deepmerge": "^4.3.1", 1125 | "kleur": "^4.1.5", 1126 | "magic-string": "^0.30.15", 1127 | "vitefu": "^1.0.4" 1128 | }, 1129 | "engines": { 1130 | "node": "^18.0.0 || ^20.0.0 || >=22" 1131 | }, 1132 | "peerDependencies": { 1133 | "svelte": "^5.0.0", 1134 | "vite": "^6.0.0" 1135 | } 1136 | }, 1137 | "node_modules/@sveltejs/vite-plugin-svelte-inspector": { 1138 | "version": "4.0.1", 1139 | "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-4.0.1.tgz", 1140 | "integrity": "sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw==", 1141 | "dev": true, 1142 | "license": "MIT", 1143 | "dependencies": { 1144 | "debug": "^4.3.7" 1145 | }, 1146 | "engines": { 1147 | "node": "^18.0.0 || ^20.0.0 || >=22" 1148 | }, 1149 | "peerDependencies": { 1150 | "@sveltejs/vite-plugin-svelte": "^5.0.0", 1151 | "svelte": "^5.0.0", 1152 | "vite": "^6.0.0" 1153 | } 1154 | }, 1155 | "node_modules/@tailwindcss/container-queries": { 1156 | "version": "0.1.1", 1157 | "resolved": "https://registry.npmjs.org/@tailwindcss/container-queries/-/container-queries-0.1.1.tgz", 1158 | "integrity": "sha512-p18dswChx6WnTSaJCSGx6lTmrGzNNvm2FtXmiO6AuA1V4U5REyoqwmT6kgAsIMdjo07QdAfYXHJ4hnMtfHzWgA==", 1159 | "peerDependencies": { 1160 | "tailwindcss": ">=3.2.0" 1161 | } 1162 | }, 1163 | "node_modules/@tailwindcss/forms": { 1164 | "version": "0.5.9", 1165 | "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.9.tgz", 1166 | "integrity": "sha512-tM4XVr2+UVTxXJzey9Twx48c1gcxFStqn1pQz0tRsX8o3DvxhN5oY5pvyAbUx7VTaZxpej4Zzvc6h+1RJBzpIg==", 1167 | "dependencies": { 1168 | "mini-svg-data-uri": "^1.2.3" 1169 | }, 1170 | "peerDependencies": { 1171 | "tailwindcss": ">=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20" 1172 | } 1173 | }, 1174 | "node_modules/@tailwindcss/typography": { 1175 | "version": "0.5.15", 1176 | "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.15.tgz", 1177 | "integrity": "sha512-AqhlCXl+8grUz8uqExv5OTtgpjuVIwFTSXTrh8y9/pw6q2ek7fJ+Y8ZEVw7EB2DCcuCOtEjf9w3+J3rzts01uA==", 1178 | "dependencies": { 1179 | "lodash.castarray": "^4.4.0", 1180 | "lodash.isplainobject": "^4.0.6", 1181 | "lodash.merge": "^4.6.2", 1182 | "postcss-selector-parser": "6.0.10" 1183 | }, 1184 | "peerDependencies": { 1185 | "tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20" 1186 | } 1187 | }, 1188 | "node_modules/@types/cookie": { 1189 | "version": "0.6.0", 1190 | "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", 1191 | "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", 1192 | "dev": true 1193 | }, 1194 | "node_modules/@types/estree": { 1195 | "version": "1.0.6", 1196 | "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", 1197 | "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", 1198 | "dev": true 1199 | }, 1200 | "node_modules/@types/json-schema": { 1201 | "version": "7.0.15", 1202 | "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", 1203 | "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", 1204 | "dev": true 1205 | }, 1206 | "node_modules/acorn": { 1207 | "version": "8.14.0", 1208 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", 1209 | "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", 1210 | "dev": true, 1211 | "bin": { 1212 | "acorn": "bin/acorn" 1213 | }, 1214 | "engines": { 1215 | "node": ">=0.4.0" 1216 | } 1217 | }, 1218 | "node_modules/acorn-jsx": { 1219 | "version": "5.3.2", 1220 | "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", 1221 | "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", 1222 | "dev": true, 1223 | "peerDependencies": { 1224 | "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" 1225 | } 1226 | }, 1227 | "node_modules/acorn-typescript": { 1228 | "version": "1.4.13", 1229 | "resolved": "https://registry.npmjs.org/acorn-typescript/-/acorn-typescript-1.4.13.tgz", 1230 | "integrity": "sha512-xsc9Xv0xlVfwp2o7sQ+GCQ1PgbkdcpWdTzrwXxO3xDMTAywVS3oXVOcOHuRjAPkS4P9b+yc/qNF15460v+jp4Q==", 1231 | "dev": true, 1232 | "peerDependencies": { 1233 | "acorn": ">=8.9.0" 1234 | } 1235 | }, 1236 | "node_modules/ajv": { 1237 | "version": "6.12.6", 1238 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", 1239 | "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", 1240 | "dev": true, 1241 | "dependencies": { 1242 | "fast-deep-equal": "^3.1.1", 1243 | "fast-json-stable-stringify": "^2.0.0", 1244 | "json-schema-traverse": "^0.4.1", 1245 | "uri-js": "^4.2.2" 1246 | }, 1247 | "funding": { 1248 | "type": "github", 1249 | "url": "https://github.com/sponsors/epoberezkin" 1250 | } 1251 | }, 1252 | "node_modules/ansi-regex": { 1253 | "version": "6.1.0", 1254 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", 1255 | "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", 1256 | "engines": { 1257 | "node": ">=12" 1258 | }, 1259 | "funding": { 1260 | "url": "https://github.com/chalk/ansi-regex?sponsor=1" 1261 | } 1262 | }, 1263 | "node_modules/ansi-styles": { 1264 | "version": "4.3.0", 1265 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 1266 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 1267 | "dependencies": { 1268 | "color-convert": "^2.0.1" 1269 | }, 1270 | "engines": { 1271 | "node": ">=8" 1272 | }, 1273 | "funding": { 1274 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 1275 | } 1276 | }, 1277 | "node_modules/any-promise": { 1278 | "version": "1.3.0", 1279 | "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", 1280 | "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" 1281 | }, 1282 | "node_modules/anymatch": { 1283 | "version": "3.1.3", 1284 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", 1285 | "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", 1286 | "dependencies": { 1287 | "normalize-path": "^3.0.0", 1288 | "picomatch": "^2.0.4" 1289 | }, 1290 | "engines": { 1291 | "node": ">= 8" 1292 | } 1293 | }, 1294 | "node_modules/arg": { 1295 | "version": "5.0.2", 1296 | "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", 1297 | "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" 1298 | }, 1299 | "node_modules/argparse": { 1300 | "version": "2.0.1", 1301 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", 1302 | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", 1303 | "dev": true 1304 | }, 1305 | "node_modules/aria-query": { 1306 | "version": "5.3.2", 1307 | "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", 1308 | "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", 1309 | "dev": true, 1310 | "engines": { 1311 | "node": ">= 0.4" 1312 | } 1313 | }, 1314 | "node_modules/autoprefixer": { 1315 | "version": "10.4.20", 1316 | "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz", 1317 | "integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==", 1318 | "dev": true, 1319 | "funding": [ 1320 | { 1321 | "type": "opencollective", 1322 | "url": "https://opencollective.com/postcss/" 1323 | }, 1324 | { 1325 | "type": "tidelift", 1326 | "url": "https://tidelift.com/funding/github/npm/autoprefixer" 1327 | }, 1328 | { 1329 | "type": "github", 1330 | "url": "https://github.com/sponsors/ai" 1331 | } 1332 | ], 1333 | "dependencies": { 1334 | "browserslist": "^4.23.3", 1335 | "caniuse-lite": "^1.0.30001646", 1336 | "fraction.js": "^4.3.7", 1337 | "normalize-range": "^0.1.2", 1338 | "picocolors": "^1.0.1", 1339 | "postcss-value-parser": "^4.2.0" 1340 | }, 1341 | "bin": { 1342 | "autoprefixer": "bin/autoprefixer" 1343 | }, 1344 | "engines": { 1345 | "node": "^10 || ^12 || >=14" 1346 | }, 1347 | "peerDependencies": { 1348 | "postcss": "^8.1.0" 1349 | } 1350 | }, 1351 | "node_modules/axobject-query": { 1352 | "version": "4.1.0", 1353 | "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", 1354 | "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", 1355 | "dev": true, 1356 | "engines": { 1357 | "node": ">= 0.4" 1358 | } 1359 | }, 1360 | "node_modules/balanced-match": { 1361 | "version": "1.0.2", 1362 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 1363 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" 1364 | }, 1365 | "node_modules/binary-extensions": { 1366 | "version": "2.3.0", 1367 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", 1368 | "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", 1369 | "engines": { 1370 | "node": ">=8" 1371 | }, 1372 | "funding": { 1373 | "url": "https://github.com/sponsors/sindresorhus" 1374 | } 1375 | }, 1376 | "node_modules/brace-expansion": { 1377 | "version": "1.1.11", 1378 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 1379 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 1380 | "dev": true, 1381 | "dependencies": { 1382 | "balanced-match": "^1.0.0", 1383 | "concat-map": "0.0.1" 1384 | } 1385 | }, 1386 | "node_modules/braces": { 1387 | "version": "3.0.3", 1388 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", 1389 | "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", 1390 | "dependencies": { 1391 | "fill-range": "^7.1.1" 1392 | }, 1393 | "engines": { 1394 | "node": ">=8" 1395 | } 1396 | }, 1397 | "node_modules/browserslist": { 1398 | "version": "4.24.3", 1399 | "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.3.tgz", 1400 | "integrity": "sha512-1CPmv8iobE2fyRMV97dAcMVegvvWKxmq94hkLiAkUGwKVTyDLw33K+ZxiFrREKmmps4rIw6grcCFCnTMSZ/YiA==", 1401 | "dev": true, 1402 | "funding": [ 1403 | { 1404 | "type": "opencollective", 1405 | "url": "https://opencollective.com/browserslist" 1406 | }, 1407 | { 1408 | "type": "tidelift", 1409 | "url": "https://tidelift.com/funding/github/npm/browserslist" 1410 | }, 1411 | { 1412 | "type": "github", 1413 | "url": "https://github.com/sponsors/ai" 1414 | } 1415 | ], 1416 | "dependencies": { 1417 | "caniuse-lite": "^1.0.30001688", 1418 | "electron-to-chromium": "^1.5.73", 1419 | "node-releases": "^2.0.19", 1420 | "update-browserslist-db": "^1.1.1" 1421 | }, 1422 | "bin": { 1423 | "browserslist": "cli.js" 1424 | }, 1425 | "engines": { 1426 | "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" 1427 | } 1428 | }, 1429 | "node_modules/callsites": { 1430 | "version": "3.1.0", 1431 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", 1432 | "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", 1433 | "dev": true, 1434 | "engines": { 1435 | "node": ">=6" 1436 | } 1437 | }, 1438 | "node_modules/camelcase-css": { 1439 | "version": "2.0.1", 1440 | "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", 1441 | "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", 1442 | "engines": { 1443 | "node": ">= 6" 1444 | } 1445 | }, 1446 | "node_modules/caniuse-lite": { 1447 | "version": "1.0.30001690", 1448 | "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001690.tgz", 1449 | "integrity": "sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w==", 1450 | "dev": true, 1451 | "funding": [ 1452 | { 1453 | "type": "opencollective", 1454 | "url": "https://opencollective.com/browserslist" 1455 | }, 1456 | { 1457 | "type": "tidelift", 1458 | "url": "https://tidelift.com/funding/github/npm/caniuse-lite" 1459 | }, 1460 | { 1461 | "type": "github", 1462 | "url": "https://github.com/sponsors/ai" 1463 | } 1464 | ] 1465 | }, 1466 | "node_modules/chalk": { 1467 | "version": "4.1.2", 1468 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", 1469 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", 1470 | "dev": true, 1471 | "dependencies": { 1472 | "ansi-styles": "^4.1.0", 1473 | "supports-color": "^7.1.0" 1474 | }, 1475 | "engines": { 1476 | "node": ">=10" 1477 | }, 1478 | "funding": { 1479 | "url": "https://github.com/chalk/chalk?sponsor=1" 1480 | } 1481 | }, 1482 | "node_modules/chokidar": { 1483 | "version": "3.6.0", 1484 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", 1485 | "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", 1486 | "dependencies": { 1487 | "anymatch": "~3.1.2", 1488 | "braces": "~3.0.2", 1489 | "glob-parent": "~5.1.2", 1490 | "is-binary-path": "~2.1.0", 1491 | "is-glob": "~4.0.1", 1492 | "normalize-path": "~3.0.0", 1493 | "readdirp": "~3.6.0" 1494 | }, 1495 | "engines": { 1496 | "node": ">= 8.10.0" 1497 | }, 1498 | "funding": { 1499 | "url": "https://paulmillr.com/funding/" 1500 | }, 1501 | "optionalDependencies": { 1502 | "fsevents": "~2.3.2" 1503 | } 1504 | }, 1505 | "node_modules/chokidar/node_modules/glob-parent": { 1506 | "version": "5.1.2", 1507 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 1508 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 1509 | "dependencies": { 1510 | "is-glob": "^4.0.1" 1511 | }, 1512 | "engines": { 1513 | "node": ">= 6" 1514 | } 1515 | }, 1516 | "node_modules/clsx": { 1517 | "version": "2.1.1", 1518 | "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", 1519 | "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", 1520 | "dev": true, 1521 | "engines": { 1522 | "node": ">=6" 1523 | } 1524 | }, 1525 | "node_modules/color-convert": { 1526 | "version": "2.0.1", 1527 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 1528 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 1529 | "dependencies": { 1530 | "color-name": "~1.1.4" 1531 | }, 1532 | "engines": { 1533 | "node": ">=7.0.0" 1534 | } 1535 | }, 1536 | "node_modules/color-name": { 1537 | "version": "1.1.4", 1538 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 1539 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" 1540 | }, 1541 | "node_modules/commander": { 1542 | "version": "4.1.1", 1543 | "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", 1544 | "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", 1545 | "engines": { 1546 | "node": ">= 6" 1547 | } 1548 | }, 1549 | "node_modules/concat-map": { 1550 | "version": "0.0.1", 1551 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 1552 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", 1553 | "dev": true 1554 | }, 1555 | "node_modules/cookie": { 1556 | "version": "0.6.0", 1557 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", 1558 | "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", 1559 | "dev": true, 1560 | "engines": { 1561 | "node": ">= 0.6" 1562 | } 1563 | }, 1564 | "node_modules/cross-spawn": { 1565 | "version": "7.0.6", 1566 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", 1567 | "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", 1568 | "dependencies": { 1569 | "path-key": "^3.1.0", 1570 | "shebang-command": "^2.0.0", 1571 | "which": "^2.0.1" 1572 | }, 1573 | "engines": { 1574 | "node": ">= 8" 1575 | } 1576 | }, 1577 | "node_modules/cssesc": { 1578 | "version": "3.0.0", 1579 | "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", 1580 | "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", 1581 | "bin": { 1582 | "cssesc": "bin/cssesc" 1583 | }, 1584 | "engines": { 1585 | "node": ">=4" 1586 | } 1587 | }, 1588 | "node_modules/debug": { 1589 | "version": "4.4.0", 1590 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", 1591 | "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", 1592 | "dev": true, 1593 | "dependencies": { 1594 | "ms": "^2.1.3" 1595 | }, 1596 | "engines": { 1597 | "node": ">=6.0" 1598 | }, 1599 | "peerDependenciesMeta": { 1600 | "supports-color": { 1601 | "optional": true 1602 | } 1603 | } 1604 | }, 1605 | "node_modules/deep-is": { 1606 | "version": "0.1.4", 1607 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", 1608 | "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", 1609 | "dev": true 1610 | }, 1611 | "node_modules/deepmerge": { 1612 | "version": "4.3.1", 1613 | "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", 1614 | "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", 1615 | "dev": true, 1616 | "engines": { 1617 | "node": ">=0.10.0" 1618 | } 1619 | }, 1620 | "node_modules/devalue": { 1621 | "version": "5.1.1", 1622 | "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.1.1.tgz", 1623 | "integrity": "sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw==", 1624 | "dev": true 1625 | }, 1626 | "node_modules/didyoumean": { 1627 | "version": "1.2.2", 1628 | "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", 1629 | "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" 1630 | }, 1631 | "node_modules/dlv": { 1632 | "version": "1.1.3", 1633 | "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", 1634 | "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" 1635 | }, 1636 | "node_modules/eastasianwidth": { 1637 | "version": "0.2.0", 1638 | "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", 1639 | "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" 1640 | }, 1641 | "node_modules/electron-to-chromium": { 1642 | "version": "1.5.76", 1643 | "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.76.tgz", 1644 | "integrity": "sha512-CjVQyG7n7Sr+eBXE86HIulnL5N8xZY1sgmOPGuq/F0Rr0FJq63lg0kEtOIDfZBk44FnDLf6FUJ+dsJcuiUDdDQ==", 1645 | "dev": true 1646 | }, 1647 | "node_modules/emoji-regex": { 1648 | "version": "9.2.2", 1649 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", 1650 | "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" 1651 | }, 1652 | "node_modules/esbuild": { 1653 | "version": "0.25.1", 1654 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.1.tgz", 1655 | "integrity": "sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==", 1656 | "dev": true, 1657 | "hasInstallScript": true, 1658 | "license": "MIT", 1659 | "bin": { 1660 | "esbuild": "bin/esbuild" 1661 | }, 1662 | "engines": { 1663 | "node": ">=18" 1664 | }, 1665 | "optionalDependencies": { 1666 | "@esbuild/aix-ppc64": "0.25.1", 1667 | "@esbuild/android-arm": "0.25.1", 1668 | "@esbuild/android-arm64": "0.25.1", 1669 | "@esbuild/android-x64": "0.25.1", 1670 | "@esbuild/darwin-arm64": "0.25.1", 1671 | "@esbuild/darwin-x64": "0.25.1", 1672 | "@esbuild/freebsd-arm64": "0.25.1", 1673 | "@esbuild/freebsd-x64": "0.25.1", 1674 | "@esbuild/linux-arm": "0.25.1", 1675 | "@esbuild/linux-arm64": "0.25.1", 1676 | "@esbuild/linux-ia32": "0.25.1", 1677 | "@esbuild/linux-loong64": "0.25.1", 1678 | "@esbuild/linux-mips64el": "0.25.1", 1679 | "@esbuild/linux-ppc64": "0.25.1", 1680 | "@esbuild/linux-riscv64": "0.25.1", 1681 | "@esbuild/linux-s390x": "0.25.1", 1682 | "@esbuild/linux-x64": "0.25.1", 1683 | "@esbuild/netbsd-arm64": "0.25.1", 1684 | "@esbuild/netbsd-x64": "0.25.1", 1685 | "@esbuild/openbsd-arm64": "0.25.1", 1686 | "@esbuild/openbsd-x64": "0.25.1", 1687 | "@esbuild/sunos-x64": "0.25.1", 1688 | "@esbuild/win32-arm64": "0.25.1", 1689 | "@esbuild/win32-ia32": "0.25.1", 1690 | "@esbuild/win32-x64": "0.25.1" 1691 | } 1692 | }, 1693 | "node_modules/escalade": { 1694 | "version": "3.2.0", 1695 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", 1696 | "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", 1697 | "dev": true, 1698 | "engines": { 1699 | "node": ">=6" 1700 | } 1701 | }, 1702 | "node_modules/escape-string-regexp": { 1703 | "version": "4.0.0", 1704 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", 1705 | "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", 1706 | "dev": true, 1707 | "engines": { 1708 | "node": ">=10" 1709 | }, 1710 | "funding": { 1711 | "url": "https://github.com/sponsors/sindresorhus" 1712 | } 1713 | }, 1714 | "node_modules/eslint": { 1715 | "version": "9.17.0", 1716 | "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.17.0.tgz", 1717 | "integrity": "sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA==", 1718 | "dev": true, 1719 | "dependencies": { 1720 | "@eslint-community/eslint-utils": "^4.2.0", 1721 | "@eslint-community/regexpp": "^4.12.1", 1722 | "@eslint/config-array": "^0.19.0", 1723 | "@eslint/core": "^0.9.0", 1724 | "@eslint/eslintrc": "^3.2.0", 1725 | "@eslint/js": "9.17.0", 1726 | "@eslint/plugin-kit": "^0.2.3", 1727 | "@humanfs/node": "^0.16.6", 1728 | "@humanwhocodes/module-importer": "^1.0.1", 1729 | "@humanwhocodes/retry": "^0.4.1", 1730 | "@types/estree": "^1.0.6", 1731 | "@types/json-schema": "^7.0.15", 1732 | "ajv": "^6.12.4", 1733 | "chalk": "^4.0.0", 1734 | "cross-spawn": "^7.0.6", 1735 | "debug": "^4.3.2", 1736 | "escape-string-regexp": "^4.0.0", 1737 | "eslint-scope": "^8.2.0", 1738 | "eslint-visitor-keys": "^4.2.0", 1739 | "espree": "^10.3.0", 1740 | "esquery": "^1.5.0", 1741 | "esutils": "^2.0.2", 1742 | "fast-deep-equal": "^3.1.3", 1743 | "file-entry-cache": "^8.0.0", 1744 | "find-up": "^5.0.0", 1745 | "glob-parent": "^6.0.2", 1746 | "ignore": "^5.2.0", 1747 | "imurmurhash": "^0.1.4", 1748 | "is-glob": "^4.0.0", 1749 | "json-stable-stringify-without-jsonify": "^1.0.1", 1750 | "lodash.merge": "^4.6.2", 1751 | "minimatch": "^3.1.2", 1752 | "natural-compare": "^1.4.0", 1753 | "optionator": "^0.9.3" 1754 | }, 1755 | "bin": { 1756 | "eslint": "bin/eslint.js" 1757 | }, 1758 | "engines": { 1759 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 1760 | }, 1761 | "funding": { 1762 | "url": "https://eslint.org/donate" 1763 | }, 1764 | "peerDependencies": { 1765 | "jiti": "*" 1766 | }, 1767 | "peerDependenciesMeta": { 1768 | "jiti": { 1769 | "optional": true 1770 | } 1771 | } 1772 | }, 1773 | "node_modules/eslint-compat-utils": { 1774 | "version": "0.5.1", 1775 | "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.5.1.tgz", 1776 | "integrity": "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==", 1777 | "dev": true, 1778 | "dependencies": { 1779 | "semver": "^7.5.4" 1780 | }, 1781 | "engines": { 1782 | "node": ">=12" 1783 | }, 1784 | "peerDependencies": { 1785 | "eslint": ">=6.0.0" 1786 | } 1787 | }, 1788 | "node_modules/eslint-config-prettier": { 1789 | "version": "9.1.0", 1790 | "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", 1791 | "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", 1792 | "dev": true, 1793 | "bin": { 1794 | "eslint-config-prettier": "bin/cli.js" 1795 | }, 1796 | "peerDependencies": { 1797 | "eslint": ">=7.0.0" 1798 | } 1799 | }, 1800 | "node_modules/eslint-plugin-svelte": { 1801 | "version": "2.46.1", 1802 | "resolved": "https://registry.npmjs.org/eslint-plugin-svelte/-/eslint-plugin-svelte-2.46.1.tgz", 1803 | "integrity": "sha512-7xYr2o4NID/f9OEYMqxsEQsCsj4KaMy4q5sANaKkAb6/QeCjYFxRmDm2S3YC3A3pl1kyPZ/syOx/i7LcWYSbIw==", 1804 | "dev": true, 1805 | "dependencies": { 1806 | "@eslint-community/eslint-utils": "^4.4.0", 1807 | "@jridgewell/sourcemap-codec": "^1.4.15", 1808 | "eslint-compat-utils": "^0.5.1", 1809 | "esutils": "^2.0.3", 1810 | "known-css-properties": "^0.35.0", 1811 | "postcss": "^8.4.38", 1812 | "postcss-load-config": "^3.1.4", 1813 | "postcss-safe-parser": "^6.0.0", 1814 | "postcss-selector-parser": "^6.1.0", 1815 | "semver": "^7.6.2", 1816 | "svelte-eslint-parser": "^0.43.0" 1817 | }, 1818 | "engines": { 1819 | "node": "^14.17.0 || >=16.0.0" 1820 | }, 1821 | "funding": { 1822 | "url": "https://github.com/sponsors/ota-meshi" 1823 | }, 1824 | "peerDependencies": { 1825 | "eslint": "^7.0.0 || ^8.0.0-0 || ^9.0.0-0", 1826 | "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0" 1827 | }, 1828 | "peerDependenciesMeta": { 1829 | "svelte": { 1830 | "optional": true 1831 | } 1832 | } 1833 | }, 1834 | "node_modules/eslint-plugin-svelte/node_modules/postcss-selector-parser": { 1835 | "version": "6.1.2", 1836 | "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", 1837 | "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", 1838 | "dev": true, 1839 | "dependencies": { 1840 | "cssesc": "^3.0.0", 1841 | "util-deprecate": "^1.0.2" 1842 | }, 1843 | "engines": { 1844 | "node": ">=4" 1845 | } 1846 | }, 1847 | "node_modules/eslint-scope": { 1848 | "version": "8.2.0", 1849 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", 1850 | "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", 1851 | "dev": true, 1852 | "dependencies": { 1853 | "esrecurse": "^4.3.0", 1854 | "estraverse": "^5.2.0" 1855 | }, 1856 | "engines": { 1857 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 1858 | }, 1859 | "funding": { 1860 | "url": "https://opencollective.com/eslint" 1861 | } 1862 | }, 1863 | "node_modules/eslint-visitor-keys": { 1864 | "version": "4.2.0", 1865 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", 1866 | "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", 1867 | "dev": true, 1868 | "engines": { 1869 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 1870 | }, 1871 | "funding": { 1872 | "url": "https://opencollective.com/eslint" 1873 | } 1874 | }, 1875 | "node_modules/esm-env": { 1876 | "version": "1.2.1", 1877 | "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.1.tgz", 1878 | "integrity": "sha512-U9JedYYjCnadUlXk7e1Kr+aENQhtUaoaV9+gZm1T8LC/YBAPJx3NSPIAurFOC0U5vrdSevnUJS2/wUVxGwPhng==", 1879 | "dev": true 1880 | }, 1881 | "node_modules/espree": { 1882 | "version": "10.3.0", 1883 | "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", 1884 | "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", 1885 | "dev": true, 1886 | "dependencies": { 1887 | "acorn": "^8.14.0", 1888 | "acorn-jsx": "^5.3.2", 1889 | "eslint-visitor-keys": "^4.2.0" 1890 | }, 1891 | "engines": { 1892 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 1893 | }, 1894 | "funding": { 1895 | "url": "https://opencollective.com/eslint" 1896 | } 1897 | }, 1898 | "node_modules/esquery": { 1899 | "version": "1.6.0", 1900 | "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", 1901 | "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", 1902 | "dev": true, 1903 | "dependencies": { 1904 | "estraverse": "^5.1.0" 1905 | }, 1906 | "engines": { 1907 | "node": ">=0.10" 1908 | } 1909 | }, 1910 | "node_modules/esrap": { 1911 | "version": "1.3.2", 1912 | "resolved": "https://registry.npmjs.org/esrap/-/esrap-1.3.2.tgz", 1913 | "integrity": "sha512-C4PXusxYhFT98GjLSmb20k9PREuUdporer50dhzGuJu9IJXktbMddVCMLAERl5dAHyAi73GWWCE4FVHGP1794g==", 1914 | "dev": true, 1915 | "dependencies": { 1916 | "@jridgewell/sourcemap-codec": "^1.4.15" 1917 | } 1918 | }, 1919 | "node_modules/esrecurse": { 1920 | "version": "4.3.0", 1921 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", 1922 | "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", 1923 | "dev": true, 1924 | "dependencies": { 1925 | "estraverse": "^5.2.0" 1926 | }, 1927 | "engines": { 1928 | "node": ">=4.0" 1929 | } 1930 | }, 1931 | "node_modules/estraverse": { 1932 | "version": "5.3.0", 1933 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", 1934 | "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", 1935 | "dev": true, 1936 | "engines": { 1937 | "node": ">=4.0" 1938 | } 1939 | }, 1940 | "node_modules/esutils": { 1941 | "version": "2.0.3", 1942 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", 1943 | "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", 1944 | "dev": true, 1945 | "engines": { 1946 | "node": ">=0.10.0" 1947 | } 1948 | }, 1949 | "node_modules/fast-deep-equal": { 1950 | "version": "3.1.3", 1951 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", 1952 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", 1953 | "dev": true 1954 | }, 1955 | "node_modules/fast-glob": { 1956 | "version": "3.3.2", 1957 | "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", 1958 | "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", 1959 | "dependencies": { 1960 | "@nodelib/fs.stat": "^2.0.2", 1961 | "@nodelib/fs.walk": "^1.2.3", 1962 | "glob-parent": "^5.1.2", 1963 | "merge2": "^1.3.0", 1964 | "micromatch": "^4.0.4" 1965 | }, 1966 | "engines": { 1967 | "node": ">=8.6.0" 1968 | } 1969 | }, 1970 | "node_modules/fast-glob/node_modules/glob-parent": { 1971 | "version": "5.1.2", 1972 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 1973 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 1974 | "dependencies": { 1975 | "is-glob": "^4.0.1" 1976 | }, 1977 | "engines": { 1978 | "node": ">= 6" 1979 | } 1980 | }, 1981 | "node_modules/fast-json-stable-stringify": { 1982 | "version": "2.1.0", 1983 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", 1984 | "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", 1985 | "dev": true 1986 | }, 1987 | "node_modules/fast-levenshtein": { 1988 | "version": "2.0.6", 1989 | "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", 1990 | "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", 1991 | "dev": true 1992 | }, 1993 | "node_modules/fastq": { 1994 | "version": "1.18.0", 1995 | "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.18.0.tgz", 1996 | "integrity": "sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==", 1997 | "dependencies": { 1998 | "reusify": "^1.0.4" 1999 | } 2000 | }, 2001 | "node_modules/file-entry-cache": { 2002 | "version": "8.0.0", 2003 | "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", 2004 | "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", 2005 | "dev": true, 2006 | "dependencies": { 2007 | "flat-cache": "^4.0.0" 2008 | }, 2009 | "engines": { 2010 | "node": ">=16.0.0" 2011 | } 2012 | }, 2013 | "node_modules/fill-range": { 2014 | "version": "7.1.1", 2015 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", 2016 | "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", 2017 | "dependencies": { 2018 | "to-regex-range": "^5.0.1" 2019 | }, 2020 | "engines": { 2021 | "node": ">=8" 2022 | } 2023 | }, 2024 | "node_modules/find-up": { 2025 | "version": "5.0.0", 2026 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", 2027 | "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", 2028 | "dev": true, 2029 | "dependencies": { 2030 | "locate-path": "^6.0.0", 2031 | "path-exists": "^4.0.0" 2032 | }, 2033 | "engines": { 2034 | "node": ">=10" 2035 | }, 2036 | "funding": { 2037 | "url": "https://github.com/sponsors/sindresorhus" 2038 | } 2039 | }, 2040 | "node_modules/flat-cache": { 2041 | "version": "4.0.1", 2042 | "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", 2043 | "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", 2044 | "dev": true, 2045 | "dependencies": { 2046 | "flatted": "^3.2.9", 2047 | "keyv": "^4.5.4" 2048 | }, 2049 | "engines": { 2050 | "node": ">=16" 2051 | } 2052 | }, 2053 | "node_modules/flatted": { 2054 | "version": "3.3.2", 2055 | "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", 2056 | "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", 2057 | "dev": true 2058 | }, 2059 | "node_modules/foreground-child": { 2060 | "version": "3.3.0", 2061 | "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", 2062 | "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", 2063 | "dependencies": { 2064 | "cross-spawn": "^7.0.0", 2065 | "signal-exit": "^4.0.1" 2066 | }, 2067 | "engines": { 2068 | "node": ">=14" 2069 | }, 2070 | "funding": { 2071 | "url": "https://github.com/sponsors/isaacs" 2072 | } 2073 | }, 2074 | "node_modules/fraction.js": { 2075 | "version": "4.3.7", 2076 | "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", 2077 | "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", 2078 | "dev": true, 2079 | "engines": { 2080 | "node": "*" 2081 | }, 2082 | "funding": { 2083 | "type": "patreon", 2084 | "url": "https://github.com/sponsors/rawify" 2085 | } 2086 | }, 2087 | "node_modules/fsevents": { 2088 | "version": "2.3.3", 2089 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 2090 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 2091 | "hasInstallScript": true, 2092 | "optional": true, 2093 | "os": [ 2094 | "darwin" 2095 | ], 2096 | "engines": { 2097 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 2098 | } 2099 | }, 2100 | "node_modules/function-bind": { 2101 | "version": "1.1.2", 2102 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", 2103 | "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", 2104 | "funding": { 2105 | "url": "https://github.com/sponsors/ljharb" 2106 | } 2107 | }, 2108 | "node_modules/glob": { 2109 | "version": "10.4.5", 2110 | "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", 2111 | "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", 2112 | "dependencies": { 2113 | "foreground-child": "^3.1.0", 2114 | "jackspeak": "^3.1.2", 2115 | "minimatch": "^9.0.4", 2116 | "minipass": "^7.1.2", 2117 | "package-json-from-dist": "^1.0.0", 2118 | "path-scurry": "^1.11.1" 2119 | }, 2120 | "bin": { 2121 | "glob": "dist/esm/bin.mjs" 2122 | }, 2123 | "funding": { 2124 | "url": "https://github.com/sponsors/isaacs" 2125 | } 2126 | }, 2127 | "node_modules/glob-parent": { 2128 | "version": "6.0.2", 2129 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", 2130 | "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", 2131 | "dependencies": { 2132 | "is-glob": "^4.0.3" 2133 | }, 2134 | "engines": { 2135 | "node": ">=10.13.0" 2136 | } 2137 | }, 2138 | "node_modules/glob/node_modules/brace-expansion": { 2139 | "version": "2.0.1", 2140 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", 2141 | "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", 2142 | "dependencies": { 2143 | "balanced-match": "^1.0.0" 2144 | } 2145 | }, 2146 | "node_modules/glob/node_modules/minimatch": { 2147 | "version": "9.0.5", 2148 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", 2149 | "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", 2150 | "dependencies": { 2151 | "brace-expansion": "^2.0.1" 2152 | }, 2153 | "engines": { 2154 | "node": ">=16 || 14 >=14.17" 2155 | }, 2156 | "funding": { 2157 | "url": "https://github.com/sponsors/isaacs" 2158 | } 2159 | }, 2160 | "node_modules/globals": { 2161 | "version": "15.14.0", 2162 | "resolved": "https://registry.npmjs.org/globals/-/globals-15.14.0.tgz", 2163 | "integrity": "sha512-OkToC372DtlQeje9/zHIo5CT8lRP/FUgEOKBEhU4e0abL7J7CD24fD9ohiLN5hagG/kWCYj4K5oaxxtj2Z0Dig==", 2164 | "dev": true, 2165 | "engines": { 2166 | "node": ">=18" 2167 | }, 2168 | "funding": { 2169 | "url": "https://github.com/sponsors/sindresorhus" 2170 | } 2171 | }, 2172 | "node_modules/globalyzer": { 2173 | "version": "0.1.0", 2174 | "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz", 2175 | "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==", 2176 | "dev": true 2177 | }, 2178 | "node_modules/globrex": { 2179 | "version": "0.1.2", 2180 | "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", 2181 | "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", 2182 | "dev": true 2183 | }, 2184 | "node_modules/has-flag": { 2185 | "version": "4.0.0", 2186 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 2187 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 2188 | "dev": true, 2189 | "engines": { 2190 | "node": ">=8" 2191 | } 2192 | }, 2193 | "node_modules/hasown": { 2194 | "version": "2.0.2", 2195 | "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", 2196 | "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", 2197 | "dependencies": { 2198 | "function-bind": "^1.1.2" 2199 | }, 2200 | "engines": { 2201 | "node": ">= 0.4" 2202 | } 2203 | }, 2204 | "node_modules/ignore": { 2205 | "version": "5.3.2", 2206 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", 2207 | "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", 2208 | "dev": true, 2209 | "engines": { 2210 | "node": ">= 4" 2211 | } 2212 | }, 2213 | "node_modules/import-fresh": { 2214 | "version": "3.3.0", 2215 | "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", 2216 | "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", 2217 | "dev": true, 2218 | "dependencies": { 2219 | "parent-module": "^1.0.0", 2220 | "resolve-from": "^4.0.0" 2221 | }, 2222 | "engines": { 2223 | "node": ">=6" 2224 | }, 2225 | "funding": { 2226 | "url": "https://github.com/sponsors/sindresorhus" 2227 | } 2228 | }, 2229 | "node_modules/import-meta-resolve": { 2230 | "version": "4.1.0", 2231 | "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz", 2232 | "integrity": "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==", 2233 | "dev": true, 2234 | "funding": { 2235 | "type": "github", 2236 | "url": "https://github.com/sponsors/wooorm" 2237 | } 2238 | }, 2239 | "node_modules/imurmurhash": { 2240 | "version": "0.1.4", 2241 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", 2242 | "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", 2243 | "dev": true, 2244 | "engines": { 2245 | "node": ">=0.8.19" 2246 | } 2247 | }, 2248 | "node_modules/is-binary-path": { 2249 | "version": "2.1.0", 2250 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 2251 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 2252 | "dependencies": { 2253 | "binary-extensions": "^2.0.0" 2254 | }, 2255 | "engines": { 2256 | "node": ">=8" 2257 | } 2258 | }, 2259 | "node_modules/is-core-module": { 2260 | "version": "2.16.1", 2261 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", 2262 | "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", 2263 | "dependencies": { 2264 | "hasown": "^2.0.2" 2265 | }, 2266 | "engines": { 2267 | "node": ">= 0.4" 2268 | }, 2269 | "funding": { 2270 | "url": "https://github.com/sponsors/ljharb" 2271 | } 2272 | }, 2273 | "node_modules/is-extglob": { 2274 | "version": "2.1.1", 2275 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 2276 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 2277 | "engines": { 2278 | "node": ">=0.10.0" 2279 | } 2280 | }, 2281 | "node_modules/is-fullwidth-code-point": { 2282 | "version": "3.0.0", 2283 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 2284 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 2285 | "engines": { 2286 | "node": ">=8" 2287 | } 2288 | }, 2289 | "node_modules/is-glob": { 2290 | "version": "4.0.3", 2291 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 2292 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 2293 | "dependencies": { 2294 | "is-extglob": "^2.1.1" 2295 | }, 2296 | "engines": { 2297 | "node": ">=0.10.0" 2298 | } 2299 | }, 2300 | "node_modules/is-number": { 2301 | "version": "7.0.0", 2302 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 2303 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 2304 | "engines": { 2305 | "node": ">=0.12.0" 2306 | } 2307 | }, 2308 | "node_modules/is-reference": { 2309 | "version": "3.0.3", 2310 | "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz", 2311 | "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==", 2312 | "dev": true, 2313 | "dependencies": { 2314 | "@types/estree": "^1.0.6" 2315 | } 2316 | }, 2317 | "node_modules/isexe": { 2318 | "version": "2.0.0", 2319 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 2320 | "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" 2321 | }, 2322 | "node_modules/jackspeak": { 2323 | "version": "3.4.3", 2324 | "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", 2325 | "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", 2326 | "dependencies": { 2327 | "@isaacs/cliui": "^8.0.2" 2328 | }, 2329 | "funding": { 2330 | "url": "https://github.com/sponsors/isaacs" 2331 | }, 2332 | "optionalDependencies": { 2333 | "@pkgjs/parseargs": "^0.11.0" 2334 | } 2335 | }, 2336 | "node_modules/jiti": { 2337 | "version": "1.21.7", 2338 | "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", 2339 | "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", 2340 | "bin": { 2341 | "jiti": "bin/jiti.js" 2342 | } 2343 | }, 2344 | "node_modules/js-yaml": { 2345 | "version": "4.1.0", 2346 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", 2347 | "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", 2348 | "dev": true, 2349 | "dependencies": { 2350 | "argparse": "^2.0.1" 2351 | }, 2352 | "bin": { 2353 | "js-yaml": "bin/js-yaml.js" 2354 | } 2355 | }, 2356 | "node_modules/json-buffer": { 2357 | "version": "3.0.1", 2358 | "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", 2359 | "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", 2360 | "dev": true 2361 | }, 2362 | "node_modules/json-schema-traverse": { 2363 | "version": "0.4.1", 2364 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 2365 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", 2366 | "dev": true 2367 | }, 2368 | "node_modules/json-stable-stringify-without-jsonify": { 2369 | "version": "1.0.1", 2370 | "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", 2371 | "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", 2372 | "dev": true 2373 | }, 2374 | "node_modules/keyv": { 2375 | "version": "4.5.4", 2376 | "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", 2377 | "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", 2378 | "dev": true, 2379 | "dependencies": { 2380 | "json-buffer": "3.0.1" 2381 | } 2382 | }, 2383 | "node_modules/kleur": { 2384 | "version": "4.1.5", 2385 | "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", 2386 | "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", 2387 | "dev": true, 2388 | "engines": { 2389 | "node": ">=6" 2390 | } 2391 | }, 2392 | "node_modules/known-css-properties": { 2393 | "version": "0.35.0", 2394 | "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.35.0.tgz", 2395 | "integrity": "sha512-a/RAk2BfKk+WFGhhOCAYqSiFLc34k8Mt/6NWRI4joER0EYUzXIcFivjjnoD3+XU1DggLn/tZc3DOAgke7l8a4A==", 2396 | "dev": true 2397 | }, 2398 | "node_modules/levn": { 2399 | "version": "0.4.1", 2400 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", 2401 | "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", 2402 | "dev": true, 2403 | "dependencies": { 2404 | "prelude-ls": "^1.2.1", 2405 | "type-check": "~0.4.0" 2406 | }, 2407 | "engines": { 2408 | "node": ">= 0.8.0" 2409 | } 2410 | }, 2411 | "node_modules/lilconfig": { 2412 | "version": "2.1.0", 2413 | "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", 2414 | "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", 2415 | "dev": true, 2416 | "engines": { 2417 | "node": ">=10" 2418 | } 2419 | }, 2420 | "node_modules/lines-and-columns": { 2421 | "version": "1.2.4", 2422 | "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", 2423 | "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" 2424 | }, 2425 | "node_modules/locate-character": { 2426 | "version": "3.0.0", 2427 | "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", 2428 | "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", 2429 | "dev": true 2430 | }, 2431 | "node_modules/locate-path": { 2432 | "version": "6.0.0", 2433 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", 2434 | "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", 2435 | "dev": true, 2436 | "dependencies": { 2437 | "p-locate": "^5.0.0" 2438 | }, 2439 | "engines": { 2440 | "node": ">=10" 2441 | }, 2442 | "funding": { 2443 | "url": "https://github.com/sponsors/sindresorhus" 2444 | } 2445 | }, 2446 | "node_modules/lodash.castarray": { 2447 | "version": "4.4.0", 2448 | "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz", 2449 | "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==" 2450 | }, 2451 | "node_modules/lodash.isplainobject": { 2452 | "version": "4.0.6", 2453 | "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", 2454 | "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" 2455 | }, 2456 | "node_modules/lodash.merge": { 2457 | "version": "4.6.2", 2458 | "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", 2459 | "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" 2460 | }, 2461 | "node_modules/lru-cache": { 2462 | "version": "10.4.3", 2463 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", 2464 | "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" 2465 | }, 2466 | "node_modules/magic-string": { 2467 | "version": "0.30.17", 2468 | "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", 2469 | "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", 2470 | "dev": true, 2471 | "dependencies": { 2472 | "@jridgewell/sourcemap-codec": "^1.5.0" 2473 | } 2474 | }, 2475 | "node_modules/merge2": { 2476 | "version": "1.4.1", 2477 | "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", 2478 | "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", 2479 | "engines": { 2480 | "node": ">= 8" 2481 | } 2482 | }, 2483 | "node_modules/micromatch": { 2484 | "version": "4.0.8", 2485 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", 2486 | "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", 2487 | "dependencies": { 2488 | "braces": "^3.0.3", 2489 | "picomatch": "^2.3.1" 2490 | }, 2491 | "engines": { 2492 | "node": ">=8.6" 2493 | } 2494 | }, 2495 | "node_modules/mini-svg-data-uri": { 2496 | "version": "1.4.4", 2497 | "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz", 2498 | "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==", 2499 | "bin": { 2500 | "mini-svg-data-uri": "cli.js" 2501 | } 2502 | }, 2503 | "node_modules/minimatch": { 2504 | "version": "3.1.2", 2505 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 2506 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 2507 | "dev": true, 2508 | "dependencies": { 2509 | "brace-expansion": "^1.1.7" 2510 | }, 2511 | "engines": { 2512 | "node": "*" 2513 | } 2514 | }, 2515 | "node_modules/minipass": { 2516 | "version": "7.1.2", 2517 | "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", 2518 | "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", 2519 | "engines": { 2520 | "node": ">=16 || 14 >=14.17" 2521 | } 2522 | }, 2523 | "node_modules/mri": { 2524 | "version": "1.2.0", 2525 | "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", 2526 | "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", 2527 | "dev": true, 2528 | "engines": { 2529 | "node": ">=4" 2530 | } 2531 | }, 2532 | "node_modules/mrmime": { 2533 | "version": "2.0.0", 2534 | "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", 2535 | "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", 2536 | "dev": true, 2537 | "engines": { 2538 | "node": ">=10" 2539 | } 2540 | }, 2541 | "node_modules/ms": { 2542 | "version": "2.1.3", 2543 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 2544 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 2545 | "dev": true 2546 | }, 2547 | "node_modules/mz": { 2548 | "version": "2.7.0", 2549 | "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", 2550 | "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", 2551 | "dependencies": { 2552 | "any-promise": "^1.0.0", 2553 | "object-assign": "^4.0.1", 2554 | "thenify-all": "^1.0.0" 2555 | } 2556 | }, 2557 | "node_modules/nanoid": { 2558 | "version": "3.3.8", 2559 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", 2560 | "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", 2561 | "funding": [ 2562 | { 2563 | "type": "github", 2564 | "url": "https://github.com/sponsors/ai" 2565 | } 2566 | ], 2567 | "bin": { 2568 | "nanoid": "bin/nanoid.cjs" 2569 | }, 2570 | "engines": { 2571 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 2572 | } 2573 | }, 2574 | "node_modules/natural-compare": { 2575 | "version": "1.4.0", 2576 | "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", 2577 | "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", 2578 | "dev": true 2579 | }, 2580 | "node_modules/node-releases": { 2581 | "version": "2.0.19", 2582 | "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", 2583 | "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", 2584 | "dev": true 2585 | }, 2586 | "node_modules/normalize-path": { 2587 | "version": "3.0.0", 2588 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 2589 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 2590 | "engines": { 2591 | "node": ">=0.10.0" 2592 | } 2593 | }, 2594 | "node_modules/normalize-range": { 2595 | "version": "0.1.2", 2596 | "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", 2597 | "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", 2598 | "dev": true, 2599 | "engines": { 2600 | "node": ">=0.10.0" 2601 | } 2602 | }, 2603 | "node_modules/object-assign": { 2604 | "version": "4.1.1", 2605 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 2606 | "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", 2607 | "engines": { 2608 | "node": ">=0.10.0" 2609 | } 2610 | }, 2611 | "node_modules/object-hash": { 2612 | "version": "3.0.0", 2613 | "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", 2614 | "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", 2615 | "engines": { 2616 | "node": ">= 6" 2617 | } 2618 | }, 2619 | "node_modules/optionator": { 2620 | "version": "0.9.4", 2621 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", 2622 | "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", 2623 | "dev": true, 2624 | "dependencies": { 2625 | "deep-is": "^0.1.3", 2626 | "fast-levenshtein": "^2.0.6", 2627 | "levn": "^0.4.1", 2628 | "prelude-ls": "^1.2.1", 2629 | "type-check": "^0.4.0", 2630 | "word-wrap": "^1.2.5" 2631 | }, 2632 | "engines": { 2633 | "node": ">= 0.8.0" 2634 | } 2635 | }, 2636 | "node_modules/p-limit": { 2637 | "version": "3.1.0", 2638 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", 2639 | "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", 2640 | "dev": true, 2641 | "dependencies": { 2642 | "yocto-queue": "^0.1.0" 2643 | }, 2644 | "engines": { 2645 | "node": ">=10" 2646 | }, 2647 | "funding": { 2648 | "url": "https://github.com/sponsors/sindresorhus" 2649 | } 2650 | }, 2651 | "node_modules/p-locate": { 2652 | "version": "5.0.0", 2653 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", 2654 | "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", 2655 | "dev": true, 2656 | "dependencies": { 2657 | "p-limit": "^3.0.2" 2658 | }, 2659 | "engines": { 2660 | "node": ">=10" 2661 | }, 2662 | "funding": { 2663 | "url": "https://github.com/sponsors/sindresorhus" 2664 | } 2665 | }, 2666 | "node_modules/package-json-from-dist": { 2667 | "version": "1.0.1", 2668 | "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", 2669 | "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==" 2670 | }, 2671 | "node_modules/parent-module": { 2672 | "version": "1.0.1", 2673 | "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", 2674 | "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", 2675 | "dev": true, 2676 | "dependencies": { 2677 | "callsites": "^3.0.0" 2678 | }, 2679 | "engines": { 2680 | "node": ">=6" 2681 | } 2682 | }, 2683 | "node_modules/path-exists": { 2684 | "version": "4.0.0", 2685 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", 2686 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", 2687 | "dev": true, 2688 | "engines": { 2689 | "node": ">=8" 2690 | } 2691 | }, 2692 | "node_modules/path-key": { 2693 | "version": "3.1.1", 2694 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", 2695 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", 2696 | "engines": { 2697 | "node": ">=8" 2698 | } 2699 | }, 2700 | "node_modules/path-parse": { 2701 | "version": "1.0.7", 2702 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 2703 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" 2704 | }, 2705 | "node_modules/path-scurry": { 2706 | "version": "1.11.1", 2707 | "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", 2708 | "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", 2709 | "dependencies": { 2710 | "lru-cache": "^10.2.0", 2711 | "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" 2712 | }, 2713 | "engines": { 2714 | "node": ">=16 || 14 >=14.18" 2715 | }, 2716 | "funding": { 2717 | "url": "https://github.com/sponsors/isaacs" 2718 | } 2719 | }, 2720 | "node_modules/picocolors": { 2721 | "version": "1.1.1", 2722 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", 2723 | "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" 2724 | }, 2725 | "node_modules/picomatch": { 2726 | "version": "2.3.1", 2727 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 2728 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 2729 | "engines": { 2730 | "node": ">=8.6" 2731 | }, 2732 | "funding": { 2733 | "url": "https://github.com/sponsors/jonschlinkert" 2734 | } 2735 | }, 2736 | "node_modules/pify": { 2737 | "version": "2.3.0", 2738 | "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", 2739 | "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", 2740 | "engines": { 2741 | "node": ">=0.10.0" 2742 | } 2743 | }, 2744 | "node_modules/pirates": { 2745 | "version": "4.0.6", 2746 | "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", 2747 | "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", 2748 | "engines": { 2749 | "node": ">= 6" 2750 | } 2751 | }, 2752 | "node_modules/postcss": { 2753 | "version": "8.5.3", 2754 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", 2755 | "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", 2756 | "funding": [ 2757 | { 2758 | "type": "opencollective", 2759 | "url": "https://opencollective.com/postcss/" 2760 | }, 2761 | { 2762 | "type": "tidelift", 2763 | "url": "https://tidelift.com/funding/github/npm/postcss" 2764 | }, 2765 | { 2766 | "type": "github", 2767 | "url": "https://github.com/sponsors/ai" 2768 | } 2769 | ], 2770 | "license": "MIT", 2771 | "dependencies": { 2772 | "nanoid": "^3.3.8", 2773 | "picocolors": "^1.1.1", 2774 | "source-map-js": "^1.2.1" 2775 | }, 2776 | "engines": { 2777 | "node": "^10 || ^12 || >=14" 2778 | } 2779 | }, 2780 | "node_modules/postcss-import": { 2781 | "version": "15.1.0", 2782 | "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", 2783 | "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", 2784 | "dependencies": { 2785 | "postcss-value-parser": "^4.0.0", 2786 | "read-cache": "^1.0.0", 2787 | "resolve": "^1.1.7" 2788 | }, 2789 | "engines": { 2790 | "node": ">=14.0.0" 2791 | }, 2792 | "peerDependencies": { 2793 | "postcss": "^8.0.0" 2794 | } 2795 | }, 2796 | "node_modules/postcss-js": { 2797 | "version": "4.0.1", 2798 | "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", 2799 | "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", 2800 | "dependencies": { 2801 | "camelcase-css": "^2.0.1" 2802 | }, 2803 | "engines": { 2804 | "node": "^12 || ^14 || >= 16" 2805 | }, 2806 | "funding": { 2807 | "type": "opencollective", 2808 | "url": "https://opencollective.com/postcss/" 2809 | }, 2810 | "peerDependencies": { 2811 | "postcss": "^8.4.21" 2812 | } 2813 | }, 2814 | "node_modules/postcss-load-config": { 2815 | "version": "3.1.4", 2816 | "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", 2817 | "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", 2818 | "dev": true, 2819 | "dependencies": { 2820 | "lilconfig": "^2.0.5", 2821 | "yaml": "^1.10.2" 2822 | }, 2823 | "engines": { 2824 | "node": ">= 10" 2825 | }, 2826 | "funding": { 2827 | "type": "opencollective", 2828 | "url": "https://opencollective.com/postcss/" 2829 | }, 2830 | "peerDependencies": { 2831 | "postcss": ">=8.0.9", 2832 | "ts-node": ">=9.0.0" 2833 | }, 2834 | "peerDependenciesMeta": { 2835 | "postcss": { 2836 | "optional": true 2837 | }, 2838 | "ts-node": { 2839 | "optional": true 2840 | } 2841 | } 2842 | }, 2843 | "node_modules/postcss-load-config/node_modules/yaml": { 2844 | "version": "1.10.2", 2845 | "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", 2846 | "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", 2847 | "dev": true, 2848 | "license": "ISC", 2849 | "engines": { 2850 | "node": ">= 6" 2851 | } 2852 | }, 2853 | "node_modules/postcss-nested": { 2854 | "version": "6.2.0", 2855 | "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", 2856 | "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", 2857 | "funding": [ 2858 | { 2859 | "type": "opencollective", 2860 | "url": "https://opencollective.com/postcss/" 2861 | }, 2862 | { 2863 | "type": "github", 2864 | "url": "https://github.com/sponsors/ai" 2865 | } 2866 | ], 2867 | "dependencies": { 2868 | "postcss-selector-parser": "^6.1.1" 2869 | }, 2870 | "engines": { 2871 | "node": ">=12.0" 2872 | }, 2873 | "peerDependencies": { 2874 | "postcss": "^8.2.14" 2875 | } 2876 | }, 2877 | "node_modules/postcss-nested/node_modules/postcss-selector-parser": { 2878 | "version": "6.1.2", 2879 | "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", 2880 | "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", 2881 | "dependencies": { 2882 | "cssesc": "^3.0.0", 2883 | "util-deprecate": "^1.0.2" 2884 | }, 2885 | "engines": { 2886 | "node": ">=4" 2887 | } 2888 | }, 2889 | "node_modules/postcss-safe-parser": { 2890 | "version": "6.0.0", 2891 | "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz", 2892 | "integrity": "sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==", 2893 | "dev": true, 2894 | "engines": { 2895 | "node": ">=12.0" 2896 | }, 2897 | "funding": { 2898 | "type": "opencollective", 2899 | "url": "https://opencollective.com/postcss/" 2900 | }, 2901 | "peerDependencies": { 2902 | "postcss": "^8.3.3" 2903 | } 2904 | }, 2905 | "node_modules/postcss-scss": { 2906 | "version": "4.0.9", 2907 | "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.9.tgz", 2908 | "integrity": "sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==", 2909 | "dev": true, 2910 | "funding": [ 2911 | { 2912 | "type": "opencollective", 2913 | "url": "https://opencollective.com/postcss/" 2914 | }, 2915 | { 2916 | "type": "tidelift", 2917 | "url": "https://tidelift.com/funding/github/npm/postcss-scss" 2918 | }, 2919 | { 2920 | "type": "github", 2921 | "url": "https://github.com/sponsors/ai" 2922 | } 2923 | ], 2924 | "engines": { 2925 | "node": ">=12.0" 2926 | }, 2927 | "peerDependencies": { 2928 | "postcss": "^8.4.29" 2929 | } 2930 | }, 2931 | "node_modules/postcss-selector-parser": { 2932 | "version": "6.0.10", 2933 | "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", 2934 | "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", 2935 | "dependencies": { 2936 | "cssesc": "^3.0.0", 2937 | "util-deprecate": "^1.0.2" 2938 | }, 2939 | "engines": { 2940 | "node": ">=4" 2941 | } 2942 | }, 2943 | "node_modules/postcss-value-parser": { 2944 | "version": "4.2.0", 2945 | "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", 2946 | "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" 2947 | }, 2948 | "node_modules/prelude-ls": { 2949 | "version": "1.2.1", 2950 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", 2951 | "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", 2952 | "dev": true, 2953 | "engines": { 2954 | "node": ">= 0.8.0" 2955 | } 2956 | }, 2957 | "node_modules/prettier": { 2958 | "version": "3.4.2", 2959 | "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz", 2960 | "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==", 2961 | "dev": true, 2962 | "bin": { 2963 | "prettier": "bin/prettier.cjs" 2964 | }, 2965 | "engines": { 2966 | "node": ">=14" 2967 | }, 2968 | "funding": { 2969 | "url": "https://github.com/prettier/prettier?sponsor=1" 2970 | } 2971 | }, 2972 | "node_modules/prettier-plugin-svelte": { 2973 | "version": "3.3.2", 2974 | "resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-3.3.2.tgz", 2975 | "integrity": "sha512-kRPjH8wSj2iu+dO+XaUv4vD8qr5mdDmlak3IT/7AOgGIMRG86z/EHOLauFcClKEnOUf4A4nOA7sre5KrJD4Raw==", 2976 | "dev": true, 2977 | "peerDependencies": { 2978 | "prettier": "^3.0.0", 2979 | "svelte": "^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0" 2980 | } 2981 | }, 2982 | "node_modules/punycode": { 2983 | "version": "2.3.1", 2984 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", 2985 | "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", 2986 | "dev": true, 2987 | "engines": { 2988 | "node": ">=6" 2989 | } 2990 | }, 2991 | "node_modules/queue-microtask": { 2992 | "version": "1.2.3", 2993 | "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", 2994 | "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", 2995 | "funding": [ 2996 | { 2997 | "type": "github", 2998 | "url": "https://github.com/sponsors/feross" 2999 | }, 3000 | { 3001 | "type": "patreon", 3002 | "url": "https://www.patreon.com/feross" 3003 | }, 3004 | { 3005 | "type": "consulting", 3006 | "url": "https://feross.org/support" 3007 | } 3008 | ] 3009 | }, 3010 | "node_modules/read-cache": { 3011 | "version": "1.0.0", 3012 | "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", 3013 | "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", 3014 | "dependencies": { 3015 | "pify": "^2.3.0" 3016 | } 3017 | }, 3018 | "node_modules/readdirp": { 3019 | "version": "3.6.0", 3020 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 3021 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 3022 | "dependencies": { 3023 | "picomatch": "^2.2.1" 3024 | }, 3025 | "engines": { 3026 | "node": ">=8.10.0" 3027 | } 3028 | }, 3029 | "node_modules/resolve": { 3030 | "version": "1.22.10", 3031 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", 3032 | "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", 3033 | "dependencies": { 3034 | "is-core-module": "^2.16.0", 3035 | "path-parse": "^1.0.7", 3036 | "supports-preserve-symlinks-flag": "^1.0.0" 3037 | }, 3038 | "bin": { 3039 | "resolve": "bin/resolve" 3040 | }, 3041 | "engines": { 3042 | "node": ">= 0.4" 3043 | }, 3044 | "funding": { 3045 | "url": "https://github.com/sponsors/ljharb" 3046 | } 3047 | }, 3048 | "node_modules/resolve-from": { 3049 | "version": "4.0.0", 3050 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", 3051 | "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", 3052 | "dev": true, 3053 | "engines": { 3054 | "node": ">=4" 3055 | } 3056 | }, 3057 | "node_modules/reusify": { 3058 | "version": "1.0.4", 3059 | "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", 3060 | "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", 3061 | "engines": { 3062 | "iojs": ">=1.0.0", 3063 | "node": ">=0.10.0" 3064 | } 3065 | }, 3066 | "node_modules/rollup": { 3067 | "version": "4.35.0", 3068 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.35.0.tgz", 3069 | "integrity": "sha512-kg6oI4g+vc41vePJyO6dHt/yl0Rz3Thv0kJeVQ3D1kS3E5XSuKbPc29G4IpT/Kv1KQwgHVcN+HtyS+HYLNSvQg==", 3070 | "dev": true, 3071 | "license": "MIT", 3072 | "dependencies": { 3073 | "@types/estree": "1.0.6" 3074 | }, 3075 | "bin": { 3076 | "rollup": "dist/bin/rollup" 3077 | }, 3078 | "engines": { 3079 | "node": ">=18.0.0", 3080 | "npm": ">=8.0.0" 3081 | }, 3082 | "optionalDependencies": { 3083 | "@rollup/rollup-android-arm-eabi": "4.35.0", 3084 | "@rollup/rollup-android-arm64": "4.35.0", 3085 | "@rollup/rollup-darwin-arm64": "4.35.0", 3086 | "@rollup/rollup-darwin-x64": "4.35.0", 3087 | "@rollup/rollup-freebsd-arm64": "4.35.0", 3088 | "@rollup/rollup-freebsd-x64": "4.35.0", 3089 | "@rollup/rollup-linux-arm-gnueabihf": "4.35.0", 3090 | "@rollup/rollup-linux-arm-musleabihf": "4.35.0", 3091 | "@rollup/rollup-linux-arm64-gnu": "4.35.0", 3092 | "@rollup/rollup-linux-arm64-musl": "4.35.0", 3093 | "@rollup/rollup-linux-loongarch64-gnu": "4.35.0", 3094 | "@rollup/rollup-linux-powerpc64le-gnu": "4.35.0", 3095 | "@rollup/rollup-linux-riscv64-gnu": "4.35.0", 3096 | "@rollup/rollup-linux-s390x-gnu": "4.35.0", 3097 | "@rollup/rollup-linux-x64-gnu": "4.35.0", 3098 | "@rollup/rollup-linux-x64-musl": "4.35.0", 3099 | "@rollup/rollup-win32-arm64-msvc": "4.35.0", 3100 | "@rollup/rollup-win32-ia32-msvc": "4.35.0", 3101 | "@rollup/rollup-win32-x64-msvc": "4.35.0", 3102 | "fsevents": "~2.3.2" 3103 | } 3104 | }, 3105 | "node_modules/run-parallel": { 3106 | "version": "1.2.0", 3107 | "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", 3108 | "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", 3109 | "funding": [ 3110 | { 3111 | "type": "github", 3112 | "url": "https://github.com/sponsors/feross" 3113 | }, 3114 | { 3115 | "type": "patreon", 3116 | "url": "https://www.patreon.com/feross" 3117 | }, 3118 | { 3119 | "type": "consulting", 3120 | "url": "https://feross.org/support" 3121 | } 3122 | ], 3123 | "dependencies": { 3124 | "queue-microtask": "^1.2.2" 3125 | } 3126 | }, 3127 | "node_modules/sade": { 3128 | "version": "1.8.1", 3129 | "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", 3130 | "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", 3131 | "dev": true, 3132 | "dependencies": { 3133 | "mri": "^1.1.0" 3134 | }, 3135 | "engines": { 3136 | "node": ">=6" 3137 | } 3138 | }, 3139 | "node_modules/semver": { 3140 | "version": "7.6.3", 3141 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", 3142 | "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", 3143 | "dev": true, 3144 | "bin": { 3145 | "semver": "bin/semver.js" 3146 | }, 3147 | "engines": { 3148 | "node": ">=10" 3149 | } 3150 | }, 3151 | "node_modules/set-cookie-parser": { 3152 | "version": "2.7.1", 3153 | "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", 3154 | "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", 3155 | "dev": true 3156 | }, 3157 | "node_modules/shebang-command": { 3158 | "version": "2.0.0", 3159 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", 3160 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", 3161 | "dependencies": { 3162 | "shebang-regex": "^3.0.0" 3163 | }, 3164 | "engines": { 3165 | "node": ">=8" 3166 | } 3167 | }, 3168 | "node_modules/shebang-regex": { 3169 | "version": "3.0.0", 3170 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", 3171 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", 3172 | "engines": { 3173 | "node": ">=8" 3174 | } 3175 | }, 3176 | "node_modules/signal-exit": { 3177 | "version": "4.1.0", 3178 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", 3179 | "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", 3180 | "engines": { 3181 | "node": ">=14" 3182 | }, 3183 | "funding": { 3184 | "url": "https://github.com/sponsors/isaacs" 3185 | } 3186 | }, 3187 | "node_modules/sirv": { 3188 | "version": "3.0.0", 3189 | "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.0.tgz", 3190 | "integrity": "sha512-BPwJGUeDaDCHihkORDchNyyTvWFhcusy1XMmhEVTQTwGeybFbp8YEmB+njbPnth1FibULBSBVwCQni25XlCUDg==", 3191 | "dev": true, 3192 | "dependencies": { 3193 | "@polka/url": "^1.0.0-next.24", 3194 | "mrmime": "^2.0.0", 3195 | "totalist": "^3.0.0" 3196 | }, 3197 | "engines": { 3198 | "node": ">=18" 3199 | } 3200 | }, 3201 | "node_modules/source-map-js": { 3202 | "version": "1.2.1", 3203 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", 3204 | "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", 3205 | "engines": { 3206 | "node": ">=0.10.0" 3207 | } 3208 | }, 3209 | "node_modules/string-width": { 3210 | "version": "5.1.2", 3211 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", 3212 | "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", 3213 | "dependencies": { 3214 | "eastasianwidth": "^0.2.0", 3215 | "emoji-regex": "^9.2.2", 3216 | "strip-ansi": "^7.0.1" 3217 | }, 3218 | "engines": { 3219 | "node": ">=12" 3220 | }, 3221 | "funding": { 3222 | "url": "https://github.com/sponsors/sindresorhus" 3223 | } 3224 | }, 3225 | "node_modules/string-width-cjs": { 3226 | "name": "string-width", 3227 | "version": "4.2.3", 3228 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 3229 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 3230 | "dependencies": { 3231 | "emoji-regex": "^8.0.0", 3232 | "is-fullwidth-code-point": "^3.0.0", 3233 | "strip-ansi": "^6.0.1" 3234 | }, 3235 | "engines": { 3236 | "node": ">=8" 3237 | } 3238 | }, 3239 | "node_modules/string-width-cjs/node_modules/ansi-regex": { 3240 | "version": "5.0.1", 3241 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 3242 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 3243 | "engines": { 3244 | "node": ">=8" 3245 | } 3246 | }, 3247 | "node_modules/string-width-cjs/node_modules/emoji-regex": { 3248 | "version": "8.0.0", 3249 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 3250 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" 3251 | }, 3252 | "node_modules/string-width-cjs/node_modules/strip-ansi": { 3253 | "version": "6.0.1", 3254 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 3255 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 3256 | "dependencies": { 3257 | "ansi-regex": "^5.0.1" 3258 | }, 3259 | "engines": { 3260 | "node": ">=8" 3261 | } 3262 | }, 3263 | "node_modules/strip-ansi": { 3264 | "version": "7.1.0", 3265 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", 3266 | "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", 3267 | "dependencies": { 3268 | "ansi-regex": "^6.0.1" 3269 | }, 3270 | "engines": { 3271 | "node": ">=12" 3272 | }, 3273 | "funding": { 3274 | "url": "https://github.com/chalk/strip-ansi?sponsor=1" 3275 | } 3276 | }, 3277 | "node_modules/strip-ansi-cjs": { 3278 | "name": "strip-ansi", 3279 | "version": "6.0.1", 3280 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 3281 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 3282 | "dependencies": { 3283 | "ansi-regex": "^5.0.1" 3284 | }, 3285 | "engines": { 3286 | "node": ">=8" 3287 | } 3288 | }, 3289 | "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { 3290 | "version": "5.0.1", 3291 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 3292 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 3293 | "engines": { 3294 | "node": ">=8" 3295 | } 3296 | }, 3297 | "node_modules/strip-json-comments": { 3298 | "version": "3.1.1", 3299 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", 3300 | "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", 3301 | "dev": true, 3302 | "engines": { 3303 | "node": ">=8" 3304 | }, 3305 | "funding": { 3306 | "url": "https://github.com/sponsors/sindresorhus" 3307 | } 3308 | }, 3309 | "node_modules/sucrase": { 3310 | "version": "3.35.0", 3311 | "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", 3312 | "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", 3313 | "dependencies": { 3314 | "@jridgewell/gen-mapping": "^0.3.2", 3315 | "commander": "^4.0.0", 3316 | "glob": "^10.3.10", 3317 | "lines-and-columns": "^1.1.6", 3318 | "mz": "^2.7.0", 3319 | "pirates": "^4.0.1", 3320 | "ts-interface-checker": "^0.1.9" 3321 | }, 3322 | "bin": { 3323 | "sucrase": "bin/sucrase", 3324 | "sucrase-node": "bin/sucrase-node" 3325 | }, 3326 | "engines": { 3327 | "node": ">=16 || 14 >=14.17" 3328 | } 3329 | }, 3330 | "node_modules/supports-color": { 3331 | "version": "7.2.0", 3332 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 3333 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 3334 | "dev": true, 3335 | "dependencies": { 3336 | "has-flag": "^4.0.0" 3337 | }, 3338 | "engines": { 3339 | "node": ">=8" 3340 | } 3341 | }, 3342 | "node_modules/supports-preserve-symlinks-flag": { 3343 | "version": "1.0.0", 3344 | "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", 3345 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", 3346 | "engines": { 3347 | "node": ">= 0.4" 3348 | }, 3349 | "funding": { 3350 | "url": "https://github.com/sponsors/ljharb" 3351 | } 3352 | }, 3353 | "node_modules/svelte": { 3354 | "version": "5.16.0", 3355 | "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.16.0.tgz", 3356 | "integrity": "sha512-Ygqsiac6UogVED2ruKclU+pOeMThxWtp9LG+li7BXeDKC2paVIsRTMkNmcON4Zejerd1s5sZHWx6ZtU85xklVg==", 3357 | "dev": true, 3358 | "dependencies": { 3359 | "@ampproject/remapping": "^2.3.0", 3360 | "@jridgewell/sourcemap-codec": "^1.5.0", 3361 | "@types/estree": "^1.0.5", 3362 | "acorn": "^8.12.1", 3363 | "acorn-typescript": "^1.4.13", 3364 | "aria-query": "^5.3.1", 3365 | "axobject-query": "^4.1.0", 3366 | "clsx": "^2.1.1", 3367 | "esm-env": "^1.2.1", 3368 | "esrap": "^1.3.2", 3369 | "is-reference": "^3.0.3", 3370 | "locate-character": "^3.0.0", 3371 | "magic-string": "^0.30.11", 3372 | "zimmerframe": "^1.1.2" 3373 | }, 3374 | "engines": { 3375 | "node": ">=18" 3376 | } 3377 | }, 3378 | "node_modules/svelte-eslint-parser": { 3379 | "version": "0.43.0", 3380 | "resolved": "https://registry.npmjs.org/svelte-eslint-parser/-/svelte-eslint-parser-0.43.0.tgz", 3381 | "integrity": "sha512-GpU52uPKKcVnh8tKN5P4UZpJ/fUDndmq7wfsvoVXsyP+aY0anol7Yqo01fyrlaWGMFfm4av5DyrjlaXdLRJvGA==", 3382 | "dev": true, 3383 | "dependencies": { 3384 | "eslint-scope": "^7.2.2", 3385 | "eslint-visitor-keys": "^3.4.3", 3386 | "espree": "^9.6.1", 3387 | "postcss": "^8.4.39", 3388 | "postcss-scss": "^4.0.9" 3389 | }, 3390 | "engines": { 3391 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 3392 | }, 3393 | "funding": { 3394 | "url": "https://github.com/sponsors/ota-meshi" 3395 | }, 3396 | "peerDependencies": { 3397 | "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0" 3398 | }, 3399 | "peerDependenciesMeta": { 3400 | "svelte": { 3401 | "optional": true 3402 | } 3403 | } 3404 | }, 3405 | "node_modules/svelte-eslint-parser/node_modules/eslint-scope": { 3406 | "version": "7.2.2", 3407 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", 3408 | "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", 3409 | "dev": true, 3410 | "dependencies": { 3411 | "esrecurse": "^4.3.0", 3412 | "estraverse": "^5.2.0" 3413 | }, 3414 | "engines": { 3415 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 3416 | }, 3417 | "funding": { 3418 | "url": "https://opencollective.com/eslint" 3419 | } 3420 | }, 3421 | "node_modules/svelte-eslint-parser/node_modules/eslint-visitor-keys": { 3422 | "version": "3.4.3", 3423 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", 3424 | "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", 3425 | "dev": true, 3426 | "engines": { 3427 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 3428 | }, 3429 | "funding": { 3430 | "url": "https://opencollective.com/eslint" 3431 | } 3432 | }, 3433 | "node_modules/svelte-eslint-parser/node_modules/espree": { 3434 | "version": "9.6.1", 3435 | "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", 3436 | "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", 3437 | "dev": true, 3438 | "dependencies": { 3439 | "acorn": "^8.9.0", 3440 | "acorn-jsx": "^5.3.2", 3441 | "eslint-visitor-keys": "^3.4.1" 3442 | }, 3443 | "engines": { 3444 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 3445 | }, 3446 | "funding": { 3447 | "url": "https://opencollective.com/eslint" 3448 | } 3449 | }, 3450 | "node_modules/tailwindcss": { 3451 | "version": "3.4.17", 3452 | "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz", 3453 | "integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==", 3454 | "dependencies": { 3455 | "@alloc/quick-lru": "^5.2.0", 3456 | "arg": "^5.0.2", 3457 | "chokidar": "^3.6.0", 3458 | "didyoumean": "^1.2.2", 3459 | "dlv": "^1.1.3", 3460 | "fast-glob": "^3.3.2", 3461 | "glob-parent": "^6.0.2", 3462 | "is-glob": "^4.0.3", 3463 | "jiti": "^1.21.6", 3464 | "lilconfig": "^3.1.3", 3465 | "micromatch": "^4.0.8", 3466 | "normalize-path": "^3.0.0", 3467 | "object-hash": "^3.0.0", 3468 | "picocolors": "^1.1.1", 3469 | "postcss": "^8.4.47", 3470 | "postcss-import": "^15.1.0", 3471 | "postcss-js": "^4.0.1", 3472 | "postcss-load-config": "^4.0.2", 3473 | "postcss-nested": "^6.2.0", 3474 | "postcss-selector-parser": "^6.1.2", 3475 | "resolve": "^1.22.8", 3476 | "sucrase": "^3.35.0" 3477 | }, 3478 | "bin": { 3479 | "tailwind": "lib/cli.js", 3480 | "tailwindcss": "lib/cli.js" 3481 | }, 3482 | "engines": { 3483 | "node": ">=14.0.0" 3484 | } 3485 | }, 3486 | "node_modules/tailwindcss/node_modules/lilconfig": { 3487 | "version": "3.1.3", 3488 | "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", 3489 | "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", 3490 | "engines": { 3491 | "node": ">=14" 3492 | }, 3493 | "funding": { 3494 | "url": "https://github.com/sponsors/antonk52" 3495 | } 3496 | }, 3497 | "node_modules/tailwindcss/node_modules/postcss-load-config": { 3498 | "version": "4.0.2", 3499 | "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", 3500 | "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", 3501 | "funding": [ 3502 | { 3503 | "type": "opencollective", 3504 | "url": "https://opencollective.com/postcss/" 3505 | }, 3506 | { 3507 | "type": "github", 3508 | "url": "https://github.com/sponsors/ai" 3509 | } 3510 | ], 3511 | "dependencies": { 3512 | "lilconfig": "^3.0.0", 3513 | "yaml": "^2.3.4" 3514 | }, 3515 | "engines": { 3516 | "node": ">= 14" 3517 | }, 3518 | "peerDependencies": { 3519 | "postcss": ">=8.0.9", 3520 | "ts-node": ">=9.0.0" 3521 | }, 3522 | "peerDependenciesMeta": { 3523 | "postcss": { 3524 | "optional": true 3525 | }, 3526 | "ts-node": { 3527 | "optional": true 3528 | } 3529 | } 3530 | }, 3531 | "node_modules/tailwindcss/node_modules/postcss-selector-parser": { 3532 | "version": "6.1.2", 3533 | "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", 3534 | "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", 3535 | "dependencies": { 3536 | "cssesc": "^3.0.0", 3537 | "util-deprecate": "^1.0.2" 3538 | }, 3539 | "engines": { 3540 | "node": ">=4" 3541 | } 3542 | }, 3543 | "node_modules/thenify": { 3544 | "version": "3.3.1", 3545 | "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", 3546 | "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", 3547 | "dependencies": { 3548 | "any-promise": "^1.0.0" 3549 | } 3550 | }, 3551 | "node_modules/thenify-all": { 3552 | "version": "1.6.0", 3553 | "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", 3554 | "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", 3555 | "dependencies": { 3556 | "thenify": ">= 3.1.0 < 4" 3557 | }, 3558 | "engines": { 3559 | "node": ">=0.8" 3560 | } 3561 | }, 3562 | "node_modules/tiny-glob": { 3563 | "version": "0.2.9", 3564 | "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz", 3565 | "integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==", 3566 | "dev": true, 3567 | "dependencies": { 3568 | "globalyzer": "0.1.0", 3569 | "globrex": "^0.1.2" 3570 | } 3571 | }, 3572 | "node_modules/to-regex-range": { 3573 | "version": "5.0.1", 3574 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 3575 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 3576 | "dependencies": { 3577 | "is-number": "^7.0.0" 3578 | }, 3579 | "engines": { 3580 | "node": ">=8.0" 3581 | } 3582 | }, 3583 | "node_modules/totalist": { 3584 | "version": "3.0.1", 3585 | "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", 3586 | "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", 3587 | "dev": true, 3588 | "engines": { 3589 | "node": ">=6" 3590 | } 3591 | }, 3592 | "node_modules/ts-interface-checker": { 3593 | "version": "0.1.13", 3594 | "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", 3595 | "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" 3596 | }, 3597 | "node_modules/type-check": { 3598 | "version": "0.4.0", 3599 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", 3600 | "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", 3601 | "dev": true, 3602 | "dependencies": { 3603 | "prelude-ls": "^1.2.1" 3604 | }, 3605 | "engines": { 3606 | "node": ">= 0.8.0" 3607 | } 3608 | }, 3609 | "node_modules/update-browserslist-db": { 3610 | "version": "1.1.1", 3611 | "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", 3612 | "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", 3613 | "dev": true, 3614 | "funding": [ 3615 | { 3616 | "type": "opencollective", 3617 | "url": "https://opencollective.com/browserslist" 3618 | }, 3619 | { 3620 | "type": "tidelift", 3621 | "url": "https://tidelift.com/funding/github/npm/browserslist" 3622 | }, 3623 | { 3624 | "type": "github", 3625 | "url": "https://github.com/sponsors/ai" 3626 | } 3627 | ], 3628 | "dependencies": { 3629 | "escalade": "^3.2.0", 3630 | "picocolors": "^1.1.0" 3631 | }, 3632 | "bin": { 3633 | "update-browserslist-db": "cli.js" 3634 | }, 3635 | "peerDependencies": { 3636 | "browserslist": ">= 4.21.0" 3637 | } 3638 | }, 3639 | "node_modules/uri-js": { 3640 | "version": "4.4.1", 3641 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", 3642 | "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", 3643 | "dev": true, 3644 | "dependencies": { 3645 | "punycode": "^2.1.0" 3646 | } 3647 | }, 3648 | "node_modules/util-deprecate": { 3649 | "version": "1.0.2", 3650 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 3651 | "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" 3652 | }, 3653 | "node_modules/vite": { 3654 | "version": "6.2.2", 3655 | "resolved": "https://registry.npmjs.org/vite/-/vite-6.2.2.tgz", 3656 | "integrity": "sha512-yW7PeMM+LkDzc7CgJuRLMW2Jz0FxMOsVJ8Lv3gpgW9WLcb9cTW+121UEr1hvmfR7w3SegR5ItvYyzVz1vxNJgQ==", 3657 | "dev": true, 3658 | "license": "MIT", 3659 | "dependencies": { 3660 | "esbuild": "^0.25.0", 3661 | "postcss": "^8.5.3", 3662 | "rollup": "^4.30.1" 3663 | }, 3664 | "bin": { 3665 | "vite": "bin/vite.js" 3666 | }, 3667 | "engines": { 3668 | "node": "^18.0.0 || ^20.0.0 || >=22.0.0" 3669 | }, 3670 | "funding": { 3671 | "url": "https://github.com/vitejs/vite?sponsor=1" 3672 | }, 3673 | "optionalDependencies": { 3674 | "fsevents": "~2.3.3" 3675 | }, 3676 | "peerDependencies": { 3677 | "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", 3678 | "jiti": ">=1.21.0", 3679 | "less": "*", 3680 | "lightningcss": "^1.21.0", 3681 | "sass": "*", 3682 | "sass-embedded": "*", 3683 | "stylus": "*", 3684 | "sugarss": "*", 3685 | "terser": "^5.16.0", 3686 | "tsx": "^4.8.1", 3687 | "yaml": "^2.4.2" 3688 | }, 3689 | "peerDependenciesMeta": { 3690 | "@types/node": { 3691 | "optional": true 3692 | }, 3693 | "jiti": { 3694 | "optional": true 3695 | }, 3696 | "less": { 3697 | "optional": true 3698 | }, 3699 | "lightningcss": { 3700 | "optional": true 3701 | }, 3702 | "sass": { 3703 | "optional": true 3704 | }, 3705 | "sass-embedded": { 3706 | "optional": true 3707 | }, 3708 | "stylus": { 3709 | "optional": true 3710 | }, 3711 | "sugarss": { 3712 | "optional": true 3713 | }, 3714 | "terser": { 3715 | "optional": true 3716 | }, 3717 | "tsx": { 3718 | "optional": true 3719 | }, 3720 | "yaml": { 3721 | "optional": true 3722 | } 3723 | } 3724 | }, 3725 | "node_modules/vitefu": { 3726 | "version": "1.0.4", 3727 | "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.0.4.tgz", 3728 | "integrity": "sha512-y6zEE3PQf6uu/Mt6DTJ9ih+kyJLr4XcSgHR2zUkM8SWDhuixEJxfJ6CZGMHh1Ec3vPLoEA0IHU5oWzVqw8ulow==", 3729 | "dev": true, 3730 | "workspaces": [ 3731 | "tests/deps/*", 3732 | "tests/projects/*" 3733 | ], 3734 | "peerDependencies": { 3735 | "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0" 3736 | }, 3737 | "peerDependenciesMeta": { 3738 | "vite": { 3739 | "optional": true 3740 | } 3741 | } 3742 | }, 3743 | "node_modules/which": { 3744 | "version": "2.0.2", 3745 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", 3746 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 3747 | "dependencies": { 3748 | "isexe": "^2.0.0" 3749 | }, 3750 | "bin": { 3751 | "node-which": "bin/node-which" 3752 | }, 3753 | "engines": { 3754 | "node": ">= 8" 3755 | } 3756 | }, 3757 | "node_modules/word-wrap": { 3758 | "version": "1.2.5", 3759 | "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", 3760 | "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", 3761 | "dev": true, 3762 | "engines": { 3763 | "node": ">=0.10.0" 3764 | } 3765 | }, 3766 | "node_modules/wrap-ansi": { 3767 | "version": "8.1.0", 3768 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", 3769 | "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", 3770 | "dependencies": { 3771 | "ansi-styles": "^6.1.0", 3772 | "string-width": "^5.0.1", 3773 | "strip-ansi": "^7.0.1" 3774 | }, 3775 | "engines": { 3776 | "node": ">=12" 3777 | }, 3778 | "funding": { 3779 | "url": "https://github.com/chalk/wrap-ansi?sponsor=1" 3780 | } 3781 | }, 3782 | "node_modules/wrap-ansi-cjs": { 3783 | "name": "wrap-ansi", 3784 | "version": "7.0.0", 3785 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", 3786 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", 3787 | "dependencies": { 3788 | "ansi-styles": "^4.0.0", 3789 | "string-width": "^4.1.0", 3790 | "strip-ansi": "^6.0.0" 3791 | }, 3792 | "engines": { 3793 | "node": ">=10" 3794 | }, 3795 | "funding": { 3796 | "url": "https://github.com/chalk/wrap-ansi?sponsor=1" 3797 | } 3798 | }, 3799 | "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { 3800 | "version": "5.0.1", 3801 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 3802 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 3803 | "engines": { 3804 | "node": ">=8" 3805 | } 3806 | }, 3807 | "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { 3808 | "version": "8.0.0", 3809 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 3810 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" 3811 | }, 3812 | "node_modules/wrap-ansi-cjs/node_modules/string-width": { 3813 | "version": "4.2.3", 3814 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 3815 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 3816 | "dependencies": { 3817 | "emoji-regex": "^8.0.0", 3818 | "is-fullwidth-code-point": "^3.0.0", 3819 | "strip-ansi": "^6.0.1" 3820 | }, 3821 | "engines": { 3822 | "node": ">=8" 3823 | } 3824 | }, 3825 | "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { 3826 | "version": "6.0.1", 3827 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 3828 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 3829 | "dependencies": { 3830 | "ansi-regex": "^5.0.1" 3831 | }, 3832 | "engines": { 3833 | "node": ">=8" 3834 | } 3835 | }, 3836 | "node_modules/wrap-ansi/node_modules/ansi-styles": { 3837 | "version": "6.2.1", 3838 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", 3839 | "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", 3840 | "engines": { 3841 | "node": ">=12" 3842 | }, 3843 | "funding": { 3844 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 3845 | } 3846 | }, 3847 | "node_modules/yaml": { 3848 | "version": "2.7.0", 3849 | "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz", 3850 | "integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==", 3851 | "license": "ISC", 3852 | "bin": { 3853 | "yaml": "bin.mjs" 3854 | }, 3855 | "engines": { 3856 | "node": ">= 14" 3857 | } 3858 | }, 3859 | "node_modules/yocto-queue": { 3860 | "version": "0.1.0", 3861 | "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", 3862 | "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", 3863 | "dev": true, 3864 | "engines": { 3865 | "node": ">=10" 3866 | }, 3867 | "funding": { 3868 | "url": "https://github.com/sponsors/sindresorhus" 3869 | } 3870 | }, 3871 | "node_modules/zimmerframe": { 3872 | "version": "1.1.2", 3873 | "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.2.tgz", 3874 | "integrity": "sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==", 3875 | "dev": true 3876 | } 3877 | } 3878 | } 3879 | -------------------------------------------------------------------------------- /web/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "web", 3 | "private": true, 4 | "version": "0.0.1", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite dev", 8 | "build": "vite build", 9 | "preview": "vite preview", 10 | "format": "prettier --write .", 11 | "lint": "prettier --check . && eslint ." 12 | }, 13 | "devDependencies": { 14 | "@eslint/compat": "^1.2.3", 15 | "@sveltejs/adapter-auto": "^3.0.0", 16 | "@sveltejs/adapter-static": "^3.0.8", 17 | "@sveltejs/kit": "^2.0.0", 18 | "@sveltejs/vite-plugin-svelte": "^5.0.3", 19 | "autoprefixer": "^10.4.20", 20 | "eslint": "^9.7.0", 21 | "eslint-config-prettier": "^9.1.0", 22 | "eslint-plugin-svelte": "^2.36.0", 23 | "globals": "^15.0.0", 24 | "prettier": "^3.3.2", 25 | "prettier-plugin-svelte": "^3.2.6", 26 | "svelte": "^5.0.0", 27 | "tailwindcss": "^3.4.9", 28 | "vite": "^6.2.2" 29 | }, 30 | "dependencies": { 31 | "@tailwindcss/container-queries": "^0.1.1", 32 | "@tailwindcss/forms": "^0.5.9", 33 | "@tailwindcss/typography": "^0.5.15" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /web/postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {} 5 | } 6 | }; 7 | -------------------------------------------------------------------------------- /web/src/app.css: -------------------------------------------------------------------------------- 1 | @import 'tailwindcss/base'; 2 | @import 'tailwindcss/components'; 3 | @import 'tailwindcss/utilities'; 4 | 5 | :root { 6 | /* Default theme colors that will be overridden by dynamic values */ 7 | --brand-primary: #3b82f6; 8 | --brand-secondary: #10b981; 9 | --brand-theme: #4caf50; 10 | } 11 | 12 | /* Add utility classes for dynamic colors */ 13 | .text-brand-primary { 14 | color: var(--brand-primary) !important; 15 | } 16 | 17 | .bg-brand-primary { 18 | background-color: var(--brand-primary) !important; 19 | } 20 | 21 | .text-brand-secondary { 22 | color: var(--brand-secondary) !important; 23 | } 24 | 25 | .bg-brand-secondary { 26 | background-color: var(--brand-secondary) !important; 27 | } 28 | 29 | html, 30 | body { 31 | margin: 0; 32 | padding: 0; 33 | height: 100%; 34 | overflow: hidden; 35 | } 36 | 37 | body { 38 | display: flex; 39 | flex-direction: column; 40 | } 41 | -------------------------------------------------------------------------------- /web/src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | GoShort - Simplify Your URLs 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | %sveltekit.head% 33 | 34 | 35 |
%sveltekit.body%
36 | 37 | 38 | -------------------------------------------------------------------------------- /web/src/components/Footer.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 | 34 | -------------------------------------------------------------------------------- /web/src/components/Main.svelte: -------------------------------------------------------------------------------- 1 | 73 | 74 |
75 |

{brandConfig.headerTitle}

76 | 77 |
78 | 79 |
80 | 81 | 90 | {#if validationError} 91 |

{validationError}

92 | {/if} 93 |
94 | 95 | 96 |
97 | 117 | {#if showAccordion} 118 |
119 | 120 |
121 | 122 | 129 |
130 | 131 | 132 |
133 | 134 | 140 |
141 |
142 | {/if} 143 |
144 | 145 | 146 | 152 |
153 | 154 | 155 | {#if shortUrl} 156 |
157 |

Your shortened URL is ready! 🚀

158 |
159 |
162 | {shortUrl} 163 |
164 | 174 |
175 |
176 | {/if} 177 | 178 | 179 | {#if errorMessage} 180 |
{errorMessage}
181 | {/if} 182 |
183 | -------------------------------------------------------------------------------- /web/src/lib/config.js: -------------------------------------------------------------------------------- 1 | // Default branding configuration 2 | export const defaultConfig = { 3 | title: 'GoShort - URL Shortener', 4 | description: 'GoShort is a powerful and user-friendly URL shortener. Simplify, manage, and track your links with ease.', 5 | keywords: 'URL shortener, GoShort, link management, shorten URLs, track links', 6 | author: 'GoShort Team', 7 | themeColor: '#4caf50', 8 | logoText: 'GoShort', 9 | primaryColor: '#3b82f6', // blue-600 10 | secondaryColor: '#10b981', // emerald-500 11 | headerTitle: 'GoShort - URL Shortener', 12 | footerText: 'View the project on GitHub', 13 | footerLink: 'https://github.com/kek-Sec/GoShort' 14 | }; 15 | 16 | // Load config from the server at runtime 17 | export const loadConfig = async () => { 18 | try { 19 | const response = await fetch('/api/v1/config'); 20 | if (response.ok) { 21 | const config = await response.json(); 22 | return { ...defaultConfig, ...config }; 23 | } 24 | return defaultConfig; 25 | } catch (error) { 26 | console.warn('Failed to load custom configuration, using defaults', error); 27 | return defaultConfig; 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /web/src/lib/index.js: -------------------------------------------------------------------------------- 1 | // place files you want to import through the `$lib` alias in this folder. 2 | -------------------------------------------------------------------------------- /web/src/routes/+layout.js: -------------------------------------------------------------------------------- 1 | import { loadConfig } from '$lib/config'; 2 | 3 | /** @type {import('./$types').LayoutLoad} */ 4 | export async function load() { 5 | const config = await loadConfig(); 6 | return { brandConfig: config }; 7 | } 8 | -------------------------------------------------------------------------------- /web/src/routes/+layout.server.js: -------------------------------------------------------------------------------- 1 | export const prerender = true; 2 | -------------------------------------------------------------------------------- /web/src/routes/+layout.svelte: -------------------------------------------------------------------------------- 1 | 15 | 16 | 17 | 18 | 19 | {brandConfig.title} 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | {@render children()} 29 | -------------------------------------------------------------------------------- /web/src/routes/+page.svelte: -------------------------------------------------------------------------------- 1 | 54 | 55 |
56 |
57 |
69 |
70 |
72 | -------------------------------------------------------------------------------- /web/static/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kek-Sec/GoShort/d73f1e7599915747514548ce1c80a015bbb55ab3/web/static/banner.png -------------------------------------------------------------------------------- /web/static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kek-Sec/GoShort/d73f1e7599915747514548ce1c80a015bbb55ab3/web/static/favicon.png -------------------------------------------------------------------------------- /web/svelte.config.js: -------------------------------------------------------------------------------- 1 | import adapter from '@sveltejs/adapter-static'; 2 | 3 | /** @type {import('@sveltejs/kit').Config} */ 4 | const config = { 5 | kit: { 6 | adapter: adapter({ 7 | // Configure the static site generation 8 | pages: 'build', // Output directory for prerendered pages 9 | assets: 'build', // Output directory for static assets 10 | fallback: 'index.html', // Enables SPA fallback 11 | precompress: false, // Disables precompression (gzip/brotli) 12 | strict: true // Ensures all routes are accounted for 13 | }), 14 | } 15 | }; 16 | 17 | export default config; 18 | -------------------------------------------------------------------------------- /web/tailwind.config.js: -------------------------------------------------------------------------------- 1 | import containerQueries from '@tailwindcss/container-queries'; 2 | import forms from '@tailwindcss/forms'; 3 | import typography from '@tailwindcss/typography'; 4 | 5 | /** @type {import('tailwindcss').Config} */ 6 | export default { 7 | content: ['./src/**/*.{html,js,svelte,ts}'], 8 | 9 | theme: { 10 | extend: {} 11 | }, 12 | 13 | // Add a safelist for dynamic classes 14 | safelist: [ 15 | 'text-brand-primary', 16 | 'bg-brand-primary', 17 | 'text-brand-secondary', 18 | 'bg-brand-secondary', 19 | 'ring-brand-primary', 20 | 'ring-brand-secondary', 21 | ], 22 | 23 | plugins: [typography, forms, containerQueries] 24 | }; 25 | -------------------------------------------------------------------------------- /web/vite.config.js: -------------------------------------------------------------------------------- 1 | import { sveltekit } from '@sveltejs/kit/vite'; 2 | import { defineConfig } from 'vite'; 3 | 4 | export default defineConfig({ 5 | plugins: [sveltekit()] 6 | }); 7 | --------------------------------------------------------------------------------