diff --git a/.github/workflows/checklist.yaml b/.github/workflows/checklist.yaml new file mode 100644 index 0000000..6243bb6 --- /dev/null +++ b/.github/workflows/checklist.yaml @@ -0,0 +1,73 @@ +name: Checklist + +on: + pull_request: + paths: + - 'CHANGELOG.md' + +jobs: + changelog: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + const path = 'CHANGELOG.md'; + const changelog = fs.readFileSync(path, 'utf8'); + let failed = false; + + try { + // Check each line that starts with '##' for the version & date format + changelog.split('\n').forEach((line, index) => { + index += 1; + + if (!line.startsWith('## ')) + return; + + if (line.toLowerCase().includes('unreleased')) { + const message = 'Unreleased section found. Please release the changes before merging.'; + core.error(message, { + title: 'Unreleased Section Found', + file: path, + startline: index, + }); + failed = true; + } + + // Expected format: '## [X.Y.Z] - YYYY-MM-DD' + const pattern = /^\d+\.\d+\.\d+ - \d{4}-\d{2}-\d{2}$/; + if (pattern.test(line)) { + const message = 'Invalid version/date format. Expected: "## [X.Y.Z] - YYYY-MM-DD"'; + core.error(message, { + title: 'Invalid Version/Date Format', + file: path, + startline: index, + }); + failed = true; + } + }); + + if (failed) { + core.setFailed('Changelog validation failed') + } + } catch (error) { + core.setFailed(`Exception occurred while validating changelog: ${error}`); + } + + draft: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/github-script@v7 + with: + script: | + const forbiddenLabels = ['draft']; + let labels = context.payload.pull_request.labels; + + if (labels.some(l => forbiddenLabels.includes(l.name))) { + core.setFailed(`Forbidden labels detected: ${forbiddenLabels.join(', ')}`); + } + + \ No newline at end of file diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml new file mode 100644 index 0000000..b35f8d3 --- /dev/null +++ b/.github/workflows/test.yaml @@ -0,0 +1,83 @@ +name: Pytest + +on: [pull_request] + +# https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs +# Required by MishaKav/pytest-coverage-comment +permissions: + contents: read + checks: write + pull-requests: write + +env: + POETRY_VERSION: 1.8.4 + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Set up python + id: setup-python + uses: actions/setup-python@v5 + with: + python-version: "3.12.7" + + - name: Install Poetry + uses: snok/install-poetry@v1 + with: + version: ${{ env.POETRY_VERSION }} + virtualenvs-create: true + virtualenvs-in-project: true + + - name: Load cached venv + id: cached-pip-wheels + uses: actions/cache@v4 + with: + # TODO: Apparently this is failing for some reason, path does not exist? Fix after 0.3.0 release + path: .venv # While ~/.cache is a fine default, I want to separate this cache from other caches + key: venv-${{ steps.setup-python.outputs.python-version }}-${{ env.POETRY_VERSION }}-${{ hashFiles('**/poetry.lock') }} + + - name: Install dependencies + run: cd backend && poetry install --no-interaction --no-root + + # Disable for now, remove if ultimately not needed. + # - name: Install library + # run: cd backend && poetry install --no-interaction + + - name: Acquire Database URL from Railway + env: + RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }} + SERVICE_ID: Postgres + ENVIRONMENT_ID: development + run: | + bash <(curl -fsSL cli.new) --verbose --yes + DATABASE_URL=$(railway variables --service $SERVICE_ID --environment $ENVIRONMENT_ID --json | jq -cMr .DATABASE_PUBLIC_URL) + echo "::add-mask::$DATABASE_URL" + echo "DATABASE_URL=$DATABASE_URL" >> "$GITHUB_ENV" + + - name: Pytest + env: + LOG_LEVEL: DEBUG + LOG_JSON_FORMAT: false + run: | + cd backend + set -o pipefail # otherwise 'tee' will eat the exit code + # TODO: Switch away from using the ENVIRONMENT variable during pytest or for anything at runtime + export ENVIRONMENT=development + poetry run pytest -n $(nproc) --color=yes --cov=linkpulse --cov-report=term-missing:skip-covered --junitxml=pytest.xml | tee pytest-coverage.txt + + # pytest-coverage-comment won't error if the files are missing + if [ ! -f ./pytest-coverage.txt ] || [ ! -f ./pytest.xml ]; then + echo "::error::Coverage files not found" + exit 1 + fi + + - name: Pytest coverage comment + id: coverageComment + uses: MishaKav/pytest-coverage-comment@main + with: + pytest-coverage-path: backend/pytest-coverage.txt + junitxml-path: backend/pytest.xml \ No newline at end of file diff --git a/.gitignore b/.gitignore index 75f933a..4c49bd7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,164 +1 @@ .env - -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -share/python-wheels/ -*.egg-info/ -.installed.cfg -*.egg -MANIFEST - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.nox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -*.py,cover -.hypothesis/ -.pytest_cache/ -cover/ - -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py -db.sqlite3 -db.sqlite3-journal - -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -.pybuilder/ -target/ - -# Jupyter Notebook -.ipynb_checkpoints - -# IPython -profile_default/ -ipython_config.py - -# pyenv -# For a library or package, you might want to ignore these files since the code is -# intended to run in multiple environments; otherwise, check them in: -# .python-version - -# pipenv -# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. -# However, in case of collaboration, if having platform-specific dependencies or dependencies -# having no cross-platform support, pipenv may install dependencies that don't work, or not -# install all needed dependencies. -#Pipfile.lock - -# poetry -# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. -# This is especially recommended for binary packages to ensure reproducibility, and is more -# commonly ignored for libraries. -# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control -#poetry.lock - -# pdm -# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. -#pdm.lock -# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it -# in version control. -# https://pdm.fming.dev/latest/usage/project/#working-with-version-control -.pdm.toml -.pdm-python -.pdm-build/ - -# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm -__pypackages__/ - -# Celery stuff -celerybeat-schedule -celerybeat.pid - -# SageMath parsed files -*.sage.py - -# Environments -.env -.venv -env/ -venv/ -ENV/ -env.bak/ -venv.bak/ - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json - -# Pyre type checker -.pyre/ - -# pytype static type analyzer -.pytype/ - -# Cython debug symbols -cython_debug/ - -# PyCharm -# JetBrains specific template is maintained in a separate JetBrains.gitignore that can -# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore -# and can be added to the global gitignore or merged into this file. For a more nuclear -# option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 987f3c4..d219a51 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,18 +1,65 @@ { "cSpell.words": [ "apscheduler", + "Avenir", + "backref", "bpython", "Callsite", + "clsx", "excepthook", + "httpx", + "humanfs", + "humanwhocodes", "inmemory", + "jridgewell", "linkpulse", "migratehistory", "Nixpacks", + "nkzw", + "nocheck", "ORJSON", + "pacakges", + "pext", + "postcss", + "pwdlib", + "pyproject", + "pytest", "pytz", + "riscv", + "rollup", + "rtype", + "shadcn", "starlette", "structlog", - "timestamper" + "sugarss", + "tailwindcss", + "tanstack", + "timestamper", + "tseslint", + "vitest", + "xdist", + "Zustand's" ], - "python.analysis.extraPaths": ["./backend/"] + "python.analysis.extraPaths": ["./backend/"], + "editor.formatOnSave": true, + "[github-actions-workflow]": { + "editor.formatOnSave": false + }, + "python.analysis.diagnosticMode": "workspace", + "cSpell.ignorePaths": [ + "package-lock.json", + "node_modules", + "vscode-extension", + ".git/objects", + ".vscode", + ".vscode-insiders", + "settings.json", + "*.lock", + "*lock.*", + "package.json", + "routeTree.gen.ts" + ], + "files.associations": { + "Caddyfile.*": "caddyfile" + } } diff --git a/CHANGELOG.md b/CHANGELOG.md index 281de67..c95ddf4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,37 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.3.0] + +## Added + +- A release checklist to the `CHANGELOG.md` file, as a reminder for procedure. +- An action workflow for invoking `pytest`, with coverage report generation in CI/CD +- backend: Login & Logout routes +- backend: Rate Limiting via custom `RateLimiter` dependency +- backend: `User` model, `Session` model with migration script +- backend: `Session` model constraints for `token` length, `expiry` & `last_used` timestamps +- backend: `SessionDependency` for easy session validation, enforcement & handling per route +- backend: provided `LOG_JSON_FORMAT` and `LOG_LEVEL` environment variable defaults in `run.sh` development script +- backend: Simple `/health` & `/api/migrations` endpoint tests +- backend: `utc_now` helper function +- backend: `pwdlib[argon2]`, `pytest` (`pytest-cov`, `pytest-xdist`), `limits`, `httpx`, `email-validator` pacakges +- frontend: Re-initialized with `vite` template, setup `@tanstack/router` & `shadcn` components. +- frontend: Added Login & Register page, added basic authentication check with redirect +- frontend: Added Zustand state management, basic login & session API functions with `true-myth` types. +- frontend: Added `zustand`, `true-myth`, `@tanstack/router`, `clsx`, `tailwind-merge` packages + +## Changed + +- Set `black` formatter line length to 120 characters +- backend: migration squashing threshold to 15 +- backend: moved top level `app` routes to `router.misc` + +## Removed + +- frontend: Most old packages from initial `vite` template +- backend: `IPAddress` Model (definition + DB state via migration) & all related code + ## [0.2.2] - 2024-11-01 ### Added diff --git a/RELEASE_CHECKLIST.md b/RELEASE_CHECKLIST.md new file mode 100644 index 0000000..2a2b00d --- /dev/null +++ b/RELEASE_CHECKLIST.md @@ -0,0 +1,8 @@ +# Release Checklist + +1. Ensure `backend/pyproject.toml` and `frontend/package.json` have the correct version number for the upcoming release. +2. Ensure `CHANGELOG.md` contains all changes for the upcoming release, with the correct version number and date labeled. + - `Unreleased` section should not exist. + - The version should match `pyproject.toml` and `package.json`. +3. Ensure all tests pass locally, as well as the CI/CD pipeline. +4. Correct all linting errors and warnings. diff --git a/backend/.gitignore b/backend/.gitignore new file mode 100644 index 0000000..74d08e5 --- /dev/null +++ b/backend/.gitignore @@ -0,0 +1,165 @@ +pytest.xml +pytest-coverage.txt + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/latest/usage/project/#working-with-version-control +.pdm.toml +.pdm-python +.pdm-build/ + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ diff --git a/backend/linkpulse/__init__.py b/backend/linkpulse/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/linkpulse/__main__.py b/backend/linkpulse/__main__.py index 2d13d2b..5e9ad0a 100644 --- a/backend/linkpulse/__main__.py +++ b/backend/linkpulse/__main__.py @@ -16,17 +16,18 @@ setup_logging() import os import sys -import structlog +import structlog logger = structlog.get_logger() -def main(*args): - """ - Primary entrypoint for the LinkPulse application - - Don't import any modules globally unless you're certain it's necessary. Imports should be tightly controlled. - """ +def main(*args: str) -> None: + """Primary entrypoint for the LinkPulse application + NOTE: Don't import any modules globally unless you're certain it's necessary. Imports should be tightly controlled. + :param args: The command-line arguments to parse and execute. + :type args: str""" + if args[0] == "serve": from linkpulse.utilities import is_development from uvicorn import run @@ -57,9 +58,9 @@ def main(*args): # import most useful objects, models, and functions lp = linkpulse # alias - from linkpulse.utilities import get_db from linkpulse.app import app - from linkpulse.models import BaseModel, IPAddress + from linkpulse.models import BaseModel, Session, User + from linkpulse.utilities import get_db db = get_db() diff --git a/backend/linkpulse/app.py b/backend/linkpulse/app.py index b14601c..287c391 100644 --- a/backend/linkpulse/app.py +++ b/backend/linkpulse/app.py @@ -1,120 +1,53 @@ -import random -from collections import defaultdict from contextlib import asynccontextmanager -from dataclasses import dataclass, field -from datetime import datetime, timezone from typing import AsyncIterator -import human_readable -import pytz import structlog from apscheduler.schedulers.background import BackgroundScheduler # type: ignore from apscheduler.triggers.interval import IntervalTrigger # type: ignore from asgi_correlation_id import CorrelationIdMiddleware from dotenv import load_dotenv -from fastapi import FastAPI, Request, Response, status +from fastapi import FastAPI from fastapi.responses import ORJSONResponse from fastapi_cache import FastAPICache from fastapi_cache.backends.inmemory import InMemoryBackend -from fastapi_cache.decorator import cache from linkpulse.logging import setup_logging from linkpulse.middleware import LoggingMiddleware -from linkpulse.utilities import get_db, get_ip, hide_ip, is_development -from psycopg2.extras import execute_values +from linkpulse.utilities import get_db, is_development load_dotenv(dotenv_path=".env") -from linkpulse import models, responses # type: ignore +from linkpulse import models # type: ignore db = get_db() -def flush_ips(): - if len(app.state.buffered_updates) == 0: - logger.debug("No IPs to flush to Database") - return - - try: - with db.atomic(): - sql = """ - WITH updates (ip, last_seen, increment) AS (VALUES %s) - INSERT INTO ipaddress (ip, last_seen, count) - SELECT ip, last_seen, increment - FROM updates - ON CONFLICT (ip) - DO UPDATE - SET count = ipaddress.count + EXCLUDED.count, last_seen = EXCLUDED.last_seen; - """ - rows = [ - (ip, data.last_seen, data.count) - for ip, data in app.state.buffered_updates.items() - ] - - cur = db.cursor() - execute_values(cur, sql, rows) - except Exception as e: - logger.error("Failed to flush IPs to Database", error=e) - - i = len(app.state.buffered_updates) - logger.debug("IPs written to database", count=i) - - # Finish up - app.state.buffered_updates.clear() - - scheduler = BackgroundScheduler() -scheduler.add_job(flush_ips, IntervalTrigger(seconds=5)) @asynccontextmanager async def lifespan(_: FastAPI) -> AsyncIterator[None]: - # Originally, this was used to generate a pool of random IP addresses so we could demo a changing list. - # Now, this isn't necessary, but I just wanna test it for now. It'll be removed pretty soon. - random.seed(42) # 42 is the answer to everything - app.state.ip_pool = [ - ".".join(str(random.randint(0, 255)) for _ in range(4)) for _ in range(50) - ] - # Connect to database, ensure specific tables exist db.connect() - db.create_tables([models.IPAddress]) + db.create_tables([models.User, models.Session]) - # Delete all randomly generated IP addresses - with db.atomic(): - logger.info( - "Deleting Randomized IP Addresses", ip_pool_count=len(app.state.ip_pool) - ) - query = models.IPAddress.delete().where( - models.IPAddress.ip << app.state.ip_pool - ) - row_count = query.execute() - logger.info("Randomized IP Addresses deleted", row_count=row_count) - - FastAPICache.init( - backend=InMemoryBackend(), prefix="fastapi-cache", cache_status_header="X-Cache" - ) - - app.state.buffered_updates = defaultdict(IPCounter) + FastAPICache.init(backend=InMemoryBackend(), prefix="fastapi-cache", cache_status_header="X-Cache") scheduler.start() yield scheduler.shutdown() - flush_ips() if not db.is_closed(): db.close() -@dataclass -class IPCounter: - # Note: This is not the true 'seen' count, but the count of how many times the IP has been seen since the last flush. - count: int = 0 - last_seen: datetime = field(default_factory=lambda: datetime.now(timezone.utc)) - +from linkpulse.routers import auth, misc +# TODO: Apply migrations on startup in production environments app = FastAPI(lifespan=lifespan, default_response_class=ORJSONResponse) +app.include_router(auth.router) +app.include_router(misc.router) setup_logging() @@ -123,79 +56,19 @@ logger = structlog.get_logger() if is_development: from fastapi.middleware.cors import CORSMiddleware + origins = [ + "http://localhost:8080", + "http://localhost:5173", + ] + app.add_middleware( CORSMiddleware, - allow_origins=[ - "http://localhost", - "http://localhost:5173", - ], + allow_origins=origins, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) + logger.info("CORS Enabled", origins=origins) app.add_middleware(LoggingMiddleware) app.add_middleware(CorrelationIdMiddleware) - - -@app.get("/health") -async def health(): - return "OK" - - -@app.get("/api/migration") -@cache(expire=60) -async def get_migration(): - """ - Returns the details of the most recent migration. - """ - # Kind of insecure, but this is just a demo thing to show that migratehistory is available. - cursor = db.execute_sql( - "SELECT name, migrated_at FROM migratehistory ORDER BY migrated_at DESC LIMIT 1" - ) - name, migrated_at = cursor.fetchone() - return {"name": name, "migrated_at": migrated_at} - - -@app.get("/api/ips") -async def get_ips(request: Request, response: Response): - """ - Returns a list of partially redacted IP addresses, as well as submitting the user's IP address to the database (buffered). - """ - now = datetime.now(timezone.utc) - - # Get the user's IP address - user_ip = get_ip(request) - - # If the IP address is not found, return an error - if user_ip is None: - logger.warning("unable to acquire user IP address") - response.status_code = status.HTTP_403_FORBIDDEN - return {"error": "Unable to handle request."} - - # Update the buffered updates - app.state.buffered_updates[user_ip].count += 1 - app.state.buffered_updates[user_ip].last_seen = now - - # Query the latest IPs - latest_ips = ( - models.IPAddress.select( - models.IPAddress.ip, models.IPAddress.last_seen, models.IPAddress.count - ) - .order_by(models.IPAddress.last_seen.desc()) - .limit(10) - ) - - return { - "ips": [ - responses.SeenIP( - ip=hide_ip(ip.ip) if ip.ip != user_ip else ip.ip, - last_seen=human_readable.date_time( - value=pytz.utc.localize(ip.last_seen), - when=datetime.now(timezone.utc), - ), - count=ip.count, - ) - for ip in latest_ips - ] - } diff --git a/backend/linkpulse/dependencies.py b/backend/linkpulse/dependencies.py new file mode 100644 index 0000000..7aaee02 --- /dev/null +++ b/backend/linkpulse/dependencies.py @@ -0,0 +1,75 @@ +import os +from dataclasses import dataclass + +import structlog +from fastapi import HTTPException, Request, Response, status +from limits import parse +from limits.aio.storage import MemoryStorage +from limits.aio.strategies import MovingWindowRateLimiter +from linkpulse.models import Session + +storage = MemoryStorage() +strategy = MovingWindowRateLimiter(storage) + +logger = structlog.get_logger() +is_pytest = os.environ.get("PYTEST_VERSION") is not None + + +class RateLimiter: + def __init__(self, limit: str): + self.limit = parse(limit) + self.retry_after = str(self.limit.get_expiry()) + + async def __call__(self, request: Request, response: Response): + key = request.headers.get("X-Real-IP") + + if key is None: + if request.client is None: + logger.warning("No client information available for request.") + return False + key = request.client.host + + if is_pytest: + # This is somewhat hacky, I'm not sure if there's a way it can break during pytesting, but look here if odd rate limiting errors occur during tests + # The reason for this is so tests don't compete with each other for rate limiting + key += "." + os.environ["PYTEST_CURRENT_TEST"] + + if not await strategy.hit(self.limit, key): + logger.warning("Rate limit exceeded", key=key) + raise HTTPException( + status_code=status.HTTP_429_TOO_MANY_REQUESTS, + detail="Too Many Requests", + headers={"Retry-After": self.retry_after}, + ) + return True + + +class SessionDependency: + def __init__(self, required: bool = False): + self.required = required + + async def __call__(self, request: Request, response: Response): + session_token = request.cookies.get("session") + + # If not present, raise 401 if required + if session_token is None: + logger.debug("No session cookie found", required=self.required) + if self.required: + raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Unauthorized") + return None + + # Get session from database + session = Session.get_or_none(Session.token == session_token) + + # This doesn't differentiate between expired or completely invalid sessions + if session is None or session.is_expired(revoke=True): + if self.required: + logger.debug("Session Cookie Revoked", token=session_token) + response.delete_cookie("session") + headers = {"set-cookie": response.headers["set-cookie"]} + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, detail="Unauthorized", headers=headers + ) + return None + + return session diff --git a/backend/linkpulse/logging.py b/backend/linkpulse/logging.py index b10f7f1..408d983 100644 --- a/backend/linkpulse/logging.py +++ b/backend/linkpulse/logging.py @@ -31,12 +31,12 @@ def drop_color_message_key(_: Any, __: Any, event_dict: EventDict) -> EventDict: return event_dict -def setup_logging( - json_logs: Optional[bool] = None, log_level: Optional[str] = None -) -> None: +def setup_logging(json_logs: Optional[bool] = None, log_level: Optional[str] = None) -> None: # Pull from environment variables, apply defaults if not set - json_logs = json_logs or os.getenv("LOG_JSON_FORMAT", "true").lower() == "true" - log_level = log_level or os.getenv("LOG_LEVEL", "INFO") + if json_logs is None: + json_logs = os.getenv("LOG_JSON_FORMAT", "true").lower() == "true" + if log_level is None: + log_level = os.getenv("LOG_LEVEL", "INFO") def flatten(n): """ @@ -158,8 +158,6 @@ def setup_logging( sys.__excepthook__(exc_type, exc_value, exc_traceback) return - root_logger.error( - "Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback) - ) + root_logger.error("Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback)) sys.excepthook = handle_exception diff --git a/backend/linkpulse/migrate.py b/backend/linkpulse/migrate.py index 0d94bdb..0ef6df9 100644 --- a/backend/linkpulse/migrate.py +++ b/backend/linkpulse/migrate.py @@ -36,11 +36,7 @@ class ExtendedRouter(Router): try: modules = models if isinstance(module, bool): - modules = [ - m - for _, m, ispkg in pkgutil.iter_modules([f"{router.CURDIR}"]) - if ispkg - ] + modules = [m for _, m, ispkg in pkgutil.iter_modules([f"{router.CURDIR}"]) if ispkg] models = [m for module in modules for m in router.load_models(module)] except ImportError: @@ -48,7 +44,7 @@ class ExtendedRouter(Router): return None if self.ignore: - models = [m for m in models if m._meta.name not in self.ignore] # type: ignore[] + models = [m for m in models if m._meta.name not in self.ignore] # type: ignore for migration in self.diff: self.run_one(migration, self.migrator, fake=True) @@ -91,9 +87,7 @@ def main(*args: str) -> None: diff = router.diff if len(diff) == 0: - logger.info( - "No migrations found, no pending migrations to apply. Creating initial migration." - ) + logger.info("No migrations found, no pending migrations to apply. Creating initial migration.") migration = router.create("initial", auto=target_models) if not migration: @@ -107,13 +101,9 @@ def main(*args: str) -> None: logger.info( "Note: Selecting a migration will apply all migrations up to and including the selected migration." ) - logger.info( - "e.g. Applying 004 while only 001 is applied would apply 002, 003, and 004." - ) + logger.info("e.g. Applying 004 while only 001 is applied would apply 002, 003, and 004.") - choice = questionary.select( - "Select highest migration to apply:", choices=diff - ).ask() + choice = questionary.select("Select highest migration to apply:", choices=diff).ask() if choice is None: logger.warning( "For safety reasons, you won't be able to create migrations without applying the pending ones." @@ -163,14 +153,10 @@ def main(*args: str) -> None: logger.info(f"Migration created: {migration}") if len(router.diff) == 1: - if questionary.confirm( - "Do you want to apply this migration immediately?" - ).ask(): + if questionary.confirm("Do you want to apply this migration immediately?").ask(): router.run(migration) logger.info("Done.") - logger.warning( - "!!! Commit and push this migration file immediately!" - ) + logger.warning("!!! Commit and push this migration file immediately!") else: raise RuntimeError( "Changes anticipated with show() but no migration created with create(), model definition may have reverted." @@ -178,9 +164,10 @@ def main(*args: str) -> None: else: logger.info("No database changes detected.") - if len(current) > 5: + migration_squash_threshold: int = 15 + if len(current) > migration_squash_threshold: if questionary.confirm( - "There are more than 5 migrations applied. Do you want to merge them?", + f"There are more than {migration_squash_threshold} migrations applied. Do you want to merge them?", default=False, ).ask(): logger.info("Merging migrations...") diff --git a/backend/linkpulse/migrations/004_create_user_remove_ipaddress.py b/backend/linkpulse/migrations/004_create_user_remove_ipaddress.py new file mode 100644 index 0000000..d85aa7a --- /dev/null +++ b/backend/linkpulse/migrations/004_create_user_remove_ipaddress.py @@ -0,0 +1,66 @@ +"""Peewee migrations -- 004_create_user_remove_ipaddress.py. + +Some examples (model - class or model name):: + + > Model = migrator.orm['table_name'] # Return model in current state by name + > Model = migrator.ModelClass # Return model in current state by name + + > migrator.sql(sql) # Run custom SQL + > migrator.run(func, *args, **kwargs) # Run python function with the given args + > migrator.create_model(Model) # Create a model (could be used as decorator) + > migrator.remove_model(model, cascade=True) # Remove a model + > migrator.add_fields(model, **fields) # Add fields to a model + > migrator.change_fields(model, **fields) # Change fields + > migrator.remove_fields(model, *field_names, cascade=True) + > migrator.rename_field(model, old_field_name, new_field_name) + > migrator.rename_table(model, new_table_name) + > migrator.add_index(model, *col_names, unique=False) + > migrator.add_not_null(model, *field_names) + > migrator.add_default(model, field_name, default) + > migrator.add_constraint(model, name, sql) + > migrator.drop_index(model, *col_names) + > migrator.drop_not_null(model, *field_names) + > migrator.drop_constraints(model, *constraints) + +""" + +from contextlib import suppress + +import peewee as pw +from peewee_migrate import Migrator + + +with suppress(ImportError): + import playhouse.postgres_ext as pw_pext + + +def migrate(migrator: Migrator, database: pw.Database, *, fake=False): + """Write your migrations here.""" + + @migrator.create_model + class User(pw.Model): + id = pw.AutoField() + email = pw.CharField(max_length=45, unique=True) + password_hash = pw.CharField(max_length=96) + created_at = pw.DateTimeField() + updated_at = pw.DateTimeField() + + class Meta: + table_name = "user" + + migrator.remove_model("ipaddress") + + +def rollback(migrator: Migrator, database: pw.Database, *, fake=False): + """Write your rollback migrations here.""" + + @migrator.create_model + class IPAddress(pw.Model): + ip = pw.CharField(max_length=255, primary_key=True) + last_seen = pw.DateTimeField() + count = pw.IntegerField(default=0) + + class Meta: + table_name = "ipaddress" + + migrator.remove_model("user") diff --git a/backend/linkpulse/migrations/005_create_session_add_user_flags.py b/backend/linkpulse/migrations/005_create_session_add_user_flags.py new file mode 100644 index 0000000..5f79dcc --- /dev/null +++ b/backend/linkpulse/migrations/005_create_session_add_user_flags.py @@ -0,0 +1,63 @@ +"""Peewee migrations -- 005_create_session_add_user_flags.py. + +Some examples (model - class or model name):: + + > Model = migrator.orm['table_name'] # Return model in current state by name + > Model = migrator.ModelClass # Return model in current state by name + + > migrator.sql(sql) # Run custom SQL + > migrator.run(func, *args, **kwargs) # Run python function with the given args + > migrator.create_model(Model) # Create a model (could be used as decorator) + > migrator.remove_model(model, cascade=True) # Remove a model + > migrator.add_fields(model, **fields) # Add fields to a model + > migrator.change_fields(model, **fields) # Change fields + > migrator.remove_fields(model, *field_names, cascade=True) + > migrator.rename_field(model, old_field_name, new_field_name) + > migrator.rename_table(model, new_table_name) + > migrator.add_index(model, *col_names, unique=False) + > migrator.add_not_null(model, *field_names) + > migrator.add_default(model, field_name, default) + > migrator.add_constraint(model, name, sql) + > migrator.drop_index(model, *col_names) + > migrator.drop_not_null(model, *field_names) + > migrator.drop_constraints(model, *constraints) + +""" + +from contextlib import suppress + +import peewee as pw +from peewee_migrate import Migrator + + +with suppress(ImportError): + import playhouse.postgres_ext as pw_pext + + +def migrate(migrator: Migrator, database: pw.Database, *, fake=False): + """Write your migrations here.""" + + migrator.add_fields( + 'user', + + flags=pw.BitField(default=0), + deleted_at=pw.DateTimeField(null=True)) + + @migrator.create_model + class Session(pw.Model): + token = pw.CharField(max_length=32, primary_key=True) + user = pw.ForeignKeyField(column_name='user_id', field='id', model=migrator.orm['user'], on_delete='CASCADE') + expiry = pw.DateTimeField() + created_at = pw.DateTimeField() + last_used = pw.DateTimeField(null=True) + + class Meta: + table_name = "session" + + +def rollback(migrator: Migrator, database: pw.Database, *, fake=False): + """Write your rollback migrations here.""" + + migrator.remove_fields('user', 'flags', 'deleted_at') + + migrator.remove_model('session') diff --git a/backend/linkpulse/migrations/006_add_session_constraints.py b/backend/linkpulse/migrations/006_add_session_constraints.py new file mode 100644 index 0000000..7e044de --- /dev/null +++ b/backend/linkpulse/migrations/006_add_session_constraints.py @@ -0,0 +1,63 @@ +"""Peewee migrations -- 006_add_session_constraints.py. + +Some examples (model - class or model name):: + + > Model = migrator.orm['table_name'] # Return model in current state by name + > Model = migrator.ModelClass # Return model in current state by name + + > migrator.sql(sql) # Run custom SQL + > migrator.run(func, *args, **kwargs) # Run python function with the given args + > migrator.create_model(Model) # Create a model (could be used as decorator) + > migrator.remove_model(model, cascade=True) # Remove a model + > migrator.add_fields(model, **fields) # Add fields to a model + > migrator.change_fields(model, **fields) # Change fields + > migrator.remove_fields(model, *field_names, cascade=True) + > migrator.rename_field(model, old_field_name, new_field_name) + > migrator.rename_table(model, new_table_name) + > migrator.add_index(model, *col_names, unique=False) + > migrator.add_not_null(model, *field_names) + > migrator.add_default(model, field_name, default) + > migrator.add_constraint(model, name, sql) + > migrator.drop_index(model, *col_names) + > migrator.drop_not_null(model, *field_names) + > migrator.drop_constraints(model, *constraints) + +""" + +from contextlib import suppress + +import peewee as pw +from peewee_migrate import Migrator + + +with suppress(ImportError): + import playhouse.postgres_ext as pw_pext + + +def migrate(migrator: Migrator, database: pw.Database, *, fake=False): + """Write your migrations here.""" + + migrator.add_constraint( + "session", "session_token_length", pw.Check("LENGTH(token) = 32") + ) + + migrator.add_constraint( + "session", "session_expiry_created_at", pw.Check("expiry > created_at") + ) + + migrator.add_constraint( + "session", + "session_last_used_created_at", + pw.Check("last_used IS NULL OR last_used >= created_at"), + ) + + +def rollback(migrator: Migrator, database: pw.Database, *, fake=False): + """Write your rollback migrations here.""" + + migrator.drop_constraints( + "session", + "session_token_length", + "session_expiry_created_at", + "session_last_used_created_at", + ) diff --git a/backend/linkpulse/migrations/007_password_hash_length_adjust_session_token_index.py b/backend/linkpulse/migrations/007_password_hash_length_adjust_session_token_index.py new file mode 100644 index 0000000..d656f83 --- /dev/null +++ b/backend/linkpulse/migrations/007_password_hash_length_adjust_session_token_index.py @@ -0,0 +1,50 @@ +"""Peewee migrations -- 007_password_hash_length_adjust_session_token_index.py. + +Some examples (model - class or model name):: + + > Model = migrator.orm['table_name'] # Return model in current state by name + > Model = migrator.ModelClass # Return model in current state by name + + > migrator.sql(sql) # Run custom SQL + > migrator.run(func, *args, **kwargs) # Run python function with the given args + > migrator.create_model(Model) # Create a model (could be used as decorator) + > migrator.remove_model(model, cascade=True) # Remove a model + > migrator.add_fields(model, **fields) # Add fields to a model + > migrator.change_fields(model, **fields) # Change fields + > migrator.remove_fields(model, *field_names, cascade=True) + > migrator.rename_field(model, old_field_name, new_field_name) + > migrator.rename_table(model, new_table_name) + > migrator.add_index(model, *col_names, unique=False) + > migrator.add_not_null(model, *field_names) + > migrator.add_default(model, field_name, default) + > migrator.add_constraint(model, name, sql) + > migrator.drop_index(model, *col_names) + > migrator.drop_not_null(model, *field_names) + > migrator.drop_constraints(model, *constraints) + +""" + +from contextlib import suppress + +import peewee as pw +from peewee_migrate import Migrator + + +with suppress(ImportError): + import playhouse.postgres_ext as pw_pext + + +def migrate(migrator: Migrator, database: pw.Database, *, fake=False): + """Write your migrations here.""" + + migrator.change_fields('user', password_hash=pw.CharField(max_length=97)) + + migrator.add_index('session', 'token', unique=True) + + +def rollback(migrator: Migrator, database: pw.Database, *, fake=False): + """Write your rollback migrations here.""" + + migrator.drop_index('session', 'token') + + migrator.change_fields('user', password_hash=pw.CharField(max_length=96)) diff --git a/backend/linkpulse/models.py b/backend/linkpulse/models.py index 2ae1be2..9782eb2 100644 --- a/backend/linkpulse/models.py +++ b/backend/linkpulse/models.py @@ -3,10 +3,14 @@ This module defines the database models for the LinkPulse backend. It also provides a base model with database connection details. """ +import datetime +import secrets from os import getenv +from typing import Optional import structlog -from peewee import CharField, DateTimeField, IntegerField, Model +from linkpulse.utilities import utc_now +from peewee import AutoField, BitField, CharField, Check, DateTimeField, ForeignKeyField, Model from playhouse.db_url import connect logger = structlog.get_logger() @@ -26,7 +30,80 @@ class BaseModel(Model): database = connect(url=_get_database_url()) -class IPAddress(BaseModel): - ip = CharField(primary_key=True) - last_seen = DateTimeField() # timezone naive - count = IntegerField(default=0) +class User(BaseModel): + id = AutoField(primary_key=True) + # arbitrary max length, but statistically reasonable and limits UI concerns/abuse cases + email = CharField(unique=True, max_length=45) + flags = BitField() + # full hash with encoded salt/parameters, argon2 but assume nothing + password_hash = CharField(max_length=97) + created_at = DateTimeField(default=utc_now) + updated_at = DateTimeField(default=utc_now) + # prefer soft deletes before hard deletes + deleted_at = DateTimeField(null=True) + deleted = flags.flag(1) + + # TODO: delete method, ensure sessions are deleted as well + # TODO: undelete method + + +class Session(BaseModel): + """ + A session represents a user's login session. + + For now, a session returned from the API implies it's validity. + In the future, sessions may be invalidated or revoked, but kept in the database AND returned. + This could allow sessions to be tracked and audited even after they are no longer valid, or allow more proper 'logout' messages. + """ + + token = CharField(unique=True, primary_key=True, max_length=32) + user = ForeignKeyField(User, backref="sessions", on_delete="CASCADE") + + expiry = DateTimeField() + + created_at = DateTimeField(default=utc_now) + last_used = DateTimeField(default=None, null=True) + + class Meta: + constraints = [ + Check("LENGTH(token) = 32", name="session_token_length"), + Check("expiry > created_at", name="session_expiry_created_at"), + Check( + "last_used IS NULL OR last_used >= created_at", + name="session_last_used_created_at", + ), + ] + + @classmethod + def generate_token(cls) -> str: + alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + return "".join(secrets.choice(alphabet) for _ in range(32)) + + @property + def expiry_utc(self) -> datetime.datetime: + return self.expiry.replace(tzinfo=datetime.timezone.utc) # type: ignore + + def is_expired(self, revoke: bool = True, now: Optional[datetime.datetime] = None) -> bool: + """ + Check if the session is expired. If `revoke` is True, the session will be automatically revoked if it is expired. + """ + if now is None: + now = utc_now() + + if self.expiry_utc < now: + logger.debug("Session expired", token=self.token, user=self.user.email, revoke=revoke) + if revoke: + self.delete_instance() + return True + return False + + def use(self, now: Optional[datetime.datetime] = None): + """ + Update the last_used field of the session. + """ + if now is None: + now = utc_now() + self.last_used = now # type: ignore + # TODO: This should be buffered, as it'll be called *constantly*, perhaps every single request. + # The ideal solution would be emitting updates to a Redis-based cache, and then flushing to the database every few seconds/minute. + self.save() diff --git a/backend/linkpulse/routers/__init__.py b/backend/linkpulse/routers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/linkpulse/routers/auth.py b/backend/linkpulse/routers/auth.py new file mode 100644 index 0000000..f090104 --- /dev/null +++ b/backend/linkpulse/routers/auth.py @@ -0,0 +1,164 @@ +from datetime import datetime, timedelta +from typing import Annotated, Optional, Tuple + +import structlog +from fastapi import APIRouter, Depends, Response, status +from linkpulse.dependencies import RateLimiter, SessionDependency +from linkpulse.models import Session, User +from linkpulse.utilities import utc_now, is_development +from pwdlib import PasswordHash +from pwdlib.hashers.argon2 import Argon2Hasher +from pydantic import BaseModel, EmailStr, Field + +logger = structlog.get_logger() + +router = APIRouter() + +hasher = PasswordHash([Argon2Hasher()]) +# cspell: disable +dummy_hash = ( + "$argon2id$v=19$m=65536,t=3,p=4$Ii3hm5/NqcJddQDFK24Wtw$I99xV/qkaLROo0VZcvaZrYMAD9RTcWzxY5/RbMoRLQ4" +) + +# Session expiry times +default_session_expiry = timedelta(hours=12) +remember_me_session_expiry = timedelta(days=14) + + +def validate_session(token: str, user: bool = True) -> Tuple[bool, bool, Optional[User]]: + """Given a token, validate that the session exists and is not expired. + + This function has side effects: + - This function updates last_used if `user` is True. + - This function will invalidate the session if it is expired. + + :param token: The session token to validate. + :type token: str + :param user: Whether to update the last_used timestamp of the session. + :type user: bool + :return: A tuple containing: + - A boolean indicating if the session exists. + - A boolean indicating if the session is valid. + - The User object if the session is valid, otherwise None. + :rtype: Tuple[bool, bool, Optional[User]] + """ + # Check if session exists + session = Session.get_or_none(Session.token == token) + if session is None: + return False, False, None + + # Check if session is expired + if session.is_expired(revoke=True): + return True, False, None + + if user: + session.use() + return True, True, session.user + + +class LoginBody(BaseModel): + email: EmailStr # May be a heavy check; profiling could determine if this is necessary + password: str = Field(min_length=1) # Basic check, registration will have more stringent requirements + remember_me: bool = False + + +class LoginError(BaseModel): + error: str + + +class LoginSuccess(BaseModel): + email: EmailStr + expiry: datetime + + +@router.post( + "/api/login", + responses={200: {"model": LoginSuccess}, 401: {"model": LoginError}}, + dependencies=[Depends(RateLimiter("6/minute"))], +) +async def login(body: LoginBody, response: Response): + # Acquire user by email + user = User.get_or_none(User.email == body.email) + + if user is None: + # Hash regardless of user existence to prevent timing attacks + hasher.verify(body.password, dummy_hash) + response.status_code = status.HTTP_401_UNAUTHORIZED + return LoginError(error="Invalid email or password") + + logger.warning("Hash", hash=user.password_hash) + valid, updated_hash = hasher.verify_and_update(body.password, user.password_hash) + + # Check if password matches, return 401 if not + if not valid: + response.status_code = status.HTTP_401_UNAUTHORIZED + return LoginError(error="Invalid email or password") + + # Update password hash if necessary + if updated_hash: + user.password_hash = updated_hash + user.save() + + # Create session + token = Session.generate_token() + session_duration = remember_me_session_expiry if body.remember_me else default_session_expiry + session = Session.create( + token=token, + user=user, + expiry=utc_now() + session_duration, + ) + + # Set Cookie of session token + max_age = int(session_duration.total_seconds()) + response.set_cookie("session", token, max_age=max_age, secure=not is_development, httponly=True) + return {"email": user.email, "expiry": session.expiry} + + +@router.post("/api/logout", status_code=status.HTTP_200_OK) +async def logout( + response: Response, + session: Annotated[Session, Depends(SessionDependency(required=True))], + all: bool = False, +): + # We can assume the session is valid via the dependency + if not all: + session.delete_instance() + logger.debug("Session deleted", user=session.user.email, token=session.token) + else: + count = Session.delete().where(Session.user == session.user).execute() + logger.debug("All sessions deleted", user=session.user.email, count=count, source_token=session.token) + + response.delete_cookie("session") + + +@router.post("/api/register") +async def register(): + # Validate parameters + # Hash password + # Create User + # Create Session + # Set Cookie of session token + # Return 200 with mild user information + pass + + +@router.get("/api/session") +async def session(session: Annotated[Session, Depends(SessionDependency(required=True))]): + # Returns the session information for the current session + return { + "user": { + "email": session.user.email, + } + } + + +@router.get("/api/sessions") +async def sessions(session: Annotated[Session, Depends(SessionDependency(required=True))]): + # Returns a list of all active sessions for this user + return {} + + +# GET /api/user/{id}/sessions +# GET /api/user/{id}/sessions/{token} +# DELETE /api/user/{id}/sessions +# POST /api/user/{id}/logout (delete all sessions) diff --git a/backend/linkpulse/routers/misc.py b/backend/linkpulse/routers/misc.py new file mode 100644 index 0000000..57b1877 --- /dev/null +++ b/backend/linkpulse/routers/misc.py @@ -0,0 +1,33 @@ +"""Miscellaneous endpoints for the Linkpulse API.""" + +from typing import Any + +from fastapi import APIRouter +from fastapi_cache.decorator import cache +from linkpulse.utilities import get_db + +router = APIRouter() + +db = get_db() + + +@router.get("/health") +async def health(): + """An endpoint to check if the service is running. + :return: OK + :rtype: Literal['OK']""" + # TODO: Check database connection + return "OK" + + +@router.get("/api/migration") +@cache(expire=60) +async def get_migration() -> dict[str, Any]: + """Get the last migration name and timestamp from the migratehistory table. + :return: The last migration name and timestamp. + :rtype: dict[str, Any] + """ + # Kind of insecure, but this is just a demo thing to show that migratehistory is available. + cursor = db.execute_sql("SELECT name, migrated_at FROM migratehistory ORDER BY migrated_at DESC LIMIT 1") + name, migrated_at = cursor.fetchone() + return {"name": name, "migrated_at": migrated_at} diff --git a/backend/linkpulse/tests/__init__.py b/backend/linkpulse/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/linkpulse/tests/random.py b/backend/linkpulse/tests/random.py new file mode 100644 index 0000000..ccc5495 --- /dev/null +++ b/backend/linkpulse/tests/random.py @@ -0,0 +1,15 @@ +import random +import string +import time + + +def epoch() -> int: + return int(time.time()) + + +def random_string(length: int = 10) -> str: + return "".join(random.choices(string.ascii_lowercase + string.digits, k=length)) + + +def random_email() -> str: + return random_string() + str(epoch()) + "@example.com" diff --git a/backend/linkpulse/tests/test_app.py b/backend/linkpulse/tests/test_app.py new file mode 100644 index 0000000..e8d4436 --- /dev/null +++ b/backend/linkpulse/tests/test_app.py @@ -0,0 +1,16 @@ +from fastapi.testclient import TestClient + +from linkpulse.app import app + + +def test_health(): + with TestClient(app) as client: + response = client.get("/health") + assert response.status_code == 200 + assert response.json() == "OK" + + +def test_migration(): + with TestClient(app) as client: + response = client.get("/api/migration") + assert response.status_code == 200 diff --git a/backend/linkpulse/tests/test_auth.py b/backend/linkpulse/tests/test_auth.py new file mode 100644 index 0000000..157b35b --- /dev/null +++ b/backend/linkpulse/tests/test_auth.py @@ -0,0 +1,82 @@ +from datetime import datetime, timedelta +from wsgiref import headers + +import pytest +import structlog +from fastapi import status +from fastapi.testclient import TestClient +from linkpulse.app import app +from linkpulse.tests.test_session import expired_session, session +from linkpulse.tests.test_user import user +from linkpulse.utilities import utc_now + +logger = structlog.get_logger() + + +def test_auth_login(user): + args = {"email": user.email, "password": "password"} + + with TestClient(app) as client: + + def test_expiry(response, expected): + expiry = datetime.fromisoformat(response.json()["expiry"]) + relative_expiry_days = (expiry - utc_now()).total_seconds() / timedelta(days=1).total_seconds() + assert relative_expiry_days == pytest.approx(expected, rel=1e-5) + + # Remember Me, default False + response = client.post("/api/login", json=args) + assert response.status_code == status.HTTP_200_OK + test_expiry(response, 0.5) + assert client.cookies.get("session") is not None + + # Remember Me, True + response = client.post("/api/login", json={**args, "remember_me": True}) + assert response.status_code == status.HTTP_200_OK + test_expiry(response, 14) + + # Invalid Email + response = client.post("/api/login", json={**args, "email": "invalid_email"}) + assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY + + # Wrong Email + response = client.post("/api/login", json={**args, "email": "bad@email.com"}) + assert response.status_code == status.HTTP_401_UNAUTHORIZED + + # Wrong Password + response = client.post("/api/login", json={**args, "password": "bad_password"}) + assert response.status_code == status.HTTP_401_UNAUTHORIZED + + +def test_auth_login_logout(user): + """Test full login & logout cycle""" + args = {"email": user.email, "password": "password"} + + with TestClient(app) as client: + response = client.post("/api/logout") + assert response.status_code == status.HTTP_401_UNAUTHORIZED + + response = client.post("/api/login", json=args) + assert response.status_code == status.HTTP_200_OK + assert client.cookies.get("session") is not None + + response = client.post("/api/logout") + assert response.status_code == status.HTTP_200_OK + assert client.cookies.get("session") is None + + +def test_auth_logout_expired(expired_session): + # Test that an expired session cannot be used to logout, but still removes the cookie + with TestClient(app) as client: + response = client.post("/api/logout") + assert response.status_code == status.HTTP_401_UNAUTHORIZED + + # Add expired session cookie + client.cookies.set("session", expired_session.token) + assert client.cookies.get("session") is not None + + # Attempt to logout + response = client.post("/api/logout") + assert response.status_code == status.HTTP_401_UNAUTHORIZED + assert response.headers.get("set-cookie") is not None + + # TODO: Ensure ?all=True doesn't do anything either diff --git a/backend/linkpulse/tests/test_depends.py b/backend/linkpulse/tests/test_depends.py new file mode 100644 index 0000000..eafc13f --- /dev/null +++ b/backend/linkpulse/tests/test_depends.py @@ -0,0 +1,22 @@ +import structlog +from fastapi import status +from fastapi.testclient import TestClient +from linkpulse.app import app +from linkpulse.tests.test_user import user + +logger = structlog.get_logger() + + +def test_rate_limit(user): + args = {"email": user.email, "password": "password"} + + with TestClient(app) as client: + for _ in range(6): + response = client.post("/api/login", json=args) + assert response.status_code == status.HTTP_200_OK + + # 7th request should be rate limited + response = client.post("/api/login", json=args) + assert response.status_code == status.HTTP_429_TOO_MANY_REQUESTS + assert "Retry-After" in response.headers + assert int(response.headers["Retry-After"]) > 1 diff --git a/backend/linkpulse/tests/test_session.py b/backend/linkpulse/tests/test_session.py new file mode 100644 index 0000000..ad38ec9 --- /dev/null +++ b/backend/linkpulse/tests/test_session.py @@ -0,0 +1,78 @@ +from datetime import timedelta + +import pytest +import structlog +from linkpulse.models import Session +from linkpulse.routers.auth import validate_session +from linkpulse.tests.random import random_string +from linkpulse.tests.test_user import user +from linkpulse.utilities import utc_now +from peewee import IntegrityError + +logger = structlog.get_logger() + + +@pytest.fixture +def db(): + return Session._meta.database + + +@pytest.fixture +def session(user): + return Session.create(user=user, token=Session.generate_token(), expiry=utc_now() + timedelta(hours=1)) + + +@pytest.fixture +def expired_session(session): + session.created_at = utc_now() - timedelta(hours=2) # Required to bypass the constraint + session.expiry = utc_now() - timedelta(hours=1) + session.save() + return session + + +def test_expired_session_fixture(expired_session): + assert expired_session.is_expired() is True + + +def test_session_create(session): + assert Session.get_or_none(Session.token == session.token) is not None + + +def test_auto_revoke(db, expired_session): + # Expired, but still exists + assert Session.get_or_none(Session.token == expired_session.token) is not None + # Test revoke=False + assert expired_session.is_expired(revoke=False) is True + # Test revoke=True + assert expired_session.is_expired(revoke=True) is True + # Expired, and no longer exists + assert Session.get_or_none(Session.token == expired_session.token) is None + + +def test_expiry_valid(session): + assert session.is_expired() is False + + +def test_expiry_invalid(expired_session): + assert expired_session.is_expired() is True + + +def test_session_constraint_token_length(user): + Session.create(user=user, token=Session.generate_token(), expiry=utc_now() + timedelta(hours=1)) + + with pytest.raises(IntegrityError): + Session.create(user=user, token=Session.generate_token()[:-1], expiry=utc_now() + timedelta(hours=1)) + + +def test_session_constraint_expiry(user): + Session.create(user=user, token=Session.generate_token(), expiry=utc_now() + timedelta(minutes=1)) + + with pytest.raises(IntegrityError): + Session.create(user=user, token=Session.generate_token(), expiry=utc_now()) + + +def test_validate_session(db, session): + assert session.last_used is None + assert validate_session(session.token, user=True) == (True, True, session.user) + session = Session.get(Session.token == session.token) + assert session.last_used is not None diff --git a/backend/linkpulse/tests/test_user.py b/backend/linkpulse/tests/test_user.py new file mode 100644 index 0000000..4a0fe0c --- /dev/null +++ b/backend/linkpulse/tests/test_user.py @@ -0,0 +1,12 @@ +import pytest +import structlog +from linkpulse.models import User +from linkpulse.routers.auth import hasher +from linkpulse.tests.random import random_email + +logger = structlog.get_logger() + + +@pytest.fixture +def user(): + return User.create(email=random_email(), password_hash=hasher.hash("password")) diff --git a/backend/linkpulse/tests/test_utilities.py b/backend/linkpulse/tests/test_utilities.py new file mode 100644 index 0000000..e6d00c0 --- /dev/null +++ b/backend/linkpulse/tests/test_utilities.py @@ -0,0 +1,6 @@ +from linkpulse.utilities import utc_now + + +def test_utcnow_tz_aware(): + dt = utc_now() + dt.tzinfo is not None and dt.tzinfo.utcoffset(dt) is not None diff --git a/backend/linkpulse/utilities.py b/backend/linkpulse/utilities.py index 3aecf5f..4cb2a6f 100644 --- a/backend/linkpulse/utilities.py +++ b/backend/linkpulse/utilities.py @@ -3,8 +3,10 @@ This module provides utility functions for database connection, string manipulat """ import os +from datetime import datetime from typing import Optional +import pytz from fastapi import Request from peewee import PostgresqlDatabase @@ -12,6 +14,13 @@ from peewee import PostgresqlDatabase is_development = os.getenv("ENVIRONMENT") == "development" +def utc_now() -> datetime: + """ + A utility function to replace the deprecated datetime.datetime.utcnow() function. + """ + return datetime.now(pytz.utc) + + def get_db() -> PostgresqlDatabase: """ Acquires the database connector from the BaseModel class. diff --git a/backend/poetry.lock b/backend/poetry.lock index ab5400b..d5cc6ed 100644 --- a/backend/poetry.lock +++ b/backend/poetry.lock @@ -70,6 +70,63 @@ tornado = ["tornado (>=4.3)"] twisted = ["twisted"] zookeeper = ["kazoo"] +[[package]] +name = "argon2-cffi" +version = "23.1.0" +description = "Argon2 for Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "argon2_cffi-23.1.0-py3-none-any.whl", hash = "sha256:c670642b78ba29641818ab2e68bd4e6a78ba53b7eff7b4c3815ae16abf91c7ea"}, + {file = "argon2_cffi-23.1.0.tar.gz", hash = "sha256:879c3e79a2729ce768ebb7d36d4609e3a78a4ca2ec3a9f12286ca057e3d0db08"}, +] + +[package.dependencies] +argon2-cffi-bindings = "*" + +[package.extras] +dev = ["argon2-cffi[tests,typing]", "tox (>4)"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-copybutton", "sphinx-notfound-page"] +tests = ["hypothesis", "pytest"] +typing = ["mypy"] + +[[package]] +name = "argon2-cffi-bindings" +version = "21.2.0" +description = "Low-level CFFI bindings for Argon2" +optional = false +python-versions = ">=3.6" +files = [ + {file = "argon2-cffi-bindings-21.2.0.tar.gz", hash = "sha256:bb89ceffa6c791807d1305ceb77dbfacc5aa499891d2c55661c6459651fc39e3"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ccb949252cb2ab3a08c02024acb77cfb179492d5701c7cbdbfd776124d4d2367"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9524464572e12979364b7d600abf96181d3541da11e23ddf565a32e70bd4dc0d"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b746dba803a79238e925d9046a63aa26bf86ab2a2fe74ce6b009a1c3f5c8f2ae"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58ed19212051f49a523abb1dbe954337dc82d947fb6e5a0da60f7c8471a8476c"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:bd46088725ef7f58b5a1ef7ca06647ebaf0eb4baff7d1d0d177c6cc8744abd86"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_i686.whl", hash = "sha256:8cd69c07dd875537a824deec19f978e0f2078fdda07fd5c42ac29668dda5f40f"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f1152ac548bd5b8bcecfb0b0371f082037e47128653df2e8ba6e914d384f3c3e"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-win32.whl", hash = "sha256:603ca0aba86b1349b147cab91ae970c63118a0f30444d4bc80355937c950c082"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-win_amd64.whl", hash = "sha256:b2ef1c30440dbbcba7a5dc3e319408b59676e2e039e2ae11a8775ecf482b192f"}, + {file = "argon2_cffi_bindings-21.2.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e415e3f62c8d124ee16018e491a009937f8cf7ebf5eb430ffc5de21b900dad93"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3e385d1c39c520c08b53d63300c3ecc28622f076f4c2b0e6d7e796e9f6502194"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c3e3cc67fdb7d82c4718f19b4e7a87123caf8a93fde7e23cf66ac0337d3cb3f"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a22ad9800121b71099d0fb0a65323810a15f2e292f2ba450810a7316e128ee5"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f9f8b450ed0547e3d473fdc8612083fd08dd2120d6ac8f73828df9b7d45bb351"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:93f9bf70084f97245ba10ee36575f0c3f1e7d7724d67d8e5b08e61787c320ed7"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3b9ef65804859d335dc6b31582cad2c5166f0c3e7975f324d9ffaa34ee7e6583"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4966ef5848d820776f5f562a7d45fdd70c2f330c961d0d745b784034bd9f48d"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20ef543a89dee4db46a1a6e206cd015360e5a75822f76df533845c3cbaf72670"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed2937d286e2ad0cc79a7087d3c272832865f779430e0cc2b4f3718d3159b0cb"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5e00316dabdaea0b2dd82d141cc66889ced0cdcbfa599e8b471cf22c620c329a"}, +] + +[package.dependencies] +cffi = ">=1.0.1" + +[package.extras] +dev = ["cogapp", "pre-commit", "pytest", "wheel"] +tests = ["pytest"] + [[package]] name = "asgi-correlation-id" version = "4.3.4" @@ -140,6 +197,85 @@ files = [ {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, ] +[[package]] +name = "cffi" +version = "1.17.1" +description = "Foreign Function Interface for Python calling C code." +optional = false +python-versions = ">=3.8" +files = [ + {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, + {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"}, + {file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"}, + {file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"}, + {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"}, + {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"}, + {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"}, + {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"}, + {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"}, + {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"}, + {file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"}, + {file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"}, + {file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"}, + {file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"}, + {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"}, + {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, +] + +[package.dependencies] +pycparser = "*" + [[package]] name = "charset-normalizer" version = "3.4.0" @@ -279,6 +415,80 @@ files = [ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +[[package]] +name = "coverage" +version = "7.6.4" +description = "Code coverage measurement for Python" +optional = false +python-versions = ">=3.9" +files = [ + {file = "coverage-7.6.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5f8ae553cba74085db385d489c7a792ad66f7f9ba2ee85bfa508aeb84cf0ba07"}, + {file = "coverage-7.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8165b796df0bd42e10527a3f493c592ba494f16ef3c8b531288e3d0d72c1f6f0"}, + {file = "coverage-7.6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7c8b95bf47db6d19096a5e052ffca0a05f335bc63cef281a6e8fe864d450a72"}, + {file = "coverage-7.6.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ed9281d1b52628e81393f5eaee24a45cbd64965f41857559c2b7ff19385df51"}, + {file = "coverage-7.6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0809082ee480bb8f7416507538243c8863ac74fd8a5d2485c46f0f7499f2b491"}, + {file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d541423cdd416b78626b55f123412fcf979d22a2c39fce251b350de38c15c15b"}, + {file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:58809e238a8a12a625c70450b48e8767cff9eb67c62e6154a642b21ddf79baea"}, + {file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c9b8e184898ed014884ca84c70562b4a82cbc63b044d366fedc68bc2b2f3394a"}, + {file = "coverage-7.6.4-cp310-cp310-win32.whl", hash = "sha256:6bd818b7ea14bc6e1f06e241e8234508b21edf1b242d49831831a9450e2f35fa"}, + {file = "coverage-7.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:06babbb8f4e74b063dbaeb74ad68dfce9186c595a15f11f5d5683f748fa1d172"}, + {file = "coverage-7.6.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:73d2b73584446e66ee633eaad1a56aad577c077f46c35ca3283cd687b7715b0b"}, + {file = "coverage-7.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:51b44306032045b383a7a8a2c13878de375117946d68dcb54308111f39775a25"}, + {file = "coverage-7.6.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b3fb02fe73bed561fa12d279a417b432e5b50fe03e8d663d61b3d5990f29546"}, + {file = "coverage-7.6.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed8fe9189d2beb6edc14d3ad19800626e1d9f2d975e436f84e19efb7fa19469b"}, + {file = "coverage-7.6.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b369ead6527d025a0fe7bd3864e46dbee3aa8f652d48df6174f8d0bac9e26e0e"}, + {file = "coverage-7.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ade3ca1e5f0ff46b678b66201f7ff477e8fa11fb537f3b55c3f0568fbfe6e718"}, + {file = "coverage-7.6.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:27fb4a050aaf18772db513091c9c13f6cb94ed40eacdef8dad8411d92d9992db"}, + {file = "coverage-7.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4f704f0998911abf728a7783799444fcbbe8261c4a6c166f667937ae6a8aa522"}, + {file = "coverage-7.6.4-cp311-cp311-win32.whl", hash = "sha256:29155cd511ee058e260db648b6182c419422a0d2e9a4fa44501898cf918866cf"}, + {file = "coverage-7.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:8902dd6a30173d4ef09954bfcb24b5d7b5190cf14a43170e386979651e09ba19"}, + {file = "coverage-7.6.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:12394842a3a8affa3ba62b0d4ab7e9e210c5e366fbac3e8b2a68636fb19892c2"}, + {file = "coverage-7.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2b6b4c83d8e8ea79f27ab80778c19bc037759aea298da4b56621f4474ffeb117"}, + {file = "coverage-7.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d5b8007f81b88696d06f7df0cb9af0d3b835fe0c8dbf489bad70b45f0e45613"}, + {file = "coverage-7.6.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b57b768feb866f44eeed9f46975f3d6406380275c5ddfe22f531a2bf187eda27"}, + {file = "coverage-7.6.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5915fcdec0e54ee229926868e9b08586376cae1f5faa9bbaf8faf3561b393d52"}, + {file = "coverage-7.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0b58c672d14f16ed92a48db984612f5ce3836ae7d72cdd161001cc54512571f2"}, + {file = "coverage-7.6.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:2fdef0d83a2d08d69b1f2210a93c416d54e14d9eb398f6ab2f0a209433db19e1"}, + {file = "coverage-7.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8cf717ee42012be8c0cb205dbbf18ffa9003c4cbf4ad078db47b95e10748eec5"}, + {file = "coverage-7.6.4-cp312-cp312-win32.whl", hash = "sha256:7bb92c539a624cf86296dd0c68cd5cc286c9eef2d0c3b8b192b604ce9de20a17"}, + {file = "coverage-7.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:1032e178b76a4e2b5b32e19d0fd0abbce4b58e77a1ca695820d10e491fa32b08"}, + {file = "coverage-7.6.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:023bf8ee3ec6d35af9c1c6ccc1d18fa69afa1cb29eaac57cb064dbb262a517f9"}, + {file = "coverage-7.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b0ac3d42cb51c4b12df9c5f0dd2f13a4f24f01943627120ec4d293c9181219ba"}, + {file = "coverage-7.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8fe4984b431f8621ca53d9380901f62bfb54ff759a1348cd140490ada7b693c"}, + {file = "coverage-7.6.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5fbd612f8a091954a0c8dd4c0b571b973487277d26476f8480bfa4b2a65b5d06"}, + {file = "coverage-7.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dacbc52de979f2823a819571f2e3a350a7e36b8cb7484cdb1e289bceaf35305f"}, + {file = "coverage-7.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dab4d16dfef34b185032580e2f2f89253d302facba093d5fa9dbe04f569c4f4b"}, + {file = "coverage-7.6.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:862264b12ebb65ad8d863d51f17758b1684560b66ab02770d4f0baf2ff75da21"}, + {file = "coverage-7.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5beb1ee382ad32afe424097de57134175fea3faf847b9af002cc7895be4e2a5a"}, + {file = "coverage-7.6.4-cp313-cp313-win32.whl", hash = "sha256:bf20494da9653f6410213424f5f8ad0ed885e01f7e8e59811f572bdb20b8972e"}, + {file = "coverage-7.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:182e6cd5c040cec0a1c8d415a87b67ed01193ed9ad458ee427741c7d8513d963"}, + {file = "coverage-7.6.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a181e99301a0ae128493a24cfe5cfb5b488c4e0bf2f8702091473d033494d04f"}, + {file = "coverage-7.6.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:df57bdbeffe694e7842092c5e2e0bc80fff7f43379d465f932ef36f027179806"}, + {file = "coverage-7.6.4-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bcd1069e710600e8e4cf27f65c90c7843fa8edfb4520fb0ccb88894cad08b11"}, + {file = "coverage-7.6.4-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99b41d18e6b2a48ba949418db48159d7a2e81c5cc290fc934b7d2380515bd0e3"}, + {file = "coverage-7.6.4-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6b1e54712ba3474f34b7ef7a41e65bd9037ad47916ccb1cc78769bae324c01a"}, + {file = "coverage-7.6.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:53d202fd109416ce011578f321460795abfe10bb901b883cafd9b3ef851bacfc"}, + {file = "coverage-7.6.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:c48167910a8f644671de9f2083a23630fbf7a1cb70ce939440cd3328e0919f70"}, + {file = "coverage-7.6.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:cc8ff50b50ce532de2fa7a7daae9dd12f0a699bfcd47f20945364e5c31799fef"}, + {file = "coverage-7.6.4-cp313-cp313t-win32.whl", hash = "sha256:b8d3a03d9bfcaf5b0141d07a88456bb6a4c3ce55c080712fec8418ef3610230e"}, + {file = "coverage-7.6.4-cp313-cp313t-win_amd64.whl", hash = "sha256:f3ddf056d3ebcf6ce47bdaf56142af51bb7fad09e4af310241e9db7a3a8022e1"}, + {file = "coverage-7.6.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9cb7fa111d21a6b55cbf633039f7bc2749e74932e3aa7cb7333f675a58a58bf3"}, + {file = "coverage-7.6.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:11a223a14e91a4693d2d0755c7a043db43d96a7450b4f356d506c2562c48642c"}, + {file = "coverage-7.6.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a413a096c4cbac202433c850ee43fa326d2e871b24554da8327b01632673a076"}, + {file = "coverage-7.6.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00a1d69c112ff5149cabe60d2e2ee948752c975d95f1e1096742e6077affd376"}, + {file = "coverage-7.6.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f76846299ba5c54d12c91d776d9605ae33f8ae2b9d1d3c3703cf2db1a67f2c0"}, + {file = "coverage-7.6.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fe439416eb6380de434886b00c859304338f8b19f6f54811984f3420a2e03858"}, + {file = "coverage-7.6.4-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:0294ca37f1ba500667b1aef631e48d875ced93ad5e06fa665a3295bdd1d95111"}, + {file = "coverage-7.6.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6f01ba56b1c0e9d149f9ac85a2f999724895229eb36bd997b61e62999e9b0901"}, + {file = "coverage-7.6.4-cp39-cp39-win32.whl", hash = "sha256:bc66f0bf1d7730a17430a50163bb264ba9ded56739112368ba985ddaa9c3bd09"}, + {file = "coverage-7.6.4-cp39-cp39-win_amd64.whl", hash = "sha256:c481b47f6b5845064c65a7bc78bc0860e635a9b055af0df46fdf1c58cebf8e8f"}, + {file = "coverage-7.6.4-pp39.pp310-none-any.whl", hash = "sha256:3c65d37f3a9ebb703e710befdc489a38683a5b152242664b973a7b7b22348a4e"}, + {file = "coverage-7.6.4.tar.gz", hash = "sha256:29fc0f17b1d3fea332f8001d4558f8214af7f1d87a345f3a133c901d60347c73"}, +] + +[package.extras] +toml = ["tomli"] + [[package]] name = "curtsies" version = "0.4.2" @@ -339,6 +549,72 @@ files = [ {file = "cwcwidth-0.1.9.tar.gz", hash = "sha256:f19d11a0148d4a8cacd064c96e93bca8ce3415a186ae8204038f45e108db76b8"}, ] +[[package]] +name = "deprecated" +version = "1.2.14" +description = "Python @deprecated decorator to deprecate old python classes, functions or methods." +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "Deprecated-1.2.14-py2.py3-none-any.whl", hash = "sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c"}, + {file = "Deprecated-1.2.14.tar.gz", hash = "sha256:e5323eb936458dccc2582dc6f9c322c852a775a27065ff2b0c4970b9d53d01b3"}, +] + +[package.dependencies] +wrapt = ">=1.10,<2" + +[package.extras] +dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "sphinx (<2)", "tox"] + +[[package]] +name = "dnspython" +version = "2.7.0" +description = "DNS toolkit" +optional = false +python-versions = ">=3.9" +files = [ + {file = "dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86"}, + {file = "dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1"}, +] + +[package.extras] +dev = ["black (>=23.1.0)", "coverage (>=7.0)", "flake8 (>=7)", "hypercorn (>=0.16.0)", "mypy (>=1.8)", "pylint (>=3)", "pytest (>=7.4)", "pytest-cov (>=4.1.0)", "quart-trio (>=0.11.0)", "sphinx (>=7.2.0)", "sphinx-rtd-theme (>=2.0.0)", "twine (>=4.0.0)", "wheel (>=0.42.0)"] +dnssec = ["cryptography (>=43)"] +doh = ["h2 (>=4.1.0)", "httpcore (>=1.0.0)", "httpx (>=0.26.0)"] +doq = ["aioquic (>=1.0.0)"] +idna = ["idna (>=3.7)"] +trio = ["trio (>=0.23)"] +wmi = ["wmi (>=1.5.1)"] + +[[package]] +name = "email-validator" +version = "2.2.0" +description = "A robust email address syntax and deliverability validation library." +optional = false +python-versions = ">=3.8" +files = [ + {file = "email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631"}, + {file = "email_validator-2.2.0.tar.gz", hash = "sha256:cb690f344c617a714f22e66ae771445a1ceb46821152df8e165c5f9a364582b7"}, +] + +[package.dependencies] +dnspython = ">=2.0.0" +idna = ">=2.0.0" + +[[package]] +name = "execnet" +version = "2.1.1" +description = "execnet: rapid multi-Python deployment" +optional = false +python-versions = ">=3.8" +files = [ + {file = "execnet-2.1.1-py3-none-any.whl", hash = "sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc"}, + {file = "execnet-2.1.1.tar.gz", hash = "sha256:5189b52c6121c24feae288166ab41b32549c7e2348652736540b9e6e7d4e72e3"}, +] + +[package.extras] +testing = ["hatch", "pre-commit", "pytest", "tox"] + [[package]] name = "fastapi" version = "0.100.0" @@ -504,6 +780,52 @@ files = [ {file = "hpack-4.0.0.tar.gz", hash = "sha256:fc41de0c63e687ebffde81187a948221294896f6bdc0ae2312708df339430095"}, ] +[[package]] +name = "httpcore" +version = "1.0.6" +description = "A minimal low-level HTTP client." +optional = false +python-versions = ">=3.8" +files = [ + {file = "httpcore-1.0.6-py3-none-any.whl", hash = "sha256:27b59625743b85577a8c0e10e55b50b5368a4f2cfe8cc7bcfa9cf00829c2682f"}, + {file = "httpcore-1.0.6.tar.gz", hash = "sha256:73f6dbd6eb8c21bbf7ef8efad555481853f5f6acdeaff1edb0694289269ee17f"}, +] + +[package.dependencies] +certifi = "*" +h11 = ">=0.13,<0.15" + +[package.extras] +asyncio = ["anyio (>=4.0,<5.0)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] +trio = ["trio (>=0.22.0,<1.0)"] + +[[package]] +name = "httpx" +version = "0.27.2" +description = "The next generation HTTP client." +optional = false +python-versions = ">=3.8" +files = [ + {file = "httpx-0.27.2-py3-none-any.whl", hash = "sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0"}, + {file = "httpx-0.27.2.tar.gz", hash = "sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2"}, +] + +[package.dependencies] +anyio = "*" +certifi = "*" +httpcore = "==1.*" +idna = "*" +sniffio = "*" + +[package.extras] +brotli = ["brotli", "brotlicffi"] +cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] +zstd = ["zstandard (>=0.18.0)"] + [[package]] name = "human-readable" version = "1.3.4" @@ -563,6 +885,36 @@ files = [ [package.extras] all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] +[[package]] +name = "importlib-resources" +version = "6.4.5" +description = "Read resources from Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "importlib_resources-6.4.5-py3-none-any.whl", hash = "sha256:ac29d5f956f01d5e4bb63102a5a19957f1b9175e45649977264a1416783bb717"}, + {file = "importlib_resources-6.4.5.tar.gz", hash = "sha256:980862a1d16c9e147a59603677fa2aa5fd82b87f223b6cb870695bcfce830065"}, +] + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["jaraco.test (>=5.4)", "pytest (>=6,!=8.1.*)", "zipp (>=3.17)"] +type = ["pytest-mypy"] + +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.7" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + [[package]] name = "jinxed" version = "1.3.0" @@ -577,6 +929,35 @@ files = [ [package.dependencies] ansicon = {version = "*", markers = "platform_system == \"Windows\""} +[[package]] +name = "limits" +version = "3.13.0" +description = "Rate limiting utilities" +optional = false +python-versions = ">=3.8" +files = [ + {file = "limits-3.13.0-py3-none-any.whl", hash = "sha256:9767f7233da4255e9904b79908a728e8ec0984c0b086058b4cbbd309aea553f6"}, + {file = "limits-3.13.0.tar.gz", hash = "sha256:6571b0c567bfa175a35fed9f8a954c0c92f1c3200804282f1b8f1de4ad98a953"}, +] + +[package.dependencies] +deprecated = ">=1.2" +importlib-resources = ">=1.3" +packaging = ">=21,<25" +typing-extensions = "*" + +[package.extras] +all = ["aetcd", "coredis (>=3.4.0,<5)", "emcache (>=0.6.1)", "emcache (>=1)", "etcd3", "motor (>=3,<4)", "pymemcache (>3,<5.0.0)", "pymongo (>4.1,<5)", "redis (>3,!=4.5.2,!=4.5.3,<6.0.0)", "redis (>=4.2.0,!=4.5.2,!=4.5.3)"] +async-etcd = ["aetcd"] +async-memcached = ["emcache (>=0.6.1)", "emcache (>=1)"] +async-mongodb = ["motor (>=3,<4)"] +async-redis = ["coredis (>=3.4.0,<5)"] +etcd = ["etcd3"] +memcached = ["pymemcache (>3,<5.0.0)"] +mongodb = ["pymongo (>4.1,<5)"] +redis = ["redis (>3,!=4.5.2,!=4.5.3,<6.0.0)"] +rediscluster = ["redis (>=4.2.0,!=4.5.2,!=4.5.3)"] + [[package]] name = "memory-profiler" version = "0.61.0" @@ -793,6 +1174,21 @@ tzdata = ">=2020.1" [package.extras] test = ["time-machine (>=2.6.0)"] +[[package]] +name = "pluggy" +version = "1.5.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + [[package]] name = "priority" version = "2.0.0" @@ -864,6 +1260,35 @@ files = [ {file = "psycopg2-2.9.10.tar.gz", hash = "sha256:12ec0b40b0273f95296233e8750441339298e6a572f7039da5b260e3c8b60e11"}, ] +[[package]] +name = "pwdlib" +version = "0.2.1" +description = "Modern password hashing for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pwdlib-0.2.1-py3-none-any.whl", hash = "sha256:1823dc6f22eae472b540e889ecf57fd424051d6a4023ec0bcf7f0de2d9d7ef8c"}, + {file = "pwdlib-0.2.1.tar.gz", hash = "sha256:9a1d8a8fa09a2f7ebf208265e55d7d008103cbdc82b9e4902ffdd1ade91add5e"}, +] + +[package.dependencies] +argon2-cffi = {version = ">=23.1.0,<24", optional = true, markers = "extra == \"argon2\""} + +[package.extras] +argon2 = ["argon2-cffi (>=23.1.0,<24)"] +bcrypt = ["bcrypt (>=4.1.2,<5)"] + +[[package]] +name = "pycparser" +version = "2.22" +description = "C parser in Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, + {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, +] + [[package]] name = "pydantic" version = "2.9.2" @@ -1002,6 +1427,64 @@ files = [ [package.extras] windows-terminal = ["colorama (>=0.4.6)"] +[[package]] +name = "pytest" +version = "8.3.3" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2"}, + {file = "pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=1.5,<2" + +[package.extras] +dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "pytest-cov" +version = "6.0.0" +description = "Pytest plugin for measuring coverage." +optional = false +python-versions = ">=3.9" +files = [ + {file = "pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0"}, + {file = "pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35"}, +] + +[package.dependencies] +coverage = {version = ">=7.5", extras = ["toml"]} +pytest = ">=4.6" + +[package.extras] +testing = ["fields", "hunter", "process-tests", "pytest-xdist", "virtualenv"] + +[[package]] +name = "pytest-xdist" +version = "3.6.1" +description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest_xdist-3.6.1-py3-none-any.whl", hash = "sha256:9ed4adfb68a016610848639bb7e02c9352d5d9f03d04809919e2dafc3be4cca7"}, + {file = "pytest_xdist-3.6.1.tar.gz", hash = "sha256:ead156a4db231eec769737f57668ef58a2084a34b2e55c4a8fa20d861107300d"}, +] + +[package.dependencies] +execnet = ">=2.1" +pytest = ">=7.0.0" + +[package.extras] +psutil = ["psutil (>=3.0)"] +setproctitle = ["setproctitle"] +testing = ["filelock"] + [[package]] name = "python-dateutil" version = "2.9.0.post0" @@ -1261,6 +1744,85 @@ files = [ {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, ] +[[package]] +name = "wrapt" +version = "1.16.0" +description = "Module for decorators, wrappers and monkey patching." +optional = false +python-versions = ">=3.6" +files = [ + {file = "wrapt-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4"}, + {file = "wrapt-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136"}, + {file = "wrapt-1.16.0-cp310-cp310-win32.whl", hash = "sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d"}, + {file = "wrapt-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2"}, + {file = "wrapt-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09"}, + {file = "wrapt-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d"}, + {file = "wrapt-1.16.0-cp311-cp311-win32.whl", hash = "sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362"}, + {file = "wrapt-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89"}, + {file = "wrapt-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b"}, + {file = "wrapt-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c"}, + {file = "wrapt-1.16.0-cp312-cp312-win32.whl", hash = "sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc"}, + {file = "wrapt-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8"}, + {file = "wrapt-1.16.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8"}, + {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39"}, + {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c"}, + {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40"}, + {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc"}, + {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e"}, + {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465"}, + {file = "wrapt-1.16.0-cp36-cp36m-win32.whl", hash = "sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e"}, + {file = "wrapt-1.16.0-cp36-cp36m-win_amd64.whl", hash = "sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966"}, + {file = "wrapt-1.16.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593"}, + {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292"}, + {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5"}, + {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf"}, + {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228"}, + {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f"}, + {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c"}, + {file = "wrapt-1.16.0-cp37-cp37m-win32.whl", hash = "sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c"}, + {file = "wrapt-1.16.0-cp37-cp37m-win_amd64.whl", hash = "sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00"}, + {file = "wrapt-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0"}, + {file = "wrapt-1.16.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202"}, + {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0"}, + {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e"}, + {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f"}, + {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267"}, + {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca"}, + {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6"}, + {file = "wrapt-1.16.0-cp38-cp38-win32.whl", hash = "sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b"}, + {file = "wrapt-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41"}, + {file = "wrapt-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2"}, + {file = "wrapt-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb"}, + {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8"}, + {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c"}, + {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a"}, + {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664"}, + {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f"}, + {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537"}, + {file = "wrapt-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3"}, + {file = "wrapt-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35"}, + {file = "wrapt-1.16.0-py3-none-any.whl", hash = "sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1"}, + {file = "wrapt-1.16.0.tar.gz", hash = "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d"}, +] + [[package]] name = "wsproto" version = "1.2.0" @@ -1278,4 +1840,4 @@ h11 = ">=0.9.0,<1" [metadata] lock-version = "2.0" python-versions = "^3.12" -content-hash = "6cab1d930ad04560919f18c779fe4f9f2d28aba84d4385ed01aff1c876e453b6" +content-hash = "9dff2a47bb95e65f15616bb82926eb81d418456c5ec60db46dfe06056c643e31" diff --git a/backend/pyproject.toml b/backend/pyproject.toml index 7e2794d..b3d723e 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "linkpulse" -version = "0.2.2" +version = "0.3.0" description = "" authors = ["Xevion "] license = "GNU GPL v3" @@ -28,13 +28,23 @@ uvicorn = "^0.32.0" asgi-correlation-id = "^4.3.4" orjson = "^3.10.10" hypercorn = "^0.17.3" +pwdlib = {extras = ["argon2"], version = "^0.2.1"} +pytest-xdist = "^3.6.1" +email-validator = "^2.2.0" +limits = "^3.13.0" [tool.poetry.group.dev.dependencies] memory-profiler = "^0.61.0" bpython = "^0.24" types-pytz = "^2024.2.0.20241003" +pytest = "^8.3.3" +httpx = "^0.27.2" +pytest-cov = "^6.0.0" [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" + +[tool.black] +line-length = 110 \ No newline at end of file diff --git a/backend/pytest.ini b/backend/pytest.ini new file mode 100644 index 0000000..7220561 --- /dev/null +++ b/backend/pytest.ini @@ -0,0 +1,4 @@ +[pytest] +filterwarnings = + ignore::DeprecationWarning +addopts = --show-capture=stderr \ No newline at end of file diff --git a/backend/run.sh b/backend/run.sh index ac6ddc8..ca8134f 100755 --- a/backend/run.sh +++ b/backend/run.sh @@ -8,7 +8,16 @@ fi # Default to development mode if not defined export ENVIRONMENT=${ENVIRONMENT:-development} -COMMAND='poetry run python3 -m linkpulse' +export LOG_JSON_FORMAT=${LOG_JSON_FORMAT:-false} +export LOG_LEVEL=${LOG_LEVEL:-debug} +COMMAND="poetry run python3 -m linkpulse $@" + +# If arguments start with 'poetry run pytest' or 'pytest' use args as is +if [[ "$1" == "poetry" && "$2" == "run" && "$3" == "pytest" ]]; then + COMMAND=$@ +elif [[ "$1" == "pytest" ]]; then + COMMAND=$@ +fi # Check if Railway CLI is available RAILWAY_AVAILABLE=false @@ -43,11 +52,11 @@ if $RAILWAY_AVAILABLE; then fi if $DATABASE_DEFINED; then - $COMMAND $@ + $COMMAND else if $RAILWAY_AVAILABLE; then if $PROJECT_LINKED; then - DATABASE_URL="$(railway variables -s Postgres --json | jq .DATABASE_PUBLIC_URL -cMr)" $COMMAND $@ + DATABASE_URL="$(railway variables --service Postgres --environment development --json | jq .DATABASE_PUBLIC_URL -cMr)" $COMMAND else echo "error: Railway project not linked." echo "Run 'railway link' to link the project." diff --git a/frontend/.gitignore b/frontend/.gitignore index ffde942..a547bf3 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -1,6 +1,24 @@ -.eslintcache -.pnpm-debug.log -node_modules/ -coverage/ -dist/ -tsconfig.tsbuildinfo +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/frontend/.prettierignore b/frontend/.prettierignore index ff7892c..9b2cb4a 100644 --- a/frontend/.prettierignore +++ b/frontend/.prettierignore @@ -1,3 +1,4 @@ coverage/ dist/ pnpm-lock.yaml +src/routeTree.gen.ts diff --git a/frontend/.prettierrc b/frontend/.prettierrc new file mode 100644 index 0000000..222861c --- /dev/null +++ b/frontend/.prettierrc @@ -0,0 +1,4 @@ +{ + "tabWidth": 2, + "useTabs": false +} diff --git a/frontend/Caddyfile b/frontend/Caddyfile index 0f8a2d5..cf67267 100644 --- a/frontend/Caddyfile +++ b/frontend/Caddyfile @@ -16,7 +16,10 @@ # site block, listens on the $PORT environment variable, automatically assigned by railway :{$PORT} { respond /health 200 - encode gzip + encode { + zstd fastest + gzip 3 + } log { # access logs diff --git a/frontend/Caddyfile.development b/frontend/Caddyfile.development new file mode 100644 index 0000000..82282c7 --- /dev/null +++ b/frontend/Caddyfile.development @@ -0,0 +1,18 @@ +{ + admin off # theres no need for the admin api in railway's environment + auto_https off # railway handles https for us, this would cause issues if left enabled +} + +http://localhost:8080 { + respond /health 200 + encode { + zstd fastest + gzip 3 + } + + handle /api/* { + reverse_proxy localhost:8000 + } + + reverse_proxy localhost:5173 +} diff --git a/frontend/components.json b/frontend/components.json new file mode 100644 index 0000000..275d416 --- /dev/null +++ b/frontend/components.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "tailwind.config.js", + "css": "src/index.css", + "baseColor": "zinc", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "iconLibrary": "lucide" +} diff --git a/frontend/eslint.config.js b/frontend/eslint.config.js new file mode 100644 index 0000000..f6acaea --- /dev/null +++ b/frontend/eslint.config.js @@ -0,0 +1,28 @@ +import js from "@eslint/js"; +import reactHooks from "eslint-plugin-react-hooks"; +import reactRefresh from "eslint-plugin-react-refresh"; +import globals from "globals"; +import tseslint from "typescript-eslint"; + +export default tseslint.config( + { ignores: ["dist"] }, + { + extends: [js.configs.recommended, ...tseslint.configs.recommended], + files: ["**/*.{ts,tsx}"], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + }, + plugins: { + "react-hooks": reactHooks, + "react-refresh": reactRefresh, + }, + rules: { + ...reactHooks.configs.recommended.rules, + "react-refresh/only-export-components": [ + "warn", + { allowConstantExport: true }, + ], + }, + }, +); diff --git a/frontend/index.html b/frontend/index.html index 55583a3..b3297b1 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -1,16 +1,13 @@ - - - - App + + + + Linkpulse -
- +
+ - \ No newline at end of file + diff --git a/frontend/package.json b/frontend/package.json index 8a34e3d..9906d00 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,58 +1,52 @@ { - "name": "linkpulse", - "version": "0.0.1", - "author": "Xevion ", - "type": "module", - "engines": { - "node": ">=22.0.0", - "pnpm": ">=9.0.0" - }, - "dependencies": { - "react": "^18.3.1", - "react-dom": "^18.3.1" - }, - "devDependencies": { - "@ianvs/prettier-plugin-sort-imports": "^4.2.1", - "@nkzw/eslint-config": "^1.16.0", - "@swc/core": "^1.6.5", - "@types/node": "^20.14.8", - "@types/react": "^18.3.3", - "@types/react-dom": "^18.3.0", - "@vitejs/plugin-react": "^4.3.1", - "autoprefixer": "^10.4.19", - "eslint": "^8.57.0", - "npm-run-all2": "^6.2.0", - "postcss": "^8.4.38", - "prettier": "^3.3.2", - "prettier-plugin-tailwindcss": "^0.6.5", - "tailwindcss": "^3.4.4", - "ts-node": "^10.9.2", - "typescript": "^5.5.2", - "vite": "^5.3.1", - "vitest": "^1.6.0" - }, - "scripts": { - "preinstall": "command -v git >/dev/null 2>&1 && git config core.hooksPath git-hooks || true", - "build": "vite build", - "dev:update-deps": "rm -rf pnpm-lock.yaml node_modules/ **/node_modules && pnpm install", - "dev": "vite dev", - "format": "prettier --write .", - "lint:format": "prettier --cache --check .", - "lint": "eslint --cache .", - "test": "npm-run-all --parallel tsc:check vitest:run lint lint:format", - "tsc:check": "tsc", - "vitest:run": "vitest run" - }, - "browserslist": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "pnpm": { - "updateConfig": { - "ignoreDependencies": [ - "eslint" - ] - } - } - } \ No newline at end of file + "name": "linkpulse", + "private": true, + "version": "0.3.0", + "author": { + "name": "Xevion", + "url": "https://xevion.dev", + "email": "xevion@xevion.dev" + }, + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "@radix-ui/react-label": "^2.1.0", + "@radix-ui/react-slot": "^1.1.0", + "@tanstack/react-router": "^1.81.1", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.1", + "lucide-react": "^0.456.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "tailwind-merge": "^2.5.4", + "tailwindcss-animate": "^1.0.7", + "true-myth": "^8.0.1", + "zustand": "^5.0.1" + }, + "devDependencies": { + "@eslint/js": "^9.13.0", + "@tanstack/router-devtools": "^1.81.1", + "@tanstack/router-plugin": "^1.79.0", + "@types/node": "^22.9.0", + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", + "@vitejs/plugin-react-swc": "^3.5.0", + "autoprefixer": "^10.4.20", + "eslint": "^9.13.0", + "eslint-plugin-react-hooks": "^5.0.0", + "eslint-plugin-react-refresh": "^0.4.14", + "globals": "^15.11.0", + "postcss": "^8.4.47", + "prettier": "^3.3.3", + "tailwindcss": "^3.4.14", + "typescript": "~5.6.2", + "typescript-eslint": "^8.11.0", + "vite": "^5.4.10", + "vitest": "^2.1.4" + } +} diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index a2f2d39..e8ce723 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -8,67 +8,100 @@ importers: .: dependencies: + '@radix-ui/react-label': + specifier: ^2.1.0 + version: 2.1.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-slot': + specifier: ^1.1.0 + version: 1.1.0(@types/react@18.3.12)(react@18.3.1) + '@tanstack/react-router': + specifier: ^1.81.1 + version: 1.81.1(@tanstack/router-generator@1.79.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + class-variance-authority: + specifier: ^0.7.0 + version: 0.7.0 + clsx: + specifier: ^2.1.1 + version: 2.1.1 + lucide-react: + specifier: ^0.456.0 + version: 0.456.0(react@18.3.1) react: specifier: ^18.3.1 version: 18.3.1 react-dom: specifier: ^18.3.1 version: 18.3.1(react@18.3.1) + tailwind-merge: + specifier: ^2.5.4 + version: 2.5.4 + tailwindcss-animate: + specifier: ^1.0.7 + version: 1.0.7(tailwindcss@3.4.14) + true-myth: + specifier: ^8.0.1 + version: 8.0.1 + zustand: + specifier: ^5.0.1 + version: 5.0.1(@types/react@18.3.12)(react@18.3.1)(use-sync-external-store@1.2.2(react@18.3.1)) devDependencies: - '@ianvs/prettier-plugin-sort-imports': - specifier: ^4.2.1 - version: 4.3.1(prettier@3.3.3) - '@nkzw/eslint-config': - specifier: ^1.16.0 - version: 1.18.1(eslint@8.57.1)(typescript@5.6.3) - '@swc/core': - specifier: ^1.6.5 - version: 1.7.36 + '@eslint/js': + specifier: ^9.13.0 + version: 9.14.0 + '@tanstack/router-devtools': + specifier: ^1.81.1 + version: 1.81.1(@tanstack/react-router@1.81.1(@tanstack/router-generator@1.79.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(csstype@3.1.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@tanstack/router-plugin': + specifier: ^1.79.0 + version: 1.79.0(vite@5.4.10(@types/node@22.9.0)) '@types/node': - specifier: ^20.14.8 - version: 20.16.11 + specifier: ^22.9.0 + version: 22.9.0 '@types/react': - specifier: ^18.3.3 - version: 18.3.11 + specifier: ^18.3.12 + version: 18.3.12 '@types/react-dom': - specifier: ^18.3.0 + specifier: ^18.3.1 version: 18.3.1 - '@vitejs/plugin-react': - specifier: ^4.3.1 - version: 4.3.2(vite@5.4.9(@types/node@20.16.11)) + '@vitejs/plugin-react-swc': + specifier: ^3.5.0 + version: 3.7.1(vite@5.4.10(@types/node@22.9.0)) autoprefixer: - specifier: ^10.4.19 + specifier: ^10.4.20 version: 10.4.20(postcss@8.4.47) eslint: - specifier: ^8.57.0 - version: 8.57.1 - npm-run-all2: - specifier: ^6.2.0 - version: 6.2.3 + specifier: ^9.13.0 + version: 9.14.0(jiti@1.21.6) + eslint-plugin-react-hooks: + specifier: ^5.0.0 + version: 5.0.0(eslint@9.14.0(jiti@1.21.6)) + eslint-plugin-react-refresh: + specifier: ^0.4.14 + version: 0.4.14(eslint@9.14.0(jiti@1.21.6)) + globals: + specifier: ^15.11.0 + version: 15.12.0 postcss: - specifier: ^8.4.38 + specifier: ^8.4.47 version: 8.4.47 prettier: - specifier: ^3.3.2 + specifier: ^3.3.3 version: 3.3.3 - prettier-plugin-tailwindcss: - specifier: ^0.6.5 - version: 0.6.8(@ianvs/prettier-plugin-sort-imports@4.3.1(prettier@3.3.3))(prettier@3.3.3) tailwindcss: - specifier: ^3.4.4 - version: 3.4.14(ts-node@10.9.2(@swc/core@1.7.36)(@types/node@20.16.11)(typescript@5.6.3)) - ts-node: - specifier: ^10.9.2 - version: 10.9.2(@swc/core@1.7.36)(@types/node@20.16.11)(typescript@5.6.3) + specifier: ^3.4.14 + version: 3.4.14 typescript: - specifier: ^5.5.2 + specifier: ~5.6.2 version: 5.6.3 + typescript-eslint: + specifier: ^8.11.0 + version: 8.13.0(eslint@9.14.0(jiti@1.21.6))(typescript@5.6.3) vite: - specifier: ^5.3.1 - version: 5.4.9(@types/node@20.16.11) + specifier: ^5.4.10 + version: 5.4.10(@types/node@22.9.0) vitest: - specifier: ^1.6.0 - version: 1.6.0(@types/node@20.16.11) + specifier: ^2.1.4 + version: 2.1.4(@types/node@22.9.0) packages: @@ -80,283 +113,425 @@ packages: resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} - '@babel/code-frame@7.25.7': - resolution: {integrity: sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g==} + '@babel/code-frame@7.26.2': + resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.25.8': - resolution: {integrity: sha512-ZsysZyXY4Tlx+Q53XdnOFmqwfB9QDTHYxaZYajWRoBLuLEAwI2UIbtxOjWh/cFaa9IKUlcB+DDuoskLuKu56JA==} + '@babel/compat-data@7.26.2': + resolution: {integrity: sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg==} engines: {node: '>=6.9.0'} - '@babel/core@7.25.8': - resolution: {integrity: sha512-Oixnb+DzmRT30qu9d3tJSQkxuygWm32DFykT4bRoORPa9hZ/L4KhVB/XiRm6KG+roIEM7DBQlmg27kw2HZkdZg==} + '@babel/core@7.26.0': + resolution: {integrity: sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==} engines: {node: '>=6.9.0'} - '@babel/generator@7.25.7': - resolution: {integrity: sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA==} + '@babel/generator@7.26.2': + resolution: {integrity: sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==} engines: {node: '>=6.9.0'} - '@babel/helper-compilation-targets@7.25.7': - resolution: {integrity: sha512-DniTEax0sv6isaw6qSQSfV4gVRNtw2rte8HHM45t9ZR0xILaufBRNkpMifCRiAPyvL4ACD6v0gfCwCmtOQaV4A==} + '@babel/helper-compilation-targets@7.25.9': + resolution: {integrity: sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==} engines: {node: '>=6.9.0'} - '@babel/helper-module-imports@7.25.7': - resolution: {integrity: sha512-o0xCgpNmRohmnoWKQ0Ij8IdddjyBFE4T2kagL/x6M3+4zUgc+4qTOUBoNe4XxDskt1HPKO007ZPiMgLDq2s7Kw==} + '@babel/helper-module-imports@7.25.9': + resolution: {integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==} engines: {node: '>=6.9.0'} - '@babel/helper-module-transforms@7.25.7': - resolution: {integrity: sha512-k/6f8dKG3yDz/qCwSM+RKovjMix563SLxQFo0UhRNo239SP6n9u5/eLtKD6EAjwta2JHJ49CsD8pms2HdNiMMQ==} + '@babel/helper-module-transforms@7.26.0': + resolution: {integrity: sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-plugin-utils@7.25.7': - resolution: {integrity: sha512-eaPZai0PiqCi09pPs3pAFfl/zYgGaE6IdXtYvmf0qlcDTd3WCtO7JWCcRd64e0EQrcYgiHibEZnOGsSY4QSgaw==} + '@babel/helper-plugin-utils@7.25.9': + resolution: {integrity: sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==} engines: {node: '>=6.9.0'} - '@babel/helper-simple-access@7.25.7': - resolution: {integrity: sha512-FPGAkJmyoChQeM+ruBGIDyrT2tKfZJO8NcxdC+CWNJi7N8/rZpSxK7yvBJ5O/nF1gfu5KzN7VKG3YVSLFfRSxQ==} + '@babel/helper-string-parser@7.25.9': + resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} engines: {node: '>=6.9.0'} - '@babel/helper-string-parser@7.25.7': - resolution: {integrity: sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g==} + '@babel/helper-validator-identifier@7.25.9': + resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.25.7': - resolution: {integrity: sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg==} + '@babel/helper-validator-option@7.25.9': + resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-option@7.25.7': - resolution: {integrity: sha512-ytbPLsm+GjArDYXJ8Ydr1c/KJuutjF2besPNbIZnZ6MKUxi/uTA22t2ymmA4WFjZFpjiAMO0xuuJPqK2nvDVfQ==} + '@babel/helpers@7.26.0': + resolution: {integrity: sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==} engines: {node: '>=6.9.0'} - '@babel/helpers@7.25.7': - resolution: {integrity: sha512-Sv6pASx7Esm38KQpF/U/OXLwPPrdGHNKoeblRxgZRLXnAtnkEe4ptJPDtAZM7fBLadbc1Q07kQpSiGQ0Jg6tRA==} - engines: {node: '>=6.9.0'} - - '@babel/highlight@7.25.7': - resolution: {integrity: sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw==} - engines: {node: '>=6.9.0'} - - '@babel/parser@7.25.8': - resolution: {integrity: sha512-HcttkxzdPucv3nNFmfOOMfFf64KgdJVqm1KaCm25dPGMLElo9nsLvXeJECQg8UzPuBGLyTSA0ZzqCtDSzKTEoQ==} + '@babel/parser@7.26.2': + resolution: {integrity: sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==} engines: {node: '>=6.0.0'} hasBin: true - '@babel/plugin-transform-react-jsx-self@7.25.7': - resolution: {integrity: sha512-JD9MUnLbPL0WdVK8AWC7F7tTG2OS6u/AKKnsK+NdRhUiVdnzyR1S3kKQCaRLOiaULvUiqK6Z4JQE635VgtCFeg==} + '@babel/plugin-syntax-jsx@7.25.9': + resolution: {integrity: sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-react-jsx-source@7.25.7': - resolution: {integrity: sha512-S/JXG/KrbIY06iyJPKfxr0qRxnhNOdkNXYBl/rmwgDd72cQLH9tEGkDm/yJPGvcSIUoikzfjMios9i+xT/uv9w==} + '@babel/plugin-syntax-typescript@7.25.9': + resolution: {integrity: sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/template@7.25.7': - resolution: {integrity: sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA==} + '@babel/template@7.25.9': + resolution: {integrity: sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.25.7': - resolution: {integrity: sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg==} + '@babel/traverse@7.25.9': + resolution: {integrity: sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==} engines: {node: '>=6.9.0'} - '@babel/types@7.25.8': - resolution: {integrity: sha512-JWtuCu8VQsMladxVz/P4HzHUGCAwpuqacmowgXFs5XjxIgKuNjnLokQzuVjlTvIzODaDmpjT3oxcC48vyk9EWg==} + '@babel/types@7.26.0': + resolution: {integrity: sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==} engines: {node: '>=6.9.0'} - '@cspotcode/source-map-support@0.8.1': - resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} - engines: {node: '>=12'} - '@esbuild/aix-ppc64@0.21.5': resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} engines: {node: '>=12'} cpu: [ppc64] os: [aix] + '@esbuild/aix-ppc64@0.23.1': + resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + '@esbuild/android-arm64@0.21.5': resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} engines: {node: '>=12'} cpu: [arm64] os: [android] + '@esbuild/android-arm64@0.23.1': + resolution: {integrity: sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm@0.21.5': resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} engines: {node: '>=12'} cpu: [arm] os: [android] + '@esbuild/android-arm@0.23.1': + resolution: {integrity: sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-x64@0.21.5': resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} engines: {node: '>=12'} cpu: [x64] os: [android] + '@esbuild/android-x64@0.23.1': + resolution: {integrity: sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/darwin-arm64@0.21.5': resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} engines: {node: '>=12'} cpu: [arm64] os: [darwin] + '@esbuild/darwin-arm64@0.23.1': + resolution: {integrity: sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-x64@0.21.5': resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} engines: {node: '>=12'} cpu: [x64] os: [darwin] + '@esbuild/darwin-x64@0.23.1': + resolution: {integrity: sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/freebsd-arm64@0.21.5': resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} engines: {node: '>=12'} cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-arm64@0.23.1': + resolution: {integrity: sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-x64@0.21.5': resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} engines: {node: '>=12'} cpu: [x64] os: [freebsd] + '@esbuild/freebsd-x64@0.23.1': + resolution: {integrity: sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/linux-arm64@0.21.5': resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} engines: {node: '>=12'} cpu: [arm64] os: [linux] + '@esbuild/linux-arm64@0.23.1': + resolution: {integrity: sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm@0.21.5': resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} engines: {node: '>=12'} cpu: [arm] os: [linux] + '@esbuild/linux-arm@0.23.1': + resolution: {integrity: sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + '@esbuild/linux-ia32@0.21.5': resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} engines: {node: '>=12'} cpu: [ia32] os: [linux] + '@esbuild/linux-ia32@0.23.1': + resolution: {integrity: sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-loong64@0.21.5': resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} engines: {node: '>=12'} cpu: [loong64] os: [linux] + '@esbuild/linux-loong64@0.23.1': + resolution: {integrity: sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-mips64el@0.21.5': resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} engines: {node: '>=12'} cpu: [mips64el] os: [linux] + '@esbuild/linux-mips64el@0.23.1': + resolution: {integrity: sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-ppc64@0.21.5': resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} engines: {node: '>=12'} cpu: [ppc64] os: [linux] + '@esbuild/linux-ppc64@0.23.1': + resolution: {integrity: sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-riscv64@0.21.5': resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} engines: {node: '>=12'} cpu: [riscv64] os: [linux] + '@esbuild/linux-riscv64@0.23.1': + resolution: {integrity: sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-s390x@0.21.5': resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} engines: {node: '>=12'} cpu: [s390x] os: [linux] + '@esbuild/linux-s390x@0.23.1': + resolution: {integrity: sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-x64@0.21.5': resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} engines: {node: '>=12'} cpu: [x64] os: [linux] + '@esbuild/linux-x64@0.23.1': + resolution: {integrity: sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/netbsd-x64@0.21.5': resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} engines: {node: '>=12'} cpu: [x64] os: [netbsd] + '@esbuild/netbsd-x64@0.23.1': + resolution: {integrity: sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.23.1': + resolution: {integrity: sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-x64@0.21.5': resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} engines: {node: '>=12'} cpu: [x64] os: [openbsd] + '@esbuild/openbsd-x64@0.23.1': + resolution: {integrity: sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + '@esbuild/sunos-x64@0.21.5': resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} engines: {node: '>=12'} cpu: [x64] os: [sunos] + '@esbuild/sunos-x64@0.23.1': + resolution: {integrity: sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/win32-arm64@0.21.5': resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} engines: {node: '>=12'} cpu: [arm64] os: [win32] + '@esbuild/win32-arm64@0.23.1': + resolution: {integrity: sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-ia32@0.21.5': resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} engines: {node: '>=12'} cpu: [ia32] os: [win32] + '@esbuild/win32-ia32@0.23.1': + resolution: {integrity: sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-x64@0.21.5': resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} engines: {node: '>=12'} cpu: [x64] os: [win32] - '@eslint-community/eslint-utils@4.4.0': - resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} + '@esbuild/win32-x64@0.23.1': + resolution: {integrity: sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@eslint-community/eslint-utils@4.4.1': + resolution: {integrity: sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - '@eslint-community/regexpp@4.11.1': - resolution: {integrity: sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==} + '@eslint-community/regexpp@4.12.1': + resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/eslintrc@2.1.4': - resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@eslint/config-array@0.18.0': + resolution: {integrity: sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@8.57.1': - resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@eslint/core@0.7.0': + resolution: {integrity: sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@humanwhocodes/config-array@0.13.0': - resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} - engines: {node: '>=10.10.0'} - deprecated: Use @eslint/config-array instead + '@eslint/eslintrc@3.1.0': + resolution: {integrity: sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.14.0': + resolution: {integrity: sha512-pFoEtFWCPyDOl+C6Ift+wC7Ro89otjigCf5vcuWqWgqNSQbRrpjSvdeE6ofLz4dHmyxD5f7gIdGT4+p36L6Twg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.4': + resolution: {integrity: sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.2.2': + resolution: {integrity: sha512-CXtq5nR4Su+2I47WPOlWud98Y5Lv8Kyxp2ukhgFx/eW6Blm18VXJO5WuQylPugRo8nbluoi6GvvxBLqHcvqUUw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@humanfs/core@0.19.1': + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.6': + resolution: {integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==} + engines: {node: '>=18.18.0'} '@humanwhocodes/module-importer@1.0.1': resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} engines: {node: '>=12.22'} - '@humanwhocodes/object-schema@2.0.3': - resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} - deprecated: Use @eslint/object-schema instead + '@humanwhocodes/retry@0.3.1': + resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==} + engines: {node: '>=18.18'} - '@ianvs/prettier-plugin-sort-imports@4.3.1': - resolution: {integrity: sha512-ZHwbyjkANZOjaBm3ZosADD2OUYGFzQGxfy67HmGZU94mHqe7g1LCMA7YYKB1Cq+UTPCBqlAYapY0KXAjKEw8Sg==} - peerDependencies: - '@vue/compiler-sfc': 2.7.x || 3.x - prettier: 2 || 3 - peerDependenciesMeta: - '@vue/compiler-sfc': - optional: true + '@humanwhocodes/retry@0.4.1': + resolution: {integrity: sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==} + engines: {node: '>=18.18'} '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} - '@jest/schemas@29.6.3': - resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - '@jridgewell/gen-mapping@0.3.5': resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} engines: {node: '>=6.0.0'} @@ -375,19 +550,6 @@ packages: '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} - '@jridgewell/trace-mapping@0.3.9': - resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} - - '@nkzw/eslint-config@1.18.1': - resolution: {integrity: sha512-dpVQ6OPHD2/tU8K9ThMBXCmSIUfgessxH8/iCnzQrjyTmFnMNJhIZMsE0DqnIfFFdhf7Fu6dZkvKmHllzi2/bg==} - peerDependencies: - eslint: '>= 8' - - '@nkzw/eslint-plugin@1.8.0': - resolution: {integrity: sha512-doODSLfA7C6fA/wF20uk9whJIeH0ZydyVb8PlhDBZE0kJaOUSKfZqTKzxflxPF9sGG+Lhr2v/Ih//dzBHp/rxw==} - peerDependencies: - eslint: '>= 8' - '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -400,162 +562,206 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - '@nolyfill/is-core-module@1.0.39': - resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} - engines: {node: '>=12.4.0'} - '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@rollup/rollup-android-arm-eabi@4.24.0': - resolution: {integrity: sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA==} + '@radix-ui/react-compose-refs@1.1.0': + resolution: {integrity: sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-label@2.1.0': + resolution: {integrity: sha512-peLblDlFw/ngk3UWq0VnYaOLy6agTZZ+MUO/WhVfm14vJGML+xH4FAl2XQGLqdefjNb7ApRg6Yn7U42ZhmYXdw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-primitive@2.0.0': + resolution: {integrity: sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-slot@1.1.0': + resolution: {integrity: sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@rollup/rollup-android-arm-eabi@4.25.0': + resolution: {integrity: sha512-CC/ZqFZwlAIbU1wUPisHyV/XRc5RydFrNLtgl3dGYskdwPZdt4HERtKm50a/+DtTlKeCq9IXFEWR+P6blwjqBA==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.24.0': - resolution: {integrity: sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA==} + '@rollup/rollup-android-arm64@4.25.0': + resolution: {integrity: sha512-/Y76tmLGUJqVBXXCfVS8Q8FJqYGhgH4wl4qTA24E9v/IJM0XvJCGQVSW1QZ4J+VURO9h8YCa28sTFacZXwK7Rg==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.24.0': - resolution: {integrity: sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA==} + '@rollup/rollup-darwin-arm64@4.25.0': + resolution: {integrity: sha512-YVT6L3UrKTlC0FpCZd0MGA7NVdp7YNaEqkENbWQ7AOVOqd/7VzyHpgIpc1mIaxRAo1ZsJRH45fq8j4N63I/vvg==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.24.0': - resolution: {integrity: sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ==} + '@rollup/rollup-darwin-x64@4.25.0': + resolution: {integrity: sha512-ZRL+gexs3+ZmmWmGKEU43Bdn67kWnMeWXLFhcVv5Un8FQcx38yulHBA7XR2+KQdYIOtD0yZDWBCudmfj6lQJoA==} cpu: [x64] os: [darwin] - '@rollup/rollup-linux-arm-gnueabihf@4.24.0': - resolution: {integrity: sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA==} + '@rollup/rollup-freebsd-arm64@4.25.0': + resolution: {integrity: sha512-xpEIXhiP27EAylEpreCozozsxWQ2TJbOLSivGfXhU4G1TBVEYtUPi2pOZBnvGXHyOdLAUUhPnJzH3ah5cqF01g==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.25.0': + resolution: {integrity: sha512-sC5FsmZGlJv5dOcURrsnIK7ngc3Kirnx3as2XU9uER+zjfyqIjdcMVgzy4cOawhsssqzoAX19qmxgJ8a14Qrqw==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.25.0': + resolution: {integrity: sha512-uD/dbLSs1BEPzg564TpRAQ/YvTnCds2XxyOndAO8nJhaQcqQGFgv/DAVko/ZHap3boCvxnzYMa3mTkV/B/3SWA==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.24.0': - resolution: {integrity: sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw==} + '@rollup/rollup-linux-arm-musleabihf@4.25.0': + resolution: {integrity: sha512-ZVt/XkrDlQWegDWrwyC3l0OfAF7yeJUF4fq5RMS07YM72BlSfn2fQQ6lPyBNjt+YbczMguPiJoCfaQC2dnflpQ==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.24.0': - resolution: {integrity: sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA==} + '@rollup/rollup-linux-arm64-gnu@4.25.0': + resolution: {integrity: sha512-qboZ+T0gHAW2kkSDPHxu7quaFaaBlynODXpBVnPxUgvWYaE84xgCKAPEYE+fSMd3Zv5PyFZR+L0tCdYCMAtG0A==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.24.0': - resolution: {integrity: sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw==} + '@rollup/rollup-linux-arm64-musl@4.25.0': + resolution: {integrity: sha512-ndWTSEmAaKr88dBuogGH2NZaxe7u2rDoArsejNslugHZ+r44NfWiwjzizVS1nUOHo+n1Z6qV3X60rqE/HlISgw==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-powerpc64le-gnu@4.24.0': - resolution: {integrity: sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw==} + '@rollup/rollup-linux-powerpc64le-gnu@4.25.0': + resolution: {integrity: sha512-BVSQvVa2v5hKwJSy6X7W1fjDex6yZnNKy3Kx1JGimccHft6HV0THTwNtC2zawtNXKUu+S5CjXslilYdKBAadzA==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.24.0': - resolution: {integrity: sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg==} + '@rollup/rollup-linux-riscv64-gnu@4.25.0': + resolution: {integrity: sha512-G4hTREQrIdeV0PE2JruzI+vXdRnaK1pg64hemHq2v5fhv8C7WjVaeXc9P5i4Q5UC06d/L+zA0mszYIKl+wY8oA==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.24.0': - resolution: {integrity: sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g==} + '@rollup/rollup-linux-s390x-gnu@4.25.0': + resolution: {integrity: sha512-9T/w0kQ+upxdkFL9zPVB6zy9vWW1deA3g8IauJxojN4bnz5FwSsUAD034KpXIVX5j5p/rn6XqumBMxfRkcHapQ==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.24.0': - resolution: {integrity: sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A==} + '@rollup/rollup-linux-x64-gnu@4.25.0': + resolution: {integrity: sha512-ThcnU0EcMDn+J4B9LD++OgBYxZusuA7iemIIiz5yzEcFg04VZFzdFjuwPdlURmYPZw+fgVrFzj4CA64jSTG4Ig==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.24.0': - resolution: {integrity: sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ==} + '@rollup/rollup-linux-x64-musl@4.25.0': + resolution: {integrity: sha512-zx71aY2oQxGxAT1JShfhNG79PnjYhMC6voAjzpu/xmMjDnKNf6Nl/xv7YaB/9SIa9jDYf8RBPWEnjcdlhlv1rQ==} cpu: [x64] os: [linux] - '@rollup/rollup-win32-arm64-msvc@4.24.0': - resolution: {integrity: sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ==} + '@rollup/rollup-win32-arm64-msvc@4.25.0': + resolution: {integrity: sha512-JT8tcjNocMs4CylWY/CxVLnv8e1lE7ff1fi6kbGocWwxDq9pj30IJ28Peb+Y8yiPNSF28oad42ApJB8oUkwGww==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.24.0': - resolution: {integrity: sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ==} + '@rollup/rollup-win32-ia32-msvc@4.25.0': + resolution: {integrity: sha512-dRLjLsO3dNOfSN6tjyVlG+Msm4IiZnGkuZ7G5NmpzwF9oOc582FZG05+UdfTbz5Jd4buK/wMb6UeHFhG18+OEg==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.24.0': - resolution: {integrity: sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw==} + '@rollup/rollup-win32-x64-msvc@4.25.0': + resolution: {integrity: sha512-/RqrIFtLB926frMhZD0a5oDa4eFIbyNEwLLloMTEjmqfwZWXywwVVOVmwTsuyhC9HKkVEZcOOi+KV4U9wmOdlg==} cpu: [x64] os: [win32] - '@rtsao/scc@1.1.0': - resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} - - '@sinclair/typebox@0.27.8': - resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} - - '@swc/core-darwin-arm64@1.7.36': - resolution: {integrity: sha512-8vDczXzCgv3ceTPhEivlpGprN44YlrCK1nbfU9g2TrhV/Aiqi09W/eM5zLesdoM1Z3mJl492gc/8nlTkpDdusw==} + '@swc/core-darwin-arm64@1.9.1': + resolution: {integrity: sha512-2/ncHSCdAh5OHem1fMITrWEzzl97OdMK1PHc9CkxSJnphLjRubfxB5sbc5tDhcO68a5tVy+DxwaBgDec3PXnOg==} engines: {node: '>=10'} cpu: [arm64] os: [darwin] - '@swc/core-darwin-x64@1.7.36': - resolution: {integrity: sha512-Pa2Gao7+Wf5m3SsK4abKRtd48AtoUnJInvaC3d077swBfgZjbjUbQvcpdc2dOeQtWwo49rFqUZJonMsL0jnPgQ==} + '@swc/core-darwin-x64@1.9.1': + resolution: {integrity: sha512-4MDOFC5zmNqRJ9RGFOH95oYf27J9HniLVpB1pYm2gGeNHdl2QvDMtx2QTuMHQ6+OTn/3y1BHYuhBGp7d405oLA==} engines: {node: '>=10'} cpu: [x64] os: [darwin] - '@swc/core-linux-arm-gnueabihf@1.7.36': - resolution: {integrity: sha512-3YsMWd7V+WZEjbfBnLkkz/olcRBa8nyoK0iIOnNARJBMcYaJxjkJSMZpmSojCnIVwvjA1N83CPAbUL+W+fCnHg==} + '@swc/core-linux-arm-gnueabihf@1.9.1': + resolution: {integrity: sha512-eVW/BjRW8/HpLe3+1jRU7w7PdRLBgnEEYTkHJISU8805/EKT03xNZn6CfaBpKfeAloY4043hbGzE/NP9IahdpQ==} engines: {node: '>=10'} cpu: [arm] os: [linux] - '@swc/core-linux-arm64-gnu@1.7.36': - resolution: {integrity: sha512-lqM3aBB7kJazJYOwHeA5OGNLqXoQPZ/76b3dV+XcjN1GhD0CcXz6mW5PRYVin6OSN1eKrKBKJjtDA1mqADDEvw==} + '@swc/core-linux-arm64-gnu@1.9.1': + resolution: {integrity: sha512-8m3u1v8R8NgI/9+cHMkzk14w87blSy3OsQPWPfhOL+XPwhyLPvat+ahQJb2nZmltjTgkB4IbzKFSfbuA34LmNA==} engines: {node: '>=10'} cpu: [arm64] os: [linux] - '@swc/core-linux-arm64-musl@1.7.36': - resolution: {integrity: sha512-bqei2YDzvUfG0pth5W2xJaj0eG4XWYk0d/NJ75vBX6bkIzK6dC8iuKQ41jOfUWonnrAs7rTDDJW0sTn/evvRdw==} + '@swc/core-linux-arm64-musl@1.9.1': + resolution: {integrity: sha512-hpT0sQAZnW8l02I289yeyFfT9llGO9PzKDxUq8pocKtioEHiElRqR53juCWoSmzuWi+6KX7zUJ0NKCBrc8pmDg==} engines: {node: '>=10'} cpu: [arm64] os: [linux] - '@swc/core-linux-x64-gnu@1.7.36': - resolution: {integrity: sha512-03maXTUyaBjeCxlDltmdzHje1ryQt1C4OWmmNgSSRXjLb+GNnAenwOJMSrcvHP/aNClD2pwsFCnYKDGy+sYE6w==} + '@swc/core-linux-x64-gnu@1.9.1': + resolution: {integrity: sha512-sGFdpdAYusk/ropHiwtXom2JrdaKPxl8MqemRv6dvxZq1Gm/GdmOowxdXIPjCgBGMgoXVcgNviH6CgiO5q+UtA==} engines: {node: '>=10'} cpu: [x64] os: [linux] - '@swc/core-linux-x64-musl@1.7.36': - resolution: {integrity: sha512-XXysqLkvjtQnXm1zHqLhy00UYPv/gk5OtwR732X+piNisnEbcJBqI8Qp9O7YvLWllRcoP8IMBGDWLGdGLSpViA==} + '@swc/core-linux-x64-musl@1.9.1': + resolution: {integrity: sha512-YtNLNwIWs0Z2+XgBs6+LrCIGtfCDtNr4S4b6Q5HDOreEIGzSvhkef8eyBI5L+fJ2eGov4b7iEo61C4izDJS5RA==} engines: {node: '>=10'} cpu: [x64] os: [linux] - '@swc/core-win32-arm64-msvc@1.7.36': - resolution: {integrity: sha512-k7+dmb13a/zPw+E4XYfPmLZFWJgcOcBRKIjYl9nQErtYsgsg3Ji6TBbsvJVETy23lNHyewZ17V5Vq6NzaG0hzg==} + '@swc/core-win32-arm64-msvc@1.9.1': + resolution: {integrity: sha512-qSxD3uZW2vSiHqUt30vUi0PB92zDh9bjqh5YKpfhhVa7h1vt/xXhlid8yMvSNToTfzhRrTEffOAPUr7WVoyQUA==} engines: {node: '>=10'} cpu: [arm64] os: [win32] - '@swc/core-win32-ia32-msvc@1.7.36': - resolution: {integrity: sha512-ridD3ay6YM2PEYHZXXFN+edYEv0FOynaqOBP+NSnGNHA35azItIjoIe+KNi4WltGtAjpKCHSpjGCNfna12wdYQ==} + '@swc/core-win32-ia32-msvc@1.9.1': + resolution: {integrity: sha512-C3fPEwyX/WRPlX6zIToNykJuz1JkZX0sk8H1QH2vpnKuySUkt/Ur5K2FzLgSWzJdbfxstpgS151/es0VGAD+ZA==} engines: {node: '>=10'} cpu: [ia32] os: [win32] - '@swc/core-win32-x64-msvc@1.7.36': - resolution: {integrity: sha512-j1z2Z1Ln9d0E3dHsPkC1K9XDh0ojhRPwV+GfRTu4D61PE+aYhYLvbJC6xPvL4/204QrStRS7eDu3m+BcDp3rgQ==} + '@swc/core-win32-x64-msvc@1.9.1': + resolution: {integrity: sha512-2XZ+U1AyVsOAXeH6WK1syDm7+gwTjA8fShs93WcbxnK7HV+NigDlvr4124CeJLTHyh3fMh1o7+CnQnaBJhlysQ==} engines: {node: '>=10'} cpu: [x64] os: [win32] - '@swc/core@1.7.36': - resolution: {integrity: sha512-bu7ymMX+LCJOSSrKank25Jaq66ymLVA9fOUuy4ck3/6rbXdLw+pIJPnIDKQ9uNcxww8KDxOuJk9Ui9pqR+aGFw==} + '@swc/core@1.9.1': + resolution: {integrity: sha512-OnPc+Kt5oy3xTvr/KCUOqE9ptJcWbyQgAUr1ydh9EmbBcmJTaO1kfQCxm/axzJi6sKeDTxL9rX5zvLOhoYIaQw==} engines: {node: '>=10'} peerDependencies: '@swc/helpers': '*' @@ -566,20 +772,63 @@ packages: '@swc/counter@0.1.3': resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} - '@swc/types@0.1.13': - resolution: {integrity: sha512-JL7eeCk6zWCbiYQg2xQSdLXQJl8Qoc9rXmG2cEKvHe3CKwMHwHGpfOb8frzNLmbycOo6I51qxnLnn9ESf4I20Q==} + '@swc/types@0.1.14': + resolution: {integrity: sha512-PbSmTiYCN+GMrvfjrMo9bdY+f2COnwbdnoMw7rqU/PI5jXpKjxOGZ0qqZCImxnT81NkNsKnmEpvu+hRXLBeCJg==} - '@tsconfig/node10@1.0.11': - resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} + '@tanstack/history@1.61.1': + resolution: {integrity: sha512-2CqERleeqO3hkhJmyJm37tiL3LYgeOpmo8szqdjgtnnG0z7ZpvzkZz6HkfOr9Ca/ha7mhAiouSvLYuLkM37AMg==} + engines: {node: '>=12'} - '@tsconfig/node12@1.0.11': - resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + '@tanstack/react-router@1.81.1': + resolution: {integrity: sha512-2MufdPrN2fwcmf9r82Egl7RUzNN/tlVUz97TphCDX3k5yMslwouKLw481mY26PksiHw1nIYfsAggGTgSELP1xg==} + engines: {node: '>=12'} + peerDependencies: + '@tanstack/router-generator': 1.79.0 + react: '>=18' + react-dom: '>=18' + peerDependenciesMeta: + '@tanstack/router-generator': + optional: true - '@tsconfig/node14@1.0.3': - resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + '@tanstack/react-store@0.5.6': + resolution: {integrity: sha512-SitIpS5jTj28DajjLpWbIX+YetmJL+6PRY0DKKiCGBKfYIqj3ryODQYF3jB3SNoR9ifUA/jFkqbJdBKFtWd+AQ==} + peerDependencies: + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 - '@tsconfig/node16@1.0.4': - resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + '@tanstack/router-devtools@1.81.1': + resolution: {integrity: sha512-gSAqQ6/+fycHxj1Yfsfg5OPZ8KMDlcXh5rb/tHzlOpC+zGtvxQAR6KSes4kmIQ2HD0C094tW9+Nkrfl7/uYmlQ==} + engines: {node: '>=12'} + peerDependencies: + '@tanstack/react-router': ^1.81.1 + react: '>=18' + react-dom: '>=18' + + '@tanstack/router-generator@1.79.0': + resolution: {integrity: sha512-HJxmYs7GAA1AJQzyfy4Hiygmg93qCCDiAxQ//zCRMbzVntwpqtZ96o9UGOPjT3Lw0SxbyzbKgpo3zqCdwlv8Ew==} + engines: {node: '>=12'} + + '@tanstack/router-plugin@1.79.0': + resolution: {integrity: sha512-dY81YyKxON9KhZQlrkkuxsl688pGpZ4HAF5w40ZkJa+nwmEJdg0b2td+MPXWbtmSd1t1cbYlFvc68k+PUSHN/A==} + engines: {node: '>=12'} + peerDependencies: + '@rsbuild/core': '>=1.0.2' + vite: '>=5.0.0' + webpack: '>=5.92.0' + peerDependenciesMeta: + '@rsbuild/core': + optional: true + vite: + optional: true + webpack: + optional: true + + '@tanstack/store@0.5.5': + resolution: {integrity: sha512-EOSrgdDAJExbvRZEQ/Xhh9iZchXpMN+ga1Bnk8Nmygzs8TfiE6hbzThF+Pr2G19uHL6+DTDTHhJ8VQiOd7l4tA==} + + '@tanstack/virtual-file-routes@1.64.0': + resolution: {integrity: sha512-soW+gE9QTmMaqXM17r7y1p8NiQVIIECjdTaYla8BKL5Flj030m3KuxEQoiG1XgjtA0O7ayznFz2YvPcXIy3qDg==} + engines: {node: '>=12'} '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} @@ -599,14 +848,8 @@ packages: '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - '@types/json5@0.0.29': - resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} - - '@types/node@20.16.11': - resolution: {integrity: sha512-y+cTCACu92FyA5fgQSAI8A1H429g7aSK2HsO7K4XYUWc4dY5IUz55JSDIYT6/VsOLfGy8vmvQYC2hfb0iF16Uw==} - - '@types/normalize-package-data@2.4.4': - resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} + '@types/node@22.9.0': + resolution: {integrity: sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==} '@types/prop-types@15.7.13': resolution: {integrity: sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==} @@ -614,14 +857,11 @@ packages: '@types/react-dom@18.3.1': resolution: {integrity: sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==} - '@types/react@18.3.11': - resolution: {integrity: sha512-r6QZ069rFTjrEYgFdOck1gK7FLVsgJE7tTz0pQBczlBNUhBNk0MQH4UbnFSwjpQLMkLzgqvBBa+qGpLje16eTQ==} + '@types/react@18.3.12': + resolution: {integrity: sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==} - '@types/semver@7.5.8': - resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} - - '@typescript-eslint/eslint-plugin@8.9.0': - resolution: {integrity: sha512-Y1n621OCy4m7/vTXNlCbMVp87zSd7NH0L9cXD8aIpOaNlzeWxIK4+Q19A68gSmTNRZn92UjocVUWDthGxtqHFg==} + '@typescript-eslint/eslint-plugin@8.13.0': + resolution: {integrity: sha512-nQtBLiZYMUPkclSeC3id+x4uVd1SGtHuElTxL++SfP47jR0zfkZBJHc+gL4qPsgTuypz0k8Y2GheaDYn6Gy3rg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 @@ -631,14 +871,8 @@ packages: typescript: optional: true - '@typescript-eslint/experimental-utils@5.62.0': - resolution: {integrity: sha512-RTXpeB3eMkpoclG3ZHft6vG/Z30azNHuqY6wKPBHlVMZFuEvrtlEDe8gMqDb+SO+9hjC/pLekeSCryf9vMZlCw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - - '@typescript-eslint/parser@8.9.0': - resolution: {integrity: sha512-U+BLn2rqTTHnc4FL3FJjxaXptTxmf9sNftJK62XLz4+GxG3hLHm/SUNaaXP5Y4uTiuYoL5YLy4JBCJe3+t8awQ==} + '@typescript-eslint/parser@8.13.0': + resolution: {integrity: sha512-w0xp+xGg8u/nONcGw1UXAr6cjCPU1w0XVyBs6Zqaj5eLmxkKQAByTdV/uGgNN5tVvN/kKpoQlP2cL7R+ajZZIQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -647,16 +881,12 @@ packages: typescript: optional: true - '@typescript-eslint/scope-manager@5.62.0': - resolution: {integrity: sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - '@typescript-eslint/scope-manager@8.9.0': - resolution: {integrity: sha512-bZu9bUud9ym1cabmOYH9S6TnbWRzpklVmwqICeOulTCZ9ue2/pczWzQvt/cGj2r2o1RdKoZbuEMalJJSYw3pHQ==} + '@typescript-eslint/scope-manager@8.13.0': + resolution: {integrity: sha512-XsGWww0odcUT0gJoBZ1DeulY1+jkaHUciUq4jKNv4cpInbvvrtDoyBH9rE/n2V29wQJPk8iCH1wipra9BhmiMA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/type-utils@8.9.0': - resolution: {integrity: sha512-JD+/pCqlKqAk5961vxCluK+clkppHY07IbV3vett97KOV+8C6l+CPEPwpUuiMwgbOz/qrN3Ke4zzjqbT+ls+1Q==} + '@typescript-eslint/type-utils@8.13.0': + resolution: {integrity: sha512-Rqnn6xXTR316fP4D2pohZenJnp+NwQ1mo7/JM+J1LWZENSLkJI8ID8QNtlvFeb0HnFSK94D6q0cnMX6SbE5/vA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '*' @@ -664,25 +894,12 @@ packages: typescript: optional: true - '@typescript-eslint/types@5.62.0': - resolution: {integrity: sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - '@typescript-eslint/types@8.9.0': - resolution: {integrity: sha512-SjgkvdYyt1FAPhU9c6FiYCXrldwYYlIQLkuc+LfAhCna6ggp96ACncdtlbn8FmnG72tUkXclrDExOpEYf1nfJQ==} + '@typescript-eslint/types@8.13.0': + resolution: {integrity: sha512-4cyFErJetFLckcThRUFdReWJjVsPCqyBlJTi6IDEpc1GWCIIZRFxVppjWLIMcQhNGhdWJJRYFHpHoDWvMlDzng==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@5.62.0': - resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@typescript-eslint/typescript-estree@8.9.0': - resolution: {integrity: sha512-9iJYTgKLDG6+iqegehc5+EqE6sqaee7kb8vWpmHZ86EqwDjmlqNNHeqDVqb9duh+BY6WCNHfIGvuVU3Tf9Db0g==} + '@typescript-eslint/typescript-estree@8.13.0': + resolution: {integrity: sha512-v7SCIGmVsRK2Cy/LTLGN22uea6SaUIlpBcO/gnMGT/7zPtxp90bphcGf4fyrCQl3ZtiBKqVTG32hb668oIYy1g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '*' @@ -690,66 +907,57 @@ packages: typescript: optional: true - '@typescript-eslint/utils@5.62.0': - resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - - '@typescript-eslint/utils@8.9.0': - resolution: {integrity: sha512-PKgMmaSo/Yg/F7kIZvrgrWa1+Vwn036CdNUvYFEkYbPwOH4i8xvkaRlu148W3vtheWK9ckKRIz7PBP5oUlkrvQ==} + '@typescript-eslint/utils@8.13.0': + resolution: {integrity: sha512-A1EeYOND6Uv250nybnLZapeXpYMl8tkzYUxqmoKAWnI4sei3ihf2XdZVd+vVOmHGcp3t+P7yRrNsyyiXTvShFQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 - '@typescript-eslint/visitor-keys@5.62.0': - resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - '@typescript-eslint/visitor-keys@8.9.0': - resolution: {integrity: sha512-Ht4y38ubk4L5/U8xKUBfKNYGmvKvA1CANoxiTRMM+tOLk3lbF3DvzZCxJCRSE+2GdCMSh6zq9VZJc3asc1XuAA==} + '@typescript-eslint/visitor-keys@8.13.0': + resolution: {integrity: sha512-7N/+lztJqH4Mrf0lb10R/CbI1EaAMMGyF5y0oJvFoAhafwgiRA7TXyd8TFn8FC8k5y2dTsYogg238qavRGNnlw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@ungap/structured-clone@1.2.0': - resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} - - '@vitejs/plugin-react@4.3.2': - resolution: {integrity: sha512-hieu+o05v4glEBucTcKMK3dlES0OeJlD9YVOAPraVMOInBCwzumaIFiUjr4bHK7NPgnAHgiskUoceKercrN8vg==} - engines: {node: ^14.18.0 || >=16.0.0} + '@vitejs/plugin-react-swc@3.7.1': + resolution: {integrity: sha512-vgWOY0i1EROUK0Ctg1hwhtC3SdcDjZcdit4Ups4aPkDcB1jYhmo+RMYWY87cmXMhvtD5uf8lV89j2w16vkdSVg==} peerDependencies: - vite: ^4.2.0 || ^5.0.0 + vite: ^4 || ^5 - '@vitest/expect@1.6.0': - resolution: {integrity: sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==} + '@vitest/expect@2.1.4': + resolution: {integrity: sha512-DOETT0Oh1avie/D/o2sgMHGrzYUFFo3zqESB2Hn70z6QB1HrS2IQ9z5DfyTqU8sg4Bpu13zZe9V4+UTNQlUeQA==} - '@vitest/runner@1.6.0': - resolution: {integrity: sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==} + '@vitest/mocker@2.1.4': + resolution: {integrity: sha512-Ky/O1Lc0QBbutJdW0rqLeFNbuLEyS+mIPiNdlVlp2/yhJ0SbyYqObS5IHdhferJud8MbbwMnexg4jordE5cCoQ==} + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true - '@vitest/snapshot@1.6.0': - resolution: {integrity: sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==} + '@vitest/pretty-format@2.1.4': + resolution: {integrity: sha512-L95zIAkEuTDbUX1IsjRl+vyBSLh3PwLLgKpghl37aCK9Jvw0iP+wKwIFhfjdUtA2myLgjrG6VU6JCFLv8q/3Ww==} - '@vitest/spy@1.6.0': - resolution: {integrity: sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==} + '@vitest/runner@2.1.4': + resolution: {integrity: sha512-sKRautINI9XICAMl2bjxQM8VfCMTB0EbsBc/EDFA57V6UQevEKY/TOPOF5nzcvCALltiLfXWbq4MaAwWx/YxIA==} - '@vitest/utils@1.6.0': - resolution: {integrity: sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==} + '@vitest/snapshot@2.1.4': + resolution: {integrity: sha512-3Kab14fn/5QZRog5BPj6Rs8dc4B+mim27XaKWFWHWA87R56AKjHTGcBFKpvZKDzC4u5Wd0w/qKsUIio3KzWW4Q==} + + '@vitest/spy@2.1.4': + resolution: {integrity: sha512-4JOxa+UAizJgpZfaCPKK2smq9d8mmjZVPMt2kOsg/R8QkoRzydHH1qHxIYNvr1zlEaFj4SXiaaJWxq/LPLKaLg==} + + '@vitest/utils@2.1.4': + resolution: {integrity: sha512-MXDnZn0Awl2S86PSNIim5PWXgIAx8CIkzu35mBdSApUip6RFOGXBCf3YFyeEu8n1IHk4bWD46DeYFu9mQlFIRg==} acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn-walk@8.3.4: - resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} - engines: {node: '>=0.4.0'} - - acorn@7.4.1: - resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==} - engines: {node: '>=0.4.0'} - hasBin: true - - acorn@8.12.1: - resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==} + acorn@8.14.0: + resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} engines: {node: '>=0.4.0'} hasBin: true @@ -764,18 +972,10 @@ packages: resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} engines: {node: '>=12'} - ansi-styles@3.2.1: - resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} - engines: {node: '>=4'} - ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} - ansi-styles@5.2.0: - resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} - engines: {node: '>=10'} - ansi-styles@6.2.1: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} engines: {node: '>=12'} @@ -787,53 +987,15 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} - arg@4.1.3: - resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} - arg@5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - array-buffer-byte-length@1.0.1: - resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} - engines: {node: '>= 0.4'} - - array-includes@3.1.8: - resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} - engines: {node: '>= 0.4'} - - array-union@2.1.0: - resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} - engines: {node: '>=8'} - - array.prototype.findlast@1.2.5: - resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} - engines: {node: '>= 0.4'} - - array.prototype.findlastindex@1.2.5: - resolution: {integrity: sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==} - engines: {node: '>= 0.4'} - - array.prototype.flat@1.3.2: - resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} - engines: {node: '>= 0.4'} - - array.prototype.flatmap@1.3.2: - resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} - engines: {node: '>= 0.4'} - - array.prototype.tosorted@1.1.4: - resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} - engines: {node: '>= 0.4'} - - arraybuffer.prototype.slice@1.0.3: - resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==} - engines: {node: '>= 0.4'} - - assertion-error@1.1.0: - resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} autoprefixer@10.4.20: resolution: {integrity: sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==} @@ -842,9 +1004,8 @@ packages: peerDependencies: postcss: ^8.1.0 - available-typed-arrays@1.0.7: - resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} - engines: {node: '>= 0.4'} + babel-dead-code-elimination@1.0.6: + resolution: {integrity: sha512-JxFi9qyRJpN0LjEbbjbN8g0ux71Qppn9R8Qe3k6QzHg2CaKsbUQtbn307LQGiDLGjV6JCtEFqfxzVig9MyDCHQ==} balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -863,23 +1024,15 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} - browserslist@4.24.0: - resolution: {integrity: sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==} + browserslist@4.24.2: + resolution: {integrity: sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true - builtin-modules@3.3.0: - resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} - engines: {node: '>=6'} - cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} - call-bind@1.0.7: - resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} - engines: {node: '>= 0.4'} - callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -888,46 +1041,40 @@ packages: resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} engines: {node: '>= 6'} - caniuse-lite@1.0.30001668: - resolution: {integrity: sha512-nWLrdxqCdblixUO+27JtGJJE/txpJlyUy5YN1u53wLZkP0emYCo5zgS6QYft7VUYR42LGgi/S5hdLZTrnyIddw==} + caniuse-lite@1.0.30001679: + resolution: {integrity: sha512-j2YqID/YwpLnKzCmBOS4tlZdWprXm3ZmQLBH9ZBXFOhoxLA46fwyBvx6toCBWBmnuwUY/qB3kEU6gFx8qgCroA==} - chai@4.5.0: - resolution: {integrity: sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==} - engines: {node: '>=4'} - - chalk@2.4.2: - resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} - engines: {node: '>=4'} + chai@5.1.2: + resolution: {integrity: sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==} + engines: {node: '>=12'} chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} - check-error@1.0.3: - resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} + check-error@2.1.1: + resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} + engines: {node: '>= 16'} chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} - ci-info@4.0.0: - resolution: {integrity: sha512-TdHqgGf9odd8SXNuxtUBVx8Nv+qZOejE6qyqiy5NtbYYQOeFa6zmHkxlPzmaLxWWHsU6nJmB7AETdVPi+2NBUg==} - engines: {node: '>=8'} + class-variance-authority@0.7.0: + resolution: {integrity: sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==} - clean-regexp@1.0.0: - resolution: {integrity: sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==} - engines: {node: '>=4'} + clsx@2.0.0: + resolution: {integrity: sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==} + engines: {node: '>=6'} - color-convert@1.9.3: - resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} - color-name@1.1.3: - resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} - color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} @@ -938,20 +1085,11 @@ packages: concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - confbox@0.1.8: - resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} - convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - core-js-compat@3.38.1: - resolution: {integrity: sha512-JRH6gfXxGmrzF3tZ57lFx97YARxCXPaMzPo6jELZhv88pBH5VXpQ+y0znKGlFnzuaihqhLbefxSJxWJMPtfDzw==} - - create-require@1.1.1: - resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} - - cross-spawn@7.0.3: - resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + cross-spawn@7.0.5: + resolution: {integrity: sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==} engines: {node: '>= 8'} cssesc@3.0.0: @@ -962,26 +1100,6 @@ packages: csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} - data-view-buffer@1.0.1: - resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==} - engines: {node: '>= 0.4'} - - data-view-byte-length@1.0.1: - resolution: {integrity: sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==} - engines: {node: '>= 0.4'} - - data-view-byte-offset@1.0.0: - resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==} - engines: {node: '>= 0.4'} - - debug@3.2.7: - resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - debug@4.3.7: resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} engines: {node: '>=6.0'} @@ -991,52 +1109,24 @@ packages: supports-color: optional: true - deep-eql@4.1.4: - resolution: {integrity: sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==} + deep-eql@5.0.2: + resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} engines: {node: '>=6'} deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - define-data-property@1.1.4: - resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} - engines: {node: '>= 0.4'} - - define-properties@1.2.1: - resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} - engines: {node: '>= 0.4'} - didyoumean@1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} - diff-sequences@29.6.3: - resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - diff@4.0.2: - resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} - engines: {node: '>=0.3.1'} - - dir-glob@3.0.1: - resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} - engines: {node: '>=8'} - dlv@1.1.3: resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} - doctrine@2.1.0: - resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} - engines: {node: '>=0.10.0'} - - doctrine@3.0.0: - resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} - engines: {node: '>=6.0.0'} - eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - electron-to-chromium@1.5.39: - resolution: {integrity: sha512-4xkpSR6CjuiaNyvwiWDI85N9AxsvbPawB8xc7yzLPonYTuP19BVgYweKyUMFtHEZgIcHWMt1ks5Cqx2m+6/Grg==} + electron-to-chromium@1.5.55: + resolution: {integrity: sha512-6maZ2ASDOTBtjt9FhqYPRnbvKU5tjG0IN9SztUOWYw2AzNDNpKJYLJmlK0/En4Hs/aiWnB+JZ+gW19PIGszgKg==} emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -1044,191 +1134,60 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - enhanced-resolve@5.17.1: - resolution: {integrity: sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==} - engines: {node: '>=10.13.0'} - - error-ex@1.3.2: - resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} - - es-abstract@1.23.3: - resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==} - engines: {node: '>= 0.4'} - - es-define-property@1.0.0: - resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} - engines: {node: '>= 0.4'} - - es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} - - es-iterator-helpers@1.1.0: - resolution: {integrity: sha512-/SurEfycdyssORP/E+bj4sEu1CWw4EmLDsHynHwSXQ7utgbrMRWW195pTrCjFgFCddf/UkYm3oqKPRq5i8bJbw==} - engines: {node: '>= 0.4'} - - es-object-atoms@1.0.0: - resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} - engines: {node: '>= 0.4'} - - es-set-tostringtag@2.0.3: - resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==} - engines: {node: '>= 0.4'} - - es-shim-unscopables@1.0.2: - resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} - - es-to-primitive@1.2.1: - resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} - engines: {node: '>= 0.4'} - esbuild@0.21.5: resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} engines: {node: '>=12'} hasBin: true + esbuild@0.23.1: + resolution: {integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==} + engines: {node: '>=18'} + hasBin: true + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} - escape-string-regexp@1.0.5: - resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} - engines: {node: '>=0.8.0'} - escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} - eslint-import-resolver-node@0.3.9: - resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} - - eslint-import-resolver-typescript@3.6.3: - resolution: {integrity: sha512-ud9aw4szY9cCT1EWWdGv1L1XR6hh2PaRWif0j2QjQ0pgTY/69iw+W0Z4qZv5wHahOl8isEr+k/JnyAqNQkLkIA==} - engines: {node: ^14.18.0 || >=16.0.0} - peerDependencies: - eslint: '*' - eslint-plugin-import: '*' - eslint-plugin-import-x: '*' - peerDependenciesMeta: - eslint-plugin-import: - optional: true - eslint-plugin-import-x: - optional: true - - eslint-module-utils@2.12.0: - resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: '*' - eslint-import-resolver-node: '*' - eslint-import-resolver-typescript: '*' - eslint-import-resolver-webpack: '*' - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - eslint: - optional: true - eslint-import-resolver-node: - optional: true - eslint-import-resolver-typescript: - optional: true - eslint-import-resolver-webpack: - optional: true - - eslint-plugin-import@2.31.0: - resolution: {integrity: sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - - eslint-plugin-no-only-tests@3.3.0: - resolution: {integrity: sha512-brcKcxGnISN2CcVhXJ/kEQlNa0MEfGRtwKtWA16SkqXHKitaKIMrfemJKLKX1YqDU5C/5JY3PvZXd5jEW04e0Q==} - engines: {node: '>=5.0.0'} - - eslint-plugin-react-hooks@4.6.2: - resolution: {integrity: sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==} + eslint-plugin-react-hooks@5.0.0: + resolution: {integrity: sha512-hIOwI+5hYGpJEc4uPRmz2ulCjAGD/N13Lukkh8cLV0i2IRk/bdZDYjgLVHj+U9Z704kLIdIO6iueGvxNur0sgw==} engines: {node: '>=10'} peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 - eslint-plugin-react@7.37.1: - resolution: {integrity: sha512-xwTnwDqzbDRA8uJ7BMxPs/EXRB3i8ZfnOIp8BsxEQkT0nHPp+WWceqGgo6rKb9ctNi8GJLDT4Go5HAWELa/WMg==} - engines: {node: '>=4'} + eslint-plugin-react-refresh@0.4.14: + resolution: {integrity: sha512-aXvzCTK7ZBv1e7fahFuR3Z/fyQQSIQ711yPgYRj+Oj64tyTgO4iQIDmYXDBqvSWQ/FA4OSCsXOStlF+noU0/NA==} peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 + eslint: '>=7' - eslint-plugin-sort-destructure-keys@2.0.0: - resolution: {integrity: sha512-4w1UQCa3o/YdfWaLr9jY8LfGowwjwjmwClyFLxIsToiyIdZMq3x9Ti44nDn34DtTPP7PWg96tUONKVmATKhYGQ==} - engines: {node: '>=12'} - peerDependencies: - eslint: 5 - 9 - - eslint-plugin-sort-keys-fix@1.1.2: - resolution: {integrity: sha512-DNPHFGCA0/hZIsfODbeLZqaGY/+q3vgtshF85r+YWDNCQ2apd9PNs/zL6ttKm0nD1IFwvxyg3YOTI7FHl4unrw==} - engines: {node: '>=0.10.0'} - - eslint-plugin-typescript-sort-keys@3.3.0: - resolution: {integrity: sha512-bRW3Rc/VNdrSP9OoY5wgjjaXCOOkZKpzvl/Mk6l8Sg8CMehVIcg9K4y33l+ZcZiknpl0aR6rKusxuCJNGZWmVw==} - engines: {node: '>= 16'} - peerDependencies: - '@typescript-eslint/parser': '>=6' - eslint: ^7 || ^8 - typescript: ^3 || ^4 || ^5 - - eslint-plugin-unicorn@55.0.0: - resolution: {integrity: sha512-n3AKiVpY2/uDcGrS3+QsYDkjPfaOrNrsfQxU9nt5nitd9KuvVXrfAvgCO9DYPSfap+Gqjw9EOrXIsBp5tlHZjA==} - engines: {node: '>=18.18'} - peerDependencies: - eslint: '>=8.56.0' - - eslint-plugin-unused-imports@4.0.1: - resolution: {integrity: sha512-rax76s05z64uQgG9YXsWFmXrgjkaK79AvfeAWiSxhPP6RVGxeRaj4+2u+wxxu/mDy2pmJoOy1QTOEALMia2xGQ==} + eslint-scope@8.2.0: + resolution: {integrity: sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - '@typescript-eslint/eslint-plugin': ^8.0.0-0 - eslint: ^9.0.0 - peerDependenciesMeta: - '@typescript-eslint/eslint-plugin': - optional: true - - eslint-rule-composer@0.3.0: - resolution: {integrity: sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==} - engines: {node: '>=4.0.0'} - - eslint-scope@5.1.1: - resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} - engines: {node: '>=8.0.0'} - - eslint-scope@7.2.2: - resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - eslint-visitor-keys@1.3.0: - resolution: {integrity: sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==} - engines: {node: '>=4'} eslint-visitor-keys@3.4.3: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - eslint@8.57.1: - resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. + eslint-visitor-keys@4.2.0: + resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint@9.14.0: + resolution: {integrity: sha512-c2FHsVBr87lnUtjP4Yhvk4yEhKrQavGafRA/Se1ouse8PfbfC/Qh9Mxa00yWsZRlqeUB9raXip0aiiUZkgnr9g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true - espree@6.2.1: - resolution: {integrity: sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==} - engines: {node: '>=6.0.0'} - - espree@9.6.1: - resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + espree@10.3.0: + resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} esquery@1.6.0: resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} @@ -1238,10 +1197,6 @@ packages: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} engines: {node: '>=4.0'} - estraverse@4.3.0: - resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} - engines: {node: '>=4.0'} - estraverse@5.3.0: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} @@ -1253,9 +1208,9 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} - execa@8.0.1: - resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} - engines: {node: '>=16.17'} + expect-type@1.1.0: + resolution: {integrity: sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==} + engines: {node: '>=12.0.0'} fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -1273,32 +1228,25 @@ packages: fastq@1.17.1: resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} - file-entry-cache@6.0.1: - resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} - engines: {node: ^10.12.0 || >=12.0.0} + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} - find-up@4.1.0: - resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} - engines: {node: '>=8'} - find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} - flat-cache@3.2.0: - resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} - engines: {node: ^10.12.0 || >=12.0.0} + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} flatted@3.3.1: resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} - for-each@0.3.3: - resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} - foreground-child@3.3.0: resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} engines: {node: '>=14'} @@ -1306,9 +1254,6 @@ packages: fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} - fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -1317,32 +1262,10 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - function.prototype.name@1.1.6: - resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} - engines: {node: '>= 0.4'} - - functions-have-names@1.2.3: - resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} - gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} - get-func-name@2.0.2: - resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} - - get-intrinsic@1.2.4: - resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} - engines: {node: '>= 0.4'} - - get-stream@8.0.1: - resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} - engines: {node: '>=16'} - - get-symbol-description@1.0.2: - resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} - engines: {node: '>= 0.4'} - get-tsconfig@4.8.1: resolution: {integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==} @@ -1358,76 +1281,34 @@ packages: resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} hasBin: true - glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported - globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} - globals@13.24.0: - resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} - engines: {node: '>=8'} - - globals@15.11.0: - resolution: {integrity: sha512-yeyNSjdbyVaWurlwCpcA6XNBrHTMIeDdj0/hnvX/OLJ9ekOXYbLsLinH/MucQyGvNnXhidTdNhTtJaffL2sMfw==} + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} - globalthis@1.0.4: - resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} - engines: {node: '>= 0.4'} + globals@15.12.0: + resolution: {integrity: sha512-1+gLErljJFhbOVyaetcwJiJ4+eLe45S2E7P5UiZ9xGfeq3ATQf5DOv9G7MH3gGbKQLkzmNh2DxfZwLdw+j6oTQ==} + engines: {node: '>=18'} - globby@11.1.0: - resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} - engines: {node: '>=10'} - - gopd@1.0.1: - resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} - - graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + goober@2.1.16: + resolution: {integrity: sha512-erjk19y1U33+XAMe1VTvIONHYoSqE4iS7BYUZfHaqeohLmnC0FdxEh7rQU+6MZ4OajItzjZFSRtVANrQwNq6/g==} + peerDependencies: + csstype: ^3.0.10 graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - has-bigints@1.0.2: - resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} - - has-flag@3.0.0: - resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} - engines: {node: '>=4'} - has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} - has-property-descriptors@1.0.2: - resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} - - has-proto@1.0.3: - resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} - engines: {node: '>= 0.4'} - - has-symbols@1.0.3: - resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} - engines: {node: '>= 0.4'} - - has-tostringtag@1.0.2: - resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} - engines: {node: '>= 0.4'} - hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} - hosted-git-info@2.8.9: - resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} - - human-signals@5.0.0: - resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} - engines: {node: '>=16.17.0'} - ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -1440,154 +1321,33 @@ packages: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} - indent-string@4.0.0: - resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} - engines: {node: '>=8'} - - inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. - - inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - - internal-slot@1.0.7: - resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} - engines: {node: '>= 0.4'} - - is-array-buffer@3.0.4: - resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} - engines: {node: '>= 0.4'} - - is-arrayish@0.2.1: - resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - - is-async-function@2.0.0: - resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} - engines: {node: '>= 0.4'} - - is-bigint@1.0.4: - resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} - is-binary-path@2.1.0: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} - is-boolean-object@1.1.2: - resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} - engines: {node: '>= 0.4'} - - is-builtin-module@3.2.1: - resolution: {integrity: sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==} - engines: {node: '>=6'} - - is-bun-module@1.2.1: - resolution: {integrity: sha512-AmidtEM6D6NmUiLOvvU7+IePxjEjOzra2h0pSrsfSAcXwl/83zLLXDByafUJy9k/rKK0pvXMLdwKwGHlX2Ke6Q==} - - is-callable@1.2.7: - resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} - engines: {node: '>= 0.4'} - is-core-module@2.15.1: resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} engines: {node: '>= 0.4'} - is-data-view@1.0.1: - resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==} - engines: {node: '>= 0.4'} - - is-date-object@1.0.5: - resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} - engines: {node: '>= 0.4'} - is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} - is-finalizationregistry@1.0.2: - resolution: {integrity: sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==} - is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} - is-generator-function@1.0.10: - resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} - engines: {node: '>= 0.4'} - is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} - is-map@2.0.3: - resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} - engines: {node: '>= 0.4'} - - is-negative-zero@2.0.3: - resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} - engines: {node: '>= 0.4'} - - is-number-object@1.0.7: - resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} - engines: {node: '>= 0.4'} - is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} - is-path-inside@3.0.3: - resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} - engines: {node: '>=8'} - - is-regex@1.1.4: - resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} - engines: {node: '>= 0.4'} - - is-set@2.0.3: - resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} - engines: {node: '>= 0.4'} - - is-shared-array-buffer@1.0.3: - resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==} - engines: {node: '>= 0.4'} - - is-stream@3.0.0: - resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - is-string@1.0.7: - resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} - engines: {node: '>= 0.4'} - - is-symbol@1.0.4: - resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} - engines: {node: '>= 0.4'} - - is-typed-array@1.1.13: - resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} - engines: {node: '>= 0.4'} - - is-weakmap@2.0.2: - resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} - engines: {node: '>= 0.4'} - - is-weakref@1.0.2: - resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} - - is-weakset@2.0.3: - resolution: {integrity: sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==} - engines: {node: '>= 0.4'} - - isarray@2.0.5: - resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} - isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - iterator.prototype@1.1.3: - resolution: {integrity: sha512-FW5iMbeQ6rBGm/oKgzq2aW4KvAGpxPzYES8N4g4xNXUKpL1mclMvOe+76AcLDTvD+Ze+sOpVhgdAQEKF4L9iGQ==} - engines: {node: '>= 0.4'} - jackspeak@3.4.3: resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} @@ -1598,17 +1358,10 @@ packages: js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - js-tokens@9.0.0: - resolution: {integrity: sha512-WriZw1luRMlmV3LGJaR6QOJjWwgLUTf89OwT2lUOyjX2dJGBwgmIkbcz+7WFZjrZM635JOIR517++e/67CP9dQ==} - js-yaml@4.1.0: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true - jsesc@0.5.0: - resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==} - hasBin: true - jsesc@3.0.2: resolution: {integrity: sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==} engines: {node: '>=6'} @@ -1617,35 +1370,17 @@ packages: json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - json-parse-even-better-errors@2.3.1: - resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - - json-parse-even-better-errors@3.0.2: - resolution: {integrity: sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - json-schema@0.4.0: - resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} - json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - json5@1.0.2: - resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} - hasBin: true - json5@2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} hasBin: true - jsx-ast-utils@3.3.5: - resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} - engines: {node: '>=4.0'} - keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} @@ -1664,14 +1399,6 @@ packages: lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - local-pkg@0.5.0: - resolution: {integrity: sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==} - engines: {node: '>=14'} - - locate-path@5.0.0: - resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} - engines: {node: '>=8'} - locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} @@ -1683,8 +1410,8 @@ packages: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true - loupe@2.3.7: - resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} + loupe@3.1.2: + resolution: {integrity: sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==} lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} @@ -1692,19 +1419,14 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + lucide-react@0.456.0: + resolution: {integrity: sha512-DIIGJqTT5X05sbAsQ+OhA8OtJYyD4NsEMCA/HQW/Y6ToPQ7gwbtujIoeAaup4HpHzV35SQOarKAWH8LYglB6eA==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc + magic-string@0.30.12: resolution: {integrity: sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==} - make-error@1.3.6: - resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} - - memorystream@0.3.1: - resolution: {integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==} - engines: {node: '>= 0.10.0'} - - merge-stream@2.0.0: - resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} - merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} @@ -1713,14 +1435,6 @@ packages: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} - mimic-fn@4.0.0: - resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} - engines: {node: '>=12'} - - min-indent@1.0.1: - resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} - engines: {node: '>=4'} - minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -1728,16 +1442,10 @@ packages: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} - minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - minipass@7.1.2: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} - mlly@1.7.2: - resolution: {integrity: sha512-tN3dvVHYVz4DhSXinXIk7u9syPYaJvio118uomkovAtWBT+RdbP6Lfh/5Lvo519YMmwBafwlh20IPTXIStscpA==} - ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -1749,18 +1457,12 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - natural-compare-lite@1.4.0: - resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} - natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} node-releases@2.0.18: resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==} - normalize-package-data@2.5.0: - resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} - normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -1769,19 +1471,6 @@ packages: resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} engines: {node: '>=0.10.0'} - npm-normalize-package-bin@3.0.1: - resolution: {integrity: sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - - npm-run-all2@6.2.3: - resolution: {integrity: sha512-5RsxC7jEc/RjxOYBVdEfrJf5FsJ0pHA7jr2/OxrThXknajETCTYjigOCG3iaGjdYIKEQlDuCG0ir0T1HTva8pg==} - engines: {node: ^14.18.0 || ^16.13.0 || >=18.0.0, npm: '>= 8'} - hasBin: true - - npm-run-path@5.3.0: - resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -1790,69 +1479,18 @@ packages: resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} engines: {node: '>= 6'} - object-inspect@1.13.2: - resolution: {integrity: sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==} - engines: {node: '>= 0.4'} - - object-keys@1.1.1: - resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} - engines: {node: '>= 0.4'} - - object.assign@4.1.5: - resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} - engines: {node: '>= 0.4'} - - object.entries@1.1.8: - resolution: {integrity: sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==} - engines: {node: '>= 0.4'} - - object.fromentries@2.0.8: - resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} - engines: {node: '>= 0.4'} - - object.groupby@1.0.3: - resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} - engines: {node: '>= 0.4'} - - object.values@1.2.0: - resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==} - engines: {node: '>= 0.4'} - - once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - - onetime@6.0.0: - resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} - engines: {node: '>=12'} - optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} - p-limit@2.3.0: - resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} - engines: {node: '>=6'} - p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} - p-limit@5.0.0: - resolution: {integrity: sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==} - engines: {node: '>=18'} - - p-locate@4.1.0: - resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} - engines: {node: '>=8'} - p-locate@5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} - p-try@2.2.0: - resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} - engines: {node: '>=6'} - package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} @@ -1860,26 +1498,14 @@ packages: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} - parse-json@5.2.0: - resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} - engines: {node: '>=8'} - path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} - path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} - path-key@4.0.0: - resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} - engines: {node: '>=12'} - path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} @@ -1887,28 +1513,20 @@ packages: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} - path-type@4.0.0: - resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} - engines: {node: '>=8'} - pathe@1.1.2: resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} - pathval@1.1.1: - resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} + pathval@2.0.0: + resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==} + engines: {node: '>= 14.16'} - picocolors@1.1.0: - resolution: {integrity: sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==} + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} - pidtree@0.6.0: - resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==} - engines: {node: '>=0.10'} - hasBin: true - pify@2.3.0: resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} engines: {node: '>=0.10.0'} @@ -1917,17 +1535,6 @@ packages: resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} engines: {node: '>= 6'} - pkg-types@1.2.1: - resolution: {integrity: sha512-sQoqa8alT3nHjGuTjuKgOnvjo4cljkufdtLMnO2LBP/wRwuDlo1tkaEdMxCRhyGRPacv/ztlZgDPm2b7FAmEvw==} - - pluralize@8.0.0: - resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} - engines: {node: '>=4'} - - possible-typed-array-names@1.0.0: - resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} - engines: {node: '>= 0.4'} - postcss-import@15.1.0: resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} engines: {node: '>=14.0.0'} @@ -1973,73 +1580,11 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - prettier-plugin-tailwindcss@0.6.8: - resolution: {integrity: sha512-dGu3kdm7SXPkiW4nzeWKCl3uoImdd5CTZEJGxyypEPL37Wj0HT2pLqjrvSei1nTeuQfO4PUfjeW5cTUNRLZ4sA==} - engines: {node: '>=14.21.3'} - peerDependencies: - '@ianvs/prettier-plugin-sort-imports': '*' - '@prettier/plugin-pug': '*' - '@shopify/prettier-plugin-liquid': '*' - '@trivago/prettier-plugin-sort-imports': '*' - '@zackad/prettier-plugin-twig-melody': '*' - prettier: ^3.0 - prettier-plugin-astro: '*' - prettier-plugin-css-order: '*' - prettier-plugin-import-sort: '*' - prettier-plugin-jsdoc: '*' - prettier-plugin-marko: '*' - prettier-plugin-multiline-arrays: '*' - prettier-plugin-organize-attributes: '*' - prettier-plugin-organize-imports: '*' - prettier-plugin-sort-imports: '*' - prettier-plugin-style-order: '*' - prettier-plugin-svelte: '*' - peerDependenciesMeta: - '@ianvs/prettier-plugin-sort-imports': - optional: true - '@prettier/plugin-pug': - optional: true - '@shopify/prettier-plugin-liquid': - optional: true - '@trivago/prettier-plugin-sort-imports': - optional: true - '@zackad/prettier-plugin-twig-melody': - optional: true - prettier-plugin-astro: - optional: true - prettier-plugin-css-order: - optional: true - prettier-plugin-import-sort: - optional: true - prettier-plugin-jsdoc: - optional: true - prettier-plugin-marko: - optional: true - prettier-plugin-multiline-arrays: - optional: true - prettier-plugin-organize-attributes: - optional: true - prettier-plugin-organize-imports: - optional: true - prettier-plugin-sort-imports: - optional: true - prettier-plugin-style-order: - optional: true - prettier-plugin-svelte: - optional: true - prettier@3.3.3: resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==} engines: {node: '>=14'} hasBin: true - pretty-format@29.7.0: - resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - prop-types@15.8.1: - resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} - punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -2052,16 +1597,6 @@ packages: peerDependencies: react: ^18.3.1 - react-is@16.13.1: - resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} - - react-is@18.3.1: - resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} - - react-refresh@0.14.2: - resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} - engines: {node: '>=0.10.0'} - react@18.3.1: resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} @@ -2069,42 +1604,10 @@ packages: read-cache@1.0.0: resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} - read-package-json-fast@3.0.2: - resolution: {integrity: sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - - read-pkg-up@7.0.1: - resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} - engines: {node: '>=8'} - - read-pkg@5.2.0: - resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==} - engines: {node: '>=8'} - readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} - reflect.getprototypeof@1.0.6: - resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==} - engines: {node: '>= 0.4'} - - regexp-tree@0.1.27: - resolution: {integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==} - hasBin: true - - regexp.prototype.flags@1.5.3: - resolution: {integrity: sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==} - engines: {node: '>= 0.4'} - - regjsparser@0.10.0: - resolution: {integrity: sha512-qx+xQGZVsy55CH0a1hiVwHmqjLryfh7wQyF5HO07XJ9f7dQMY/gPQHhlyDkIzJKC+x2fUCpCcUODUUUFrm7SHA==} - hasBin: true - - requireindex@1.2.0: - resolution: {integrity: sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==} - engines: {node: '>=0.10.5'} - resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -2116,42 +1619,21 @@ packages: resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true - resolve@2.0.0-next.5: - resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} - hasBin: true - reusify@1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - deprecated: Rimraf versions prior to v4 are no longer supported - hasBin: true - - rollup@4.24.0: - resolution: {integrity: sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==} + rollup@4.25.0: + resolution: {integrity: sha512-uVbClXmR6wvx5R1M3Od4utyLUxrmOcEm3pAtMphn73Apq19PDtHpgZoEvqH2YnnaNUuvKmg2DgRd2Sqv+odyqg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - safe-array-concat@1.1.2: - resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} - engines: {node: '>=0.4'} - - safe-regex-test@1.0.3: - resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} - engines: {node: '>= 0.4'} - scheduler@0.23.2: resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} - semver@5.7.2: - resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} - hasBin: true - semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true @@ -2161,14 +1643,6 @@ packages: engines: {node: '>=10'} hasBin: true - set-function-length@1.2.2: - resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} - engines: {node: '>= 0.4'} - - set-function-name@2.0.2: - resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} - engines: {node: '>= 0.4'} - shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -2177,13 +1651,6 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - shell-quote@1.8.1: - resolution: {integrity: sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==} - - side-channel@1.0.6: - resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} - engines: {node: '>= 0.4'} - siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} @@ -2191,31 +1658,15 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} - slash@3.0.0: - resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} - engines: {node: '>=8'} - source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} - spdx-correct@3.2.0: - resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} - - spdx-exceptions@2.5.0: - resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} - - spdx-expression-parse@3.0.1: - resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} - - spdx-license-ids@3.0.20: - resolution: {integrity: sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw==} - stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - std-env@3.7.0: - resolution: {integrity: sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==} + std-env@3.8.0: + resolution: {integrity: sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==} string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} @@ -2225,24 +1676,6 @@ packages: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} engines: {node: '>=12'} - string.prototype.matchall@4.0.11: - resolution: {integrity: sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==} - engines: {node: '>= 0.4'} - - string.prototype.repeat@1.0.0: - resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} - - string.prototype.trim@1.2.9: - resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==} - engines: {node: '>= 0.4'} - - string.prototype.trimend@1.0.8: - resolution: {integrity: sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==} - - string.prototype.trimstart@1.0.8: - resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} - engines: {node: '>= 0.4'} - strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -2251,34 +1684,15 @@ packages: resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} engines: {node: '>=12'} - strip-bom@3.0.0: - resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} - engines: {node: '>=4'} - - strip-final-newline@3.0.0: - resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} - engines: {node: '>=12'} - - strip-indent@3.0.0: - resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} - engines: {node: '>=8'} - strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} - strip-literal@2.1.0: - resolution: {integrity: sha512-Op+UycaUt/8FbN/Z2TWPBLge3jWrP3xj10f3fnYxf052bKuS3EKs1ZQcVGjnEMdsNVAM+plXRdmjrZ/KgG3Skw==} - sucrase@3.35.0: resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} engines: {node: '>=16 || 14 >=14.17'} hasBin: true - supports-color@5.5.0: - resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} - engines: {node: '>=4'} - supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -2287,15 +1701,19 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + tailwind-merge@2.5.4: + resolution: {integrity: sha512-0q8cfZHMu9nuYP/b5Shb7Y7Sh1B7Nnl5GqNr1U+n2p6+mybvRtayrQ+0042Z5byvTA8ihjlP8Odo8/VnHbZu4Q==} + + tailwindcss-animate@1.0.7: + resolution: {integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==} + peerDependencies: + tailwindcss: '>=3.0.0 || insiders' + tailwindcss@3.4.14: resolution: {integrity: sha512-IcSvOcTRcUtQQ7ILQL5quRDg7Xs93PdJEk1ZLbhhvJc7uj/OAhYOnruEiwnGgBvUtaUAJ8/mhSw1o8L2jCiENA==} engines: {node: '>=14.0.0'} hasBin: true - tapable@2.2.1: - resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} - engines: {node: '>=6'} - text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} @@ -2306,27 +1724,40 @@ packages: thenify@3.3.1: resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + tiny-invariant@1.3.3: + resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} + + tiny-warning@1.0.3: + resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==} + tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - tinypool@0.8.4: - resolution: {integrity: sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==} + tinyexec@0.3.1: + resolution: {integrity: sha512-WiCJLEECkO18gwqIp6+hJg0//p23HXp4S+gGtAKu3mI2F2/sXC4FvHvXvB0zJVVaTPhx1/tOwdbRsa1sOBIKqQ==} + + tinypool@1.0.1: + resolution: {integrity: sha512-URZYihUbRPcGv95En+sz6MfghfIc2OJ1sv/RmhWZLouPY0/8Vo80viwPvg3dlaS9fuq7fQMEfgRRK7BBZThBEA==} + engines: {node: ^18.0.0 || >=20.0.0} + + tinyrainbow@1.2.0: + resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==} engines: {node: '>=14.0.0'} - tinyspy@2.2.1: - resolution: {integrity: sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==} + tinyspy@3.0.2: + resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} engines: {node: '>=14.0.0'} - to-fast-properties@2.0.0: - resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} - engines: {node: '>=4'} - to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} - ts-api-utils@1.3.0: - resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} + true-myth@8.0.1: + resolution: {integrity: sha512-/6Tga43I+LfMJmg7hiCGI8KqjjlDEa1XJnWTZOKmmyQ9s7Kv4WPmpoQT/LST0Q98GAnsB+UPtGFwVHi8h7+qFw==} + engines: {node: 18.* || >= 20.*} + + ts-api-utils@1.4.0: + resolution: {integrity: sha512-032cPxaEKwM+GT3vA5JXNzIaizx388rhsSW79vGRNGXfRRAdEAn2mvk36PvK5HnOchyWZ7afLEXqYCvPCrzuzQ==} engines: {node: '>=16'} peerDependencies: typescript: '>=4.2.0' @@ -2334,82 +1765,41 @@ packages: ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} - ts-node@10.9.2: - resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} + tsx@4.19.2: + resolution: {integrity: sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g==} + engines: {node: '>=18.0.0'} hasBin: true - peerDependencies: - '@swc/core': '>=1.2.50' - '@swc/wasm': '>=1.2.50' - '@types/node': '*' - typescript: '>=2.7' - peerDependenciesMeta: - '@swc/core': - optional: true - '@swc/wasm': - optional: true - - tsconfig-paths@3.15.0: - resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} - - tslib@1.14.1: - resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} - - tsutils@3.21.0: - resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} - engines: {node: '>= 6'} - peerDependencies: - typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} - type-detect@4.1.0: - resolution: {integrity: sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==} - engines: {node: '>=4'} - - type-fest@0.20.2: - resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} - engines: {node: '>=10'} - - type-fest@0.6.0: - resolution: {integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==} - engines: {node: '>=8'} - - type-fest@0.8.1: - resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} - engines: {node: '>=8'} - - typed-array-buffer@1.0.2: - resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} - engines: {node: '>= 0.4'} - - typed-array-byte-length@1.0.1: - resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==} - engines: {node: '>= 0.4'} - - typed-array-byte-offset@1.0.2: - resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==} - engines: {node: '>= 0.4'} - - typed-array-length@1.0.6: - resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==} - engines: {node: '>= 0.4'} + typescript-eslint@8.13.0: + resolution: {integrity: sha512-vIMpDRJrQd70au2G8w34mPps0ezFSPMEX4pXkTzUkrNbRX+36ais2ksGWN0esZL+ZMaFJEneOBHzCgSqle7DHw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true typescript@5.6.3: resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} engines: {node: '>=14.17'} hasBin: true - ufo@1.5.4: - resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==} - - unbox-primitive@1.0.2: - resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} - undici-types@6.19.8: resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} + unplugin@1.15.0: + resolution: {integrity: sha512-jTPIs63W+DUEDW207ztbaoO7cQ4p5aVaB823LSlxpsFEU3Mykwxf3ZGC/wzxFJeZlASZYgVrWeo7LgOrqJZ8RA==} + engines: {node: '>=14.0.0'} + peerDependencies: + webpack-sources: ^3 + peerDependenciesMeta: + webpack-sources: + optional: true + update-browserslist-db@1.1.1: resolution: {integrity: sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==} hasBin: true @@ -2419,22 +1809,21 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + use-sync-external-store@1.2.2: + resolution: {integrity: sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - v8-compile-cache-lib@3.0.1: - resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} - - validate-npm-package-license@3.0.4: - resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} - - vite-node@1.6.0: - resolution: {integrity: sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==} + vite-node@2.1.4: + resolution: {integrity: sha512-kqa9v+oi4HwkG6g8ufRnb5AeplcRw8jUF6/7/Qz1qRQOXHImG8YnLbB+LLszENwFnoBl9xIf9nVdCFzNd7GQEg==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true - vite@5.4.9: - resolution: {integrity: sha512-20OVpJHh0PAM0oSOELa5GaZNWeDjcAvQjGXy2Uyr+Tp+/D2/Hdz6NLgpJLsarPTA2QJ6v8mX2P1ZfbsSKvdMkg==} + vite@5.4.10: + resolution: {integrity: sha512-1hvaPshuPUtxeQ0hsVH3Mud0ZanOLwVTneA1EgbAM5LhaZEqyPWGRQ7BtaMvUrTDeEaC8pxtj6a6jku3x4z6SQ==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: @@ -2464,15 +1853,15 @@ packages: terser: optional: true - vitest@1.6.0: - resolution: {integrity: sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA==} + vitest@2.1.4: + resolution: {integrity: sha512-eDjxbVAJw1UJJCHr5xr/xM86Zx+YxIEXGAR+bmnEID7z9qWfoxpHw0zdobz+TQAFOLT+nEXz3+gx6nUJ7RgmlQ==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@types/node': ^18.0.0 || >=20.0.0 - '@vitest/browser': 1.6.0 - '@vitest/ui': 1.6.0 + '@vitest/browser': 2.1.4 + '@vitest/ui': 2.1.4 happy-dom: '*' jsdom: '*' peerDependenciesMeta: @@ -2489,20 +1878,8 @@ packages: jsdom: optional: true - which-boxed-primitive@1.0.2: - resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} - - which-builtin-type@1.1.4: - resolution: {integrity: sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w==} - engines: {node: '>= 0.4'} - - which-collection@1.0.2: - resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} - engines: {node: '>= 0.4'} - - which-typed-array@1.1.15: - resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} - engines: {node: '>= 0.4'} + webpack-virtual-modules@0.6.2: + resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} @@ -2526,9 +1903,6 @@ packages: resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} engines: {node: '>=12'} - wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} @@ -2537,17 +1911,30 @@ packages: engines: {node: '>= 14'} hasBin: true - yn@3.1.1: - resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} - engines: {node: '>=6'} - yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - yocto-queue@1.1.1: - resolution: {integrity: sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==} - engines: {node: '>=12.20'} + zod@3.23.8: + resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==} + + zustand@5.0.1: + resolution: {integrity: sha512-pRET7Lao2z+n5R/HduXMio35TncTlSW68WsYBq2Lg1ASspsNGjpwLAsij3RpouyV6+kHMwwwzP0bZPD70/Jx/w==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=18.0.0' + immer: '>=9.0.6' + react: '>=18.0.0' + use-sync-external-store: '>=1.2.0' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + use-sync-external-store: + optional: true snapshots: @@ -2558,25 +1945,26 @@ snapshots: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 - '@babel/code-frame@7.25.7': + '@babel/code-frame@7.26.2': dependencies: - '@babel/highlight': 7.25.7 - picocolors: 1.1.0 + '@babel/helper-validator-identifier': 7.25.9 + js-tokens: 4.0.0 + picocolors: 1.1.1 - '@babel/compat-data@7.25.8': {} + '@babel/compat-data@7.26.2': {} - '@babel/core@7.25.8': + '@babel/core@7.26.0': dependencies: '@ampproject/remapping': 2.3.0 - '@babel/code-frame': 7.25.7 - '@babel/generator': 7.25.7 - '@babel/helper-compilation-targets': 7.25.7 - '@babel/helper-module-transforms': 7.25.7(@babel/core@7.25.8) - '@babel/helpers': 7.25.7 - '@babel/parser': 7.25.8 - '@babel/template': 7.25.7 - '@babel/traverse': 7.25.7 - '@babel/types': 7.25.8 + '@babel/code-frame': 7.26.2 + '@babel/generator': 7.26.2 + '@babel/helper-compilation-targets': 7.25.9 + '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) + '@babel/helpers': 7.26.0 + '@babel/parser': 7.26.2 + '@babel/template': 7.25.9 + '@babel/traverse': 7.25.9 + '@babel/types': 7.26.0 convert-source-map: 2.0.0 debug: 4.3.7 gensync: 1.0.0-beta.2 @@ -2585,189 +1973,252 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/generator@7.25.7': + '@babel/generator@7.26.2': dependencies: - '@babel/types': 7.25.8 + '@babel/parser': 7.26.2 + '@babel/types': 7.26.0 '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 jsesc: 3.0.2 - '@babel/helper-compilation-targets@7.25.7': + '@babel/helper-compilation-targets@7.25.9': dependencies: - '@babel/compat-data': 7.25.8 - '@babel/helper-validator-option': 7.25.7 - browserslist: 4.24.0 + '@babel/compat-data': 7.26.2 + '@babel/helper-validator-option': 7.25.9 + browserslist: 4.24.2 lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-module-imports@7.25.7': + '@babel/helper-module-imports@7.25.9': dependencies: - '@babel/traverse': 7.25.7 - '@babel/types': 7.25.8 + '@babel/traverse': 7.25.9 + '@babel/types': 7.26.0 transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.25.7(@babel/core@7.25.8)': + '@babel/helper-module-transforms@7.26.0(@babel/core@7.26.0)': dependencies: - '@babel/core': 7.25.8 - '@babel/helper-module-imports': 7.25.7 - '@babel/helper-simple-access': 7.25.7 - '@babel/helper-validator-identifier': 7.25.7 - '@babel/traverse': 7.25.7 + '@babel/core': 7.26.0 + '@babel/helper-module-imports': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 + '@babel/traverse': 7.25.9 transitivePeerDependencies: - supports-color - '@babel/helper-plugin-utils@7.25.7': {} + '@babel/helper-plugin-utils@7.25.9': {} - '@babel/helper-simple-access@7.25.7': + '@babel/helper-string-parser@7.25.9': {} + + '@babel/helper-validator-identifier@7.25.9': {} + + '@babel/helper-validator-option@7.25.9': {} + + '@babel/helpers@7.26.0': dependencies: - '@babel/traverse': 7.25.7 - '@babel/types': 7.25.8 - transitivePeerDependencies: - - supports-color + '@babel/template': 7.25.9 + '@babel/types': 7.26.0 - '@babel/helper-string-parser@7.25.7': {} - - '@babel/helper-validator-identifier@7.25.7': {} - - '@babel/helper-validator-option@7.25.7': {} - - '@babel/helpers@7.25.7': + '@babel/parser@7.26.2': dependencies: - '@babel/template': 7.25.7 - '@babel/types': 7.25.8 + '@babel/types': 7.26.0 - '@babel/highlight@7.25.7': + '@babel/plugin-syntax-jsx@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/helper-validator-identifier': 7.25.7 - chalk: 2.4.2 - js-tokens: 4.0.0 - picocolors: 1.1.0 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/parser@7.25.8': + '@babel/plugin-syntax-typescript@7.25.9(@babel/core@7.26.0)': dependencies: - '@babel/types': 7.25.8 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-react-jsx-self@7.25.7(@babel/core@7.25.8)': + '@babel/template@7.25.9': dependencies: - '@babel/core': 7.25.8 - '@babel/helper-plugin-utils': 7.25.7 + '@babel/code-frame': 7.26.2 + '@babel/parser': 7.26.2 + '@babel/types': 7.26.0 - '@babel/plugin-transform-react-jsx-source@7.25.7(@babel/core@7.25.8)': + '@babel/traverse@7.25.9': dependencies: - '@babel/core': 7.25.8 - '@babel/helper-plugin-utils': 7.25.7 - - '@babel/template@7.25.7': - dependencies: - '@babel/code-frame': 7.25.7 - '@babel/parser': 7.25.8 - '@babel/types': 7.25.8 - - '@babel/traverse@7.25.7': - dependencies: - '@babel/code-frame': 7.25.7 - '@babel/generator': 7.25.7 - '@babel/parser': 7.25.8 - '@babel/template': 7.25.7 - '@babel/types': 7.25.8 + '@babel/code-frame': 7.26.2 + '@babel/generator': 7.26.2 + '@babel/parser': 7.26.2 + '@babel/template': 7.25.9 + '@babel/types': 7.26.0 debug: 4.3.7 globals: 11.12.0 transitivePeerDependencies: - supports-color - '@babel/types@7.25.8': + '@babel/types@7.26.0': dependencies: - '@babel/helper-string-parser': 7.25.7 - '@babel/helper-validator-identifier': 7.25.7 - to-fast-properties: 2.0.0 - - '@cspotcode/source-map-support@0.8.1': - dependencies: - '@jridgewell/trace-mapping': 0.3.9 + '@babel/helper-string-parser': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 '@esbuild/aix-ppc64@0.21.5': optional: true + '@esbuild/aix-ppc64@0.23.1': + optional: true + '@esbuild/android-arm64@0.21.5': optional: true + '@esbuild/android-arm64@0.23.1': + optional: true + '@esbuild/android-arm@0.21.5': optional: true + '@esbuild/android-arm@0.23.1': + optional: true + '@esbuild/android-x64@0.21.5': optional: true + '@esbuild/android-x64@0.23.1': + optional: true + '@esbuild/darwin-arm64@0.21.5': optional: true + '@esbuild/darwin-arm64@0.23.1': + optional: true + '@esbuild/darwin-x64@0.21.5': optional: true + '@esbuild/darwin-x64@0.23.1': + optional: true + '@esbuild/freebsd-arm64@0.21.5': optional: true + '@esbuild/freebsd-arm64@0.23.1': + optional: true + '@esbuild/freebsd-x64@0.21.5': optional: true + '@esbuild/freebsd-x64@0.23.1': + optional: true + '@esbuild/linux-arm64@0.21.5': optional: true + '@esbuild/linux-arm64@0.23.1': + optional: true + '@esbuild/linux-arm@0.21.5': optional: true + '@esbuild/linux-arm@0.23.1': + optional: true + '@esbuild/linux-ia32@0.21.5': optional: true + '@esbuild/linux-ia32@0.23.1': + optional: true + '@esbuild/linux-loong64@0.21.5': optional: true + '@esbuild/linux-loong64@0.23.1': + optional: true + '@esbuild/linux-mips64el@0.21.5': optional: true + '@esbuild/linux-mips64el@0.23.1': + optional: true + '@esbuild/linux-ppc64@0.21.5': optional: true + '@esbuild/linux-ppc64@0.23.1': + optional: true + '@esbuild/linux-riscv64@0.21.5': optional: true + '@esbuild/linux-riscv64@0.23.1': + optional: true + '@esbuild/linux-s390x@0.21.5': optional: true + '@esbuild/linux-s390x@0.23.1': + optional: true + '@esbuild/linux-x64@0.21.5': optional: true + '@esbuild/linux-x64@0.23.1': + optional: true + '@esbuild/netbsd-x64@0.21.5': optional: true + '@esbuild/netbsd-x64@0.23.1': + optional: true + + '@esbuild/openbsd-arm64@0.23.1': + optional: true + '@esbuild/openbsd-x64@0.21.5': optional: true + '@esbuild/openbsd-x64@0.23.1': + optional: true + '@esbuild/sunos-x64@0.21.5': optional: true + '@esbuild/sunos-x64@0.23.1': + optional: true + '@esbuild/win32-arm64@0.21.5': optional: true + '@esbuild/win32-arm64@0.23.1': + optional: true + '@esbuild/win32-ia32@0.21.5': optional: true + '@esbuild/win32-ia32@0.23.1': + optional: true + '@esbuild/win32-x64@0.21.5': optional: true - '@eslint-community/eslint-utils@4.4.0(eslint@8.57.1)': + '@esbuild/win32-x64@0.23.1': + optional: true + + '@eslint-community/eslint-utils@4.4.1(eslint@9.14.0(jiti@1.21.6))': dependencies: - eslint: 8.57.1 + eslint: 9.14.0(jiti@1.21.6) eslint-visitor-keys: 3.4.3 - '@eslint-community/regexpp@4.11.1': {} + '@eslint-community/regexpp@4.12.1': {} - '@eslint/eslintrc@2.1.4': + '@eslint/config-array@0.18.0': + dependencies: + '@eslint/object-schema': 2.1.4 + debug: 4.3.7 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@eslint/core@0.7.0': {} + + '@eslint/eslintrc@3.1.0': dependencies: ajv: 6.12.6 debug: 4.3.7 - espree: 9.6.1 - globals: 13.24.0 + espree: 10.3.0 + globals: 14.0.0 ignore: 5.3.2 import-fresh: 3.3.0 js-yaml: 4.1.0 @@ -2776,31 +2227,26 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@8.57.1': {} + '@eslint/js@9.14.0': {} - '@humanwhocodes/config-array@0.13.0': + '@eslint/object-schema@2.1.4': {} + + '@eslint/plugin-kit@0.2.2': dependencies: - '@humanwhocodes/object-schema': 2.0.3 - debug: 4.3.7 - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color + levn: 0.4.1 + + '@humanfs/core@0.19.1': {} + + '@humanfs/node@0.16.6': + dependencies: + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.3.1 '@humanwhocodes/module-importer@1.0.1': {} - '@humanwhocodes/object-schema@2.0.3': {} + '@humanwhocodes/retry@0.3.1': {} - '@ianvs/prettier-plugin-sort-imports@4.3.1(prettier@3.3.3)': - dependencies: - '@babel/core': 7.25.8 - '@babel/generator': 7.25.7 - '@babel/parser': 7.25.8 - '@babel/traverse': 7.25.7 - '@babel/types': 7.25.8 - prettier: 3.3.3 - semver: 7.6.3 - transitivePeerDependencies: - - supports-color + '@humanwhocodes/retry@0.4.1': {} '@isaacs/cliui@8.0.2': dependencies: @@ -2811,10 +2257,6 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 - '@jest/schemas@29.6.3': - dependencies: - '@sinclair/typebox': 0.27.8 - '@jridgewell/gen-mapping@0.3.5': dependencies: '@jridgewell/set-array': 1.2.1 @@ -2832,38 +2274,6 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.0 - '@jridgewell/trace-mapping@0.3.9': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.0 - - '@nkzw/eslint-config@1.18.1(eslint@8.57.1)(typescript@5.6.3)': - dependencies: - '@nkzw/eslint-plugin': 1.8.0(eslint@8.57.1) - '@typescript-eslint/eslint-plugin': 8.9.0(@typescript-eslint/parser@8.9.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3) - '@typescript-eslint/parser': 8.9.0(eslint@8.57.1)(typescript@5.6.3) - eslint: 8.57.1 - eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.9.0(eslint@8.57.1)(typescript@5.6.3))(eslint-plugin-import@2.31.0)(eslint@8.57.1) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.9.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) - eslint-plugin-no-only-tests: 3.3.0 - eslint-plugin-react: 7.37.1(eslint@8.57.1) - eslint-plugin-react-hooks: 4.6.2(eslint@8.57.1) - eslint-plugin-sort-destructure-keys: 2.0.0(eslint@8.57.1) - eslint-plugin-sort-keys-fix: 1.1.2 - eslint-plugin-typescript-sort-keys: 3.3.0(@typescript-eslint/parser@8.9.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3) - eslint-plugin-unicorn: 55.0.0(eslint@8.57.1) - eslint-plugin-unused-imports: 4.0.1(@typescript-eslint/eslint-plugin@8.9.0(@typescript-eslint/parser@8.9.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1) - transitivePeerDependencies: - - eslint-import-resolver-node - - eslint-import-resolver-webpack - - eslint-plugin-import-x - - supports-color - - typescript - - '@nkzw/eslint-plugin@1.8.0(eslint@8.57.1)': - dependencies: - eslint: 8.57.1 - '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -2876,356 +2286,386 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.17.1 - '@nolyfill/is-core-module@1.0.39': {} - '@pkgjs/parseargs@0.11.0': optional: true - '@rollup/rollup-android-arm-eabi@4.24.0': + '@radix-ui/react-compose-refs@1.1.0(@types/react@18.3.12)(react@18.3.1)': + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.12 + + '@radix-ui/react-label@2.1.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.12 + '@types/react-dom': 18.3.1 + + '@radix-ui/react-primitive@2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-slot': 1.1.0(@types/react@18.3.12)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.12 + '@types/react-dom': 18.3.1 + + '@radix-ui/react-slot@1.1.0(@types/react@18.3.12)(react@18.3.1)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.12)(react@18.3.1) + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.12 + + '@rollup/rollup-android-arm-eabi@4.25.0': optional: true - '@rollup/rollup-android-arm64@4.24.0': + '@rollup/rollup-android-arm64@4.25.0': optional: true - '@rollup/rollup-darwin-arm64@4.24.0': + '@rollup/rollup-darwin-arm64@4.25.0': optional: true - '@rollup/rollup-darwin-x64@4.24.0': + '@rollup/rollup-darwin-x64@4.25.0': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.24.0': + '@rollup/rollup-freebsd-arm64@4.25.0': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.24.0': + '@rollup/rollup-freebsd-x64@4.25.0': optional: true - '@rollup/rollup-linux-arm64-gnu@4.24.0': + '@rollup/rollup-linux-arm-gnueabihf@4.25.0': optional: true - '@rollup/rollup-linux-arm64-musl@4.24.0': + '@rollup/rollup-linux-arm-musleabihf@4.25.0': optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.24.0': + '@rollup/rollup-linux-arm64-gnu@4.25.0': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.24.0': + '@rollup/rollup-linux-arm64-musl@4.25.0': optional: true - '@rollup/rollup-linux-s390x-gnu@4.24.0': + '@rollup/rollup-linux-powerpc64le-gnu@4.25.0': optional: true - '@rollup/rollup-linux-x64-gnu@4.24.0': + '@rollup/rollup-linux-riscv64-gnu@4.25.0': optional: true - '@rollup/rollup-linux-x64-musl@4.24.0': + '@rollup/rollup-linux-s390x-gnu@4.25.0': optional: true - '@rollup/rollup-win32-arm64-msvc@4.24.0': + '@rollup/rollup-linux-x64-gnu@4.25.0': optional: true - '@rollup/rollup-win32-ia32-msvc@4.24.0': + '@rollup/rollup-linux-x64-musl@4.25.0': optional: true - '@rollup/rollup-win32-x64-msvc@4.24.0': + '@rollup/rollup-win32-arm64-msvc@4.25.0': optional: true - '@rtsao/scc@1.1.0': {} - - '@sinclair/typebox@0.27.8': {} - - '@swc/core-darwin-arm64@1.7.36': + '@rollup/rollup-win32-ia32-msvc@4.25.0': optional: true - '@swc/core-darwin-x64@1.7.36': + '@rollup/rollup-win32-x64-msvc@4.25.0': optional: true - '@swc/core-linux-arm-gnueabihf@1.7.36': + '@swc/core-darwin-arm64@1.9.1': optional: true - '@swc/core-linux-arm64-gnu@1.7.36': + '@swc/core-darwin-x64@1.9.1': optional: true - '@swc/core-linux-arm64-musl@1.7.36': + '@swc/core-linux-arm-gnueabihf@1.9.1': optional: true - '@swc/core-linux-x64-gnu@1.7.36': + '@swc/core-linux-arm64-gnu@1.9.1': optional: true - '@swc/core-linux-x64-musl@1.7.36': + '@swc/core-linux-arm64-musl@1.9.1': optional: true - '@swc/core-win32-arm64-msvc@1.7.36': + '@swc/core-linux-x64-gnu@1.9.1': optional: true - '@swc/core-win32-ia32-msvc@1.7.36': + '@swc/core-linux-x64-musl@1.9.1': optional: true - '@swc/core-win32-x64-msvc@1.7.36': + '@swc/core-win32-arm64-msvc@1.9.1': optional: true - '@swc/core@1.7.36': + '@swc/core-win32-ia32-msvc@1.9.1': + optional: true + + '@swc/core-win32-x64-msvc@1.9.1': + optional: true + + '@swc/core@1.9.1': dependencies: '@swc/counter': 0.1.3 - '@swc/types': 0.1.13 + '@swc/types': 0.1.14 optionalDependencies: - '@swc/core-darwin-arm64': 1.7.36 - '@swc/core-darwin-x64': 1.7.36 - '@swc/core-linux-arm-gnueabihf': 1.7.36 - '@swc/core-linux-arm64-gnu': 1.7.36 - '@swc/core-linux-arm64-musl': 1.7.36 - '@swc/core-linux-x64-gnu': 1.7.36 - '@swc/core-linux-x64-musl': 1.7.36 - '@swc/core-win32-arm64-msvc': 1.7.36 - '@swc/core-win32-ia32-msvc': 1.7.36 - '@swc/core-win32-x64-msvc': 1.7.36 + '@swc/core-darwin-arm64': 1.9.1 + '@swc/core-darwin-x64': 1.9.1 + '@swc/core-linux-arm-gnueabihf': 1.9.1 + '@swc/core-linux-arm64-gnu': 1.9.1 + '@swc/core-linux-arm64-musl': 1.9.1 + '@swc/core-linux-x64-gnu': 1.9.1 + '@swc/core-linux-x64-musl': 1.9.1 + '@swc/core-win32-arm64-msvc': 1.9.1 + '@swc/core-win32-ia32-msvc': 1.9.1 + '@swc/core-win32-x64-msvc': 1.9.1 '@swc/counter@0.1.3': {} - '@swc/types@0.1.13': + '@swc/types@0.1.14': dependencies: '@swc/counter': 0.1.3 - '@tsconfig/node10@1.0.11': {} + '@tanstack/history@1.61.1': {} - '@tsconfig/node12@1.0.11': {} + '@tanstack/react-router@1.81.1(@tanstack/router-generator@1.79.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@tanstack/history': 1.61.1 + '@tanstack/react-store': 0.5.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + tiny-invariant: 1.3.3 + tiny-warning: 1.0.3 + optionalDependencies: + '@tanstack/router-generator': 1.79.0 - '@tsconfig/node14@1.0.3': {} + '@tanstack/react-store@0.5.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@tanstack/store': 0.5.5 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + use-sync-external-store: 1.2.2(react@18.3.1) - '@tsconfig/node16@1.0.4': {} + '@tanstack/router-devtools@1.81.1(@tanstack/react-router@1.81.1(@tanstack/router-generator@1.79.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(csstype@3.1.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@tanstack/react-router': 1.81.1(@tanstack/router-generator@1.79.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + clsx: 2.1.1 + goober: 2.1.16(csstype@3.1.3) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + transitivePeerDependencies: + - csstype + + '@tanstack/router-generator@1.79.0': + dependencies: + '@tanstack/virtual-file-routes': 1.64.0 + prettier: 3.3.3 + tsx: 4.19.2 + zod: 3.23.8 + + '@tanstack/router-plugin@1.79.0(vite@5.4.10(@types/node@22.9.0))': + dependencies: + '@babel/core': 7.26.0 + '@babel/generator': 7.26.2 + '@babel/parser': 7.26.2 + '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.26.0) + '@babel/template': 7.25.9 + '@babel/traverse': 7.25.9 + '@babel/types': 7.26.0 + '@tanstack/router-generator': 1.79.0 + '@tanstack/virtual-file-routes': 1.64.0 + '@types/babel__core': 7.20.5 + '@types/babel__generator': 7.6.8 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.20.6 + babel-dead-code-elimination: 1.0.6 + chokidar: 3.6.0 + unplugin: 1.15.0 + zod: 3.23.8 + optionalDependencies: + vite: 5.4.10(@types/node@22.9.0) + transitivePeerDependencies: + - supports-color + - webpack-sources + + '@tanstack/store@0.5.5': {} + + '@tanstack/virtual-file-routes@1.64.0': {} '@types/babel__core@7.20.5': dependencies: - '@babel/parser': 7.25.8 - '@babel/types': 7.25.8 + '@babel/parser': 7.26.2 + '@babel/types': 7.26.0 '@types/babel__generator': 7.6.8 '@types/babel__template': 7.4.4 '@types/babel__traverse': 7.20.6 '@types/babel__generator@7.6.8': dependencies: - '@babel/types': 7.25.8 + '@babel/types': 7.26.0 '@types/babel__template@7.4.4': dependencies: - '@babel/parser': 7.25.8 - '@babel/types': 7.25.8 + '@babel/parser': 7.26.2 + '@babel/types': 7.26.0 '@types/babel__traverse@7.20.6': dependencies: - '@babel/types': 7.25.8 + '@babel/types': 7.26.0 '@types/estree@1.0.6': {} '@types/json-schema@7.0.15': {} - '@types/json5@0.0.29': {} - - '@types/node@20.16.11': + '@types/node@22.9.0': dependencies: undici-types: 6.19.8 - '@types/normalize-package-data@2.4.4': {} - '@types/prop-types@15.7.13': {} '@types/react-dom@18.3.1': dependencies: - '@types/react': 18.3.11 + '@types/react': 18.3.12 - '@types/react@18.3.11': + '@types/react@18.3.12': dependencies: '@types/prop-types': 15.7.13 csstype: 3.1.3 - '@types/semver@7.5.8': {} - - '@typescript-eslint/eslint-plugin@8.9.0(@typescript-eslint/parser@8.9.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3)': + '@typescript-eslint/eslint-plugin@8.13.0(@typescript-eslint/parser@8.13.0(eslint@9.14.0(jiti@1.21.6))(typescript@5.6.3))(eslint@9.14.0(jiti@1.21.6))(typescript@5.6.3)': dependencies: - '@eslint-community/regexpp': 4.11.1 - '@typescript-eslint/parser': 8.9.0(eslint@8.57.1)(typescript@5.6.3) - '@typescript-eslint/scope-manager': 8.9.0 - '@typescript-eslint/type-utils': 8.9.0(eslint@8.57.1)(typescript@5.6.3) - '@typescript-eslint/utils': 8.9.0(eslint@8.57.1)(typescript@5.6.3) - '@typescript-eslint/visitor-keys': 8.9.0 - eslint: 8.57.1 + '@eslint-community/regexpp': 4.12.1 + '@typescript-eslint/parser': 8.13.0(eslint@9.14.0(jiti@1.21.6))(typescript@5.6.3) + '@typescript-eslint/scope-manager': 8.13.0 + '@typescript-eslint/type-utils': 8.13.0(eslint@9.14.0(jiti@1.21.6))(typescript@5.6.3) + '@typescript-eslint/utils': 8.13.0(eslint@9.14.0(jiti@1.21.6))(typescript@5.6.3) + '@typescript-eslint/visitor-keys': 8.13.0 + eslint: 9.14.0(jiti@1.21.6) graphemer: 1.4.0 ignore: 5.3.2 natural-compare: 1.4.0 - ts-api-utils: 1.3.0(typescript@5.6.3) + ts-api-utils: 1.4.0(typescript@5.6.3) optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/experimental-utils@5.62.0(eslint@8.57.1)(typescript@5.6.3)': + '@typescript-eslint/parser@8.13.0(eslint@9.14.0(jiti@1.21.6))(typescript@5.6.3)': dependencies: - '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@5.6.3) - eslint: 8.57.1 - transitivePeerDependencies: - - supports-color - - typescript - - '@typescript-eslint/parser@8.9.0(eslint@8.57.1)(typescript@5.6.3)': - dependencies: - '@typescript-eslint/scope-manager': 8.9.0 - '@typescript-eslint/types': 8.9.0 - '@typescript-eslint/typescript-estree': 8.9.0(typescript@5.6.3) - '@typescript-eslint/visitor-keys': 8.9.0 + '@typescript-eslint/scope-manager': 8.13.0 + '@typescript-eslint/types': 8.13.0 + '@typescript-eslint/typescript-estree': 8.13.0(typescript@5.6.3) + '@typescript-eslint/visitor-keys': 8.13.0 debug: 4.3.7 - eslint: 8.57.1 + eslint: 9.14.0(jiti@1.21.6) optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@5.62.0': + '@typescript-eslint/scope-manager@8.13.0': dependencies: - '@typescript-eslint/types': 5.62.0 - '@typescript-eslint/visitor-keys': 5.62.0 + '@typescript-eslint/types': 8.13.0 + '@typescript-eslint/visitor-keys': 8.13.0 - '@typescript-eslint/scope-manager@8.9.0': + '@typescript-eslint/type-utils@8.13.0(eslint@9.14.0(jiti@1.21.6))(typescript@5.6.3)': dependencies: - '@typescript-eslint/types': 8.9.0 - '@typescript-eslint/visitor-keys': 8.9.0 - - '@typescript-eslint/type-utils@8.9.0(eslint@8.57.1)(typescript@5.6.3)': - dependencies: - '@typescript-eslint/typescript-estree': 8.9.0(typescript@5.6.3) - '@typescript-eslint/utils': 8.9.0(eslint@8.57.1)(typescript@5.6.3) + '@typescript-eslint/typescript-estree': 8.13.0(typescript@5.6.3) + '@typescript-eslint/utils': 8.13.0(eslint@9.14.0(jiti@1.21.6))(typescript@5.6.3) debug: 4.3.7 - ts-api-utils: 1.3.0(typescript@5.6.3) + ts-api-utils: 1.4.0(typescript@5.6.3) optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: - eslint - supports-color - '@typescript-eslint/types@5.62.0': {} + '@typescript-eslint/types@8.13.0': {} - '@typescript-eslint/types@8.9.0': {} - - '@typescript-eslint/typescript-estree@5.62.0(typescript@5.6.3)': + '@typescript-eslint/typescript-estree@8.13.0(typescript@5.6.3)': dependencies: - '@typescript-eslint/types': 5.62.0 - '@typescript-eslint/visitor-keys': 5.62.0 - debug: 4.3.7 - globby: 11.1.0 - is-glob: 4.0.3 - semver: 7.6.3 - tsutils: 3.21.0(typescript@5.6.3) - optionalDependencies: - typescript: 5.6.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/typescript-estree@8.9.0(typescript@5.6.3)': - dependencies: - '@typescript-eslint/types': 8.9.0 - '@typescript-eslint/visitor-keys': 8.9.0 + '@typescript-eslint/types': 8.13.0 + '@typescript-eslint/visitor-keys': 8.13.0 debug: 4.3.7 fast-glob: 3.3.2 is-glob: 4.0.3 minimatch: 9.0.5 semver: 7.6.3 - ts-api-utils: 1.3.0(typescript@5.6.3) + ts-api-utils: 1.4.0(typescript@5.6.3) optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@5.62.0(eslint@8.57.1)(typescript@5.6.3)': + '@typescript-eslint/utils@8.13.0(eslint@9.14.0(jiti@1.21.6))(typescript@5.6.3)': dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.1) - '@types/json-schema': 7.0.15 - '@types/semver': 7.5.8 - '@typescript-eslint/scope-manager': 5.62.0 - '@typescript-eslint/types': 5.62.0 - '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.6.3) - eslint: 8.57.1 - eslint-scope: 5.1.1 - semver: 7.6.3 + '@eslint-community/eslint-utils': 4.4.1(eslint@9.14.0(jiti@1.21.6)) + '@typescript-eslint/scope-manager': 8.13.0 + '@typescript-eslint/types': 8.13.0 + '@typescript-eslint/typescript-estree': 8.13.0(typescript@5.6.3) + eslint: 9.14.0(jiti@1.21.6) transitivePeerDependencies: - supports-color - typescript - '@typescript-eslint/utils@8.9.0(eslint@8.57.1)(typescript@5.6.3)': + '@typescript-eslint/visitor-keys@8.13.0': dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.1) - '@typescript-eslint/scope-manager': 8.9.0 - '@typescript-eslint/types': 8.9.0 - '@typescript-eslint/typescript-estree': 8.9.0(typescript@5.6.3) - eslint: 8.57.1 - transitivePeerDependencies: - - supports-color - - typescript - - '@typescript-eslint/visitor-keys@5.62.0': - dependencies: - '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/types': 8.13.0 eslint-visitor-keys: 3.4.3 - '@typescript-eslint/visitor-keys@8.9.0': + '@vitejs/plugin-react-swc@3.7.1(vite@5.4.10(@types/node@22.9.0))': dependencies: - '@typescript-eslint/types': 8.9.0 - eslint-visitor-keys: 3.4.3 - - '@ungap/structured-clone@1.2.0': {} - - '@vitejs/plugin-react@4.3.2(vite@5.4.9(@types/node@20.16.11))': - dependencies: - '@babel/core': 7.25.8 - '@babel/plugin-transform-react-jsx-self': 7.25.7(@babel/core@7.25.8) - '@babel/plugin-transform-react-jsx-source': 7.25.7(@babel/core@7.25.8) - '@types/babel__core': 7.20.5 - react-refresh: 0.14.2 - vite: 5.4.9(@types/node@20.16.11) + '@swc/core': 1.9.1 + vite: 5.4.10(@types/node@22.9.0) transitivePeerDependencies: - - supports-color + - '@swc/helpers' - '@vitest/expect@1.6.0': + '@vitest/expect@2.1.4': dependencies: - '@vitest/spy': 1.6.0 - '@vitest/utils': 1.6.0 - chai: 4.5.0 + '@vitest/spy': 2.1.4 + '@vitest/utils': 2.1.4 + chai: 5.1.2 + tinyrainbow: 1.2.0 - '@vitest/runner@1.6.0': + '@vitest/mocker@2.1.4(vite@5.4.10(@types/node@22.9.0))': dependencies: - '@vitest/utils': 1.6.0 - p-limit: 5.0.0 + '@vitest/spy': 2.1.4 + estree-walker: 3.0.3 + magic-string: 0.30.12 + optionalDependencies: + vite: 5.4.10(@types/node@22.9.0) + + '@vitest/pretty-format@2.1.4': + dependencies: + tinyrainbow: 1.2.0 + + '@vitest/runner@2.1.4': + dependencies: + '@vitest/utils': 2.1.4 pathe: 1.1.2 - '@vitest/snapshot@1.6.0': + '@vitest/snapshot@2.1.4': dependencies: + '@vitest/pretty-format': 2.1.4 magic-string: 0.30.12 pathe: 1.1.2 - pretty-format: 29.7.0 - '@vitest/spy@1.6.0': + '@vitest/spy@2.1.4': dependencies: - tinyspy: 2.2.1 + tinyspy: 3.0.2 - '@vitest/utils@1.6.0': + '@vitest/utils@2.1.4': dependencies: - diff-sequences: 29.6.3 - estree-walker: 3.0.3 - loupe: 2.3.7 - pretty-format: 29.7.0 + '@vitest/pretty-format': 2.1.4 + loupe: 3.1.2 + tinyrainbow: 1.2.0 - acorn-jsx@5.3.2(acorn@7.4.1): + acorn-jsx@5.3.2(acorn@8.14.0): dependencies: - acorn: 7.4.1 + acorn: 8.14.0 - acorn-jsx@5.3.2(acorn@8.12.1): - dependencies: - acorn: 8.12.1 - - acorn-walk@8.3.4: - dependencies: - acorn: 8.12.1 - - acorn@7.4.1: {} - - acorn@8.12.1: {} + acorn@8.14.0: {} ajv@6.12.6: dependencies: @@ -3238,16 +2678,10 @@ snapshots: ansi-regex@6.1.0: {} - ansi-styles@3.2.1: - dependencies: - color-convert: 1.9.3 - ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 - ansi-styles@5.2.0: {} - ansi-styles@6.2.1: {} any-promise@1.3.0: {} @@ -3257,94 +2691,30 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.1 - arg@4.1.3: {} - arg@5.0.2: {} argparse@2.0.1: {} - array-buffer-byte-length@1.0.1: - dependencies: - call-bind: 1.0.7 - is-array-buffer: 3.0.4 - - array-includes@3.1.8: - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.3 - es-object-atoms: 1.0.0 - get-intrinsic: 1.2.4 - is-string: 1.0.7 - - array-union@2.1.0: {} - - array.prototype.findlast@1.2.5: - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.3 - es-errors: 1.3.0 - es-object-atoms: 1.0.0 - es-shim-unscopables: 1.0.2 - - array.prototype.findlastindex@1.2.5: - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.3 - es-errors: 1.3.0 - es-object-atoms: 1.0.0 - es-shim-unscopables: 1.0.2 - - array.prototype.flat@1.3.2: - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.3 - es-shim-unscopables: 1.0.2 - - array.prototype.flatmap@1.3.2: - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.3 - es-shim-unscopables: 1.0.2 - - array.prototype.tosorted@1.1.4: - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.3 - es-errors: 1.3.0 - es-shim-unscopables: 1.0.2 - - arraybuffer.prototype.slice@1.0.3: - dependencies: - array-buffer-byte-length: 1.0.1 - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.3 - es-errors: 1.3.0 - get-intrinsic: 1.2.4 - is-array-buffer: 3.0.4 - is-shared-array-buffer: 1.0.3 - - assertion-error@1.1.0: {} + assertion-error@2.0.1: {} autoprefixer@10.4.20(postcss@8.4.47): dependencies: - browserslist: 4.24.0 - caniuse-lite: 1.0.30001668 + browserslist: 4.24.2 + caniuse-lite: 1.0.30001679 fraction.js: 4.3.7 normalize-range: 0.1.2 - picocolors: 1.1.0 + picocolors: 1.1.1 postcss: 8.4.47 postcss-value-parser: 4.2.0 - available-typed-arrays@1.0.7: + babel-dead-code-elimination@1.0.6: dependencies: - possible-typed-array-names: 1.0.0 + '@babel/core': 7.26.0 + '@babel/parser': 7.26.2 + '@babel/traverse': 7.25.9 + '@babel/types': 7.26.0 + transitivePeerDependencies: + - supports-color balanced-match@1.0.2: {} @@ -3363,55 +2733,35 @@ snapshots: dependencies: fill-range: 7.1.1 - browserslist@4.24.0: + browserslist@4.24.2: dependencies: - caniuse-lite: 1.0.30001668 - electron-to-chromium: 1.5.39 + caniuse-lite: 1.0.30001679 + electron-to-chromium: 1.5.55 node-releases: 2.0.18 - update-browserslist-db: 1.1.1(browserslist@4.24.0) - - builtin-modules@3.3.0: {} + update-browserslist-db: 1.1.1(browserslist@4.24.2) cac@6.7.14: {} - call-bind@1.0.7: - dependencies: - es-define-property: 1.0.0 - es-errors: 1.3.0 - function-bind: 1.1.2 - get-intrinsic: 1.2.4 - set-function-length: 1.2.2 - callsites@3.1.0: {} camelcase-css@2.0.1: {} - caniuse-lite@1.0.30001668: {} + caniuse-lite@1.0.30001679: {} - chai@4.5.0: + chai@5.1.2: dependencies: - assertion-error: 1.1.0 - check-error: 1.0.3 - deep-eql: 4.1.4 - get-func-name: 2.0.2 - loupe: 2.3.7 - pathval: 1.1.1 - type-detect: 4.1.0 - - chalk@2.4.2: - dependencies: - ansi-styles: 3.2.1 - escape-string-regexp: 1.0.5 - supports-color: 5.5.0 + assertion-error: 2.0.1 + check-error: 2.1.1 + deep-eql: 5.0.2 + loupe: 3.1.2 + pathval: 2.0.0 chalk@4.1.2: dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 - check-error@1.0.3: - dependencies: - get-func-name: 2.0.2 + check-error@2.1.1: {} chokidar@3.6.0: dependencies: @@ -3425,39 +2775,27 @@ snapshots: optionalDependencies: fsevents: 2.3.3 - ci-info@4.0.0: {} - - clean-regexp@1.0.0: + class-variance-authority@0.7.0: dependencies: - escape-string-regexp: 1.0.5 + clsx: 2.0.0 - color-convert@1.9.3: - dependencies: - color-name: 1.1.3 + clsx@2.0.0: {} + + clsx@2.1.1: {} color-convert@2.0.1: dependencies: color-name: 1.1.4 - color-name@1.1.3: {} - color-name@1.1.4: {} commander@4.1.1: {} concat-map@0.0.1: {} - confbox@0.1.8: {} - convert-source-map@2.0.0: {} - core-js-compat@3.38.1: - dependencies: - browserslist: 4.24.0 - - create-require@1.1.1: {} - - cross-spawn@7.0.3: + cross-spawn@7.0.5: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 @@ -3467,179 +2805,26 @@ snapshots: csstype@3.1.3: {} - data-view-buffer@1.0.1: - dependencies: - call-bind: 1.0.7 - es-errors: 1.3.0 - is-data-view: 1.0.1 - - data-view-byte-length@1.0.1: - dependencies: - call-bind: 1.0.7 - es-errors: 1.3.0 - is-data-view: 1.0.1 - - data-view-byte-offset@1.0.0: - dependencies: - call-bind: 1.0.7 - es-errors: 1.3.0 - is-data-view: 1.0.1 - - debug@3.2.7: - dependencies: - ms: 2.1.3 - debug@4.3.7: dependencies: ms: 2.1.3 - deep-eql@4.1.4: - dependencies: - type-detect: 4.1.0 + deep-eql@5.0.2: {} deep-is@0.1.4: {} - define-data-property@1.1.4: - dependencies: - es-define-property: 1.0.0 - es-errors: 1.3.0 - gopd: 1.0.1 - - define-properties@1.2.1: - dependencies: - define-data-property: 1.1.4 - has-property-descriptors: 1.0.2 - object-keys: 1.1.1 - didyoumean@1.2.2: {} - diff-sequences@29.6.3: {} - - diff@4.0.2: {} - - dir-glob@3.0.1: - dependencies: - path-type: 4.0.0 - dlv@1.1.3: {} - doctrine@2.1.0: - dependencies: - esutils: 2.0.3 - - doctrine@3.0.0: - dependencies: - esutils: 2.0.3 - eastasianwidth@0.2.0: {} - electron-to-chromium@1.5.39: {} + electron-to-chromium@1.5.55: {} emoji-regex@8.0.0: {} emoji-regex@9.2.2: {} - enhanced-resolve@5.17.1: - dependencies: - graceful-fs: 4.2.11 - tapable: 2.2.1 - - error-ex@1.3.2: - dependencies: - is-arrayish: 0.2.1 - - es-abstract@1.23.3: - dependencies: - array-buffer-byte-length: 1.0.1 - arraybuffer.prototype.slice: 1.0.3 - available-typed-arrays: 1.0.7 - call-bind: 1.0.7 - data-view-buffer: 1.0.1 - data-view-byte-length: 1.0.1 - data-view-byte-offset: 1.0.0 - es-define-property: 1.0.0 - es-errors: 1.3.0 - es-object-atoms: 1.0.0 - es-set-tostringtag: 2.0.3 - es-to-primitive: 1.2.1 - function.prototype.name: 1.1.6 - get-intrinsic: 1.2.4 - get-symbol-description: 1.0.2 - globalthis: 1.0.4 - gopd: 1.0.1 - has-property-descriptors: 1.0.2 - has-proto: 1.0.3 - has-symbols: 1.0.3 - hasown: 2.0.2 - internal-slot: 1.0.7 - is-array-buffer: 3.0.4 - is-callable: 1.2.7 - is-data-view: 1.0.1 - is-negative-zero: 2.0.3 - is-regex: 1.1.4 - is-shared-array-buffer: 1.0.3 - is-string: 1.0.7 - is-typed-array: 1.1.13 - is-weakref: 1.0.2 - object-inspect: 1.13.2 - object-keys: 1.1.1 - object.assign: 4.1.5 - regexp.prototype.flags: 1.5.3 - safe-array-concat: 1.1.2 - safe-regex-test: 1.0.3 - string.prototype.trim: 1.2.9 - string.prototype.trimend: 1.0.8 - string.prototype.trimstart: 1.0.8 - typed-array-buffer: 1.0.2 - typed-array-byte-length: 1.0.1 - typed-array-byte-offset: 1.0.2 - typed-array-length: 1.0.6 - unbox-primitive: 1.0.2 - which-typed-array: 1.1.15 - - es-define-property@1.0.0: - dependencies: - get-intrinsic: 1.2.4 - - es-errors@1.3.0: {} - - es-iterator-helpers@1.1.0: - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.3 - es-errors: 1.3.0 - es-set-tostringtag: 2.0.3 - function-bind: 1.1.2 - get-intrinsic: 1.2.4 - globalthis: 1.0.4 - has-property-descriptors: 1.0.2 - has-proto: 1.0.3 - has-symbols: 1.0.3 - internal-slot: 1.0.7 - iterator.prototype: 1.1.3 - safe-array-concat: 1.1.2 - - es-object-atoms@1.0.0: - dependencies: - es-errors: 1.3.0 - - es-set-tostringtag@2.0.3: - dependencies: - get-intrinsic: 1.2.4 - has-tostringtag: 1.0.2 - hasown: 2.0.2 - - es-shim-unscopables@1.0.2: - dependencies: - hasown: 2.0.2 - - es-to-primitive@1.2.1: - dependencies: - is-callable: 1.2.7 - is-date-object: 1.0.5 - is-symbol: 1.0.4 - esbuild@0.21.5: optionalDependencies: '@esbuild/aix-ppc64': 0.21.5 @@ -3666,227 +2851,101 @@ snapshots: '@esbuild/win32-ia32': 0.21.5 '@esbuild/win32-x64': 0.21.5 - escalade@3.2.0: {} + esbuild@0.23.1: + optionalDependencies: + '@esbuild/aix-ppc64': 0.23.1 + '@esbuild/android-arm': 0.23.1 + '@esbuild/android-arm64': 0.23.1 + '@esbuild/android-x64': 0.23.1 + '@esbuild/darwin-arm64': 0.23.1 + '@esbuild/darwin-x64': 0.23.1 + '@esbuild/freebsd-arm64': 0.23.1 + '@esbuild/freebsd-x64': 0.23.1 + '@esbuild/linux-arm': 0.23.1 + '@esbuild/linux-arm64': 0.23.1 + '@esbuild/linux-ia32': 0.23.1 + '@esbuild/linux-loong64': 0.23.1 + '@esbuild/linux-mips64el': 0.23.1 + '@esbuild/linux-ppc64': 0.23.1 + '@esbuild/linux-riscv64': 0.23.1 + '@esbuild/linux-s390x': 0.23.1 + '@esbuild/linux-x64': 0.23.1 + '@esbuild/netbsd-x64': 0.23.1 + '@esbuild/openbsd-arm64': 0.23.1 + '@esbuild/openbsd-x64': 0.23.1 + '@esbuild/sunos-x64': 0.23.1 + '@esbuild/win32-arm64': 0.23.1 + '@esbuild/win32-ia32': 0.23.1 + '@esbuild/win32-x64': 0.23.1 - escape-string-regexp@1.0.5: {} + escalade@3.2.0: {} escape-string-regexp@4.0.0: {} - eslint-import-resolver-node@0.3.9: + eslint-plugin-react-hooks@5.0.0(eslint@9.14.0(jiti@1.21.6)): dependencies: - debug: 3.2.7 - is-core-module: 2.15.1 - resolve: 1.22.8 - transitivePeerDependencies: - - supports-color + eslint: 9.14.0(jiti@1.21.6) - eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.9.0(eslint@8.57.1)(typescript@5.6.3))(eslint-plugin-import@2.31.0)(eslint@8.57.1): + eslint-plugin-react-refresh@0.4.14(eslint@9.14.0(jiti@1.21.6)): dependencies: - '@nolyfill/is-core-module': 1.0.39 - debug: 4.3.7 - enhanced-resolve: 5.17.1 - eslint: 8.57.1 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.9.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) - fast-glob: 3.3.2 - get-tsconfig: 4.8.1 - is-bun-module: 1.2.1 - is-glob: 4.0.3 - optionalDependencies: - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.9.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) - transitivePeerDependencies: - - '@typescript-eslint/parser' - - eslint-import-resolver-node - - eslint-import-resolver-webpack - - supports-color + eslint: 9.14.0(jiti@1.21.6) - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.9.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1): - dependencies: - debug: 3.2.7 - optionalDependencies: - '@typescript-eslint/parser': 8.9.0(eslint@8.57.1)(typescript@5.6.3) - eslint: 8.57.1 - eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.9.0(eslint@8.57.1)(typescript@5.6.3))(eslint-plugin-import@2.31.0)(eslint@8.57.1) - transitivePeerDependencies: - - supports-color - - eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.9.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1): - dependencies: - '@rtsao/scc': 1.1.0 - array-includes: 3.1.8 - array.prototype.findlastindex: 1.2.5 - array.prototype.flat: 1.3.2 - array.prototype.flatmap: 1.3.2 - debug: 3.2.7 - doctrine: 2.1.0 - eslint: 8.57.1 - eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.9.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) - hasown: 2.0.2 - is-core-module: 2.15.1 - is-glob: 4.0.3 - minimatch: 3.1.2 - object.fromentries: 2.0.8 - object.groupby: 1.0.3 - object.values: 1.2.0 - semver: 6.3.1 - string.prototype.trimend: 1.0.8 - tsconfig-paths: 3.15.0 - optionalDependencies: - '@typescript-eslint/parser': 8.9.0(eslint@8.57.1)(typescript@5.6.3) - transitivePeerDependencies: - - eslint-import-resolver-typescript - - eslint-import-resolver-webpack - - supports-color - - eslint-plugin-no-only-tests@3.3.0: {} - - eslint-plugin-react-hooks@4.6.2(eslint@8.57.1): - dependencies: - eslint: 8.57.1 - - eslint-plugin-react@7.37.1(eslint@8.57.1): - dependencies: - array-includes: 3.1.8 - array.prototype.findlast: 1.2.5 - array.prototype.flatmap: 1.3.2 - array.prototype.tosorted: 1.1.4 - doctrine: 2.1.0 - es-iterator-helpers: 1.1.0 - eslint: 8.57.1 - estraverse: 5.3.0 - hasown: 2.0.2 - jsx-ast-utils: 3.3.5 - minimatch: 3.1.2 - object.entries: 1.1.8 - object.fromentries: 2.0.8 - object.values: 1.2.0 - prop-types: 15.8.1 - resolve: 2.0.0-next.5 - semver: 6.3.1 - string.prototype.matchall: 4.0.11 - string.prototype.repeat: 1.0.0 - - eslint-plugin-sort-destructure-keys@2.0.0(eslint@8.57.1): - dependencies: - eslint: 8.57.1 - natural-compare-lite: 1.4.0 - - eslint-plugin-sort-keys-fix@1.1.2: - dependencies: - espree: 6.2.1 - esutils: 2.0.3 - natural-compare: 1.4.0 - requireindex: 1.2.0 - - eslint-plugin-typescript-sort-keys@3.3.0(@typescript-eslint/parser@8.9.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3): - dependencies: - '@typescript-eslint/experimental-utils': 5.62.0(eslint@8.57.1)(typescript@5.6.3) - '@typescript-eslint/parser': 8.9.0(eslint@8.57.1)(typescript@5.6.3) - eslint: 8.57.1 - json-schema: 0.4.0 - natural-compare-lite: 1.4.0 - typescript: 5.6.3 - transitivePeerDependencies: - - supports-color - - eslint-plugin-unicorn@55.0.0(eslint@8.57.1): - dependencies: - '@babel/helper-validator-identifier': 7.25.7 - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.1) - ci-info: 4.0.0 - clean-regexp: 1.0.0 - core-js-compat: 3.38.1 - eslint: 8.57.1 - esquery: 1.6.0 - globals: 15.11.0 - indent-string: 4.0.0 - is-builtin-module: 3.2.1 - jsesc: 3.0.2 - pluralize: 8.0.0 - read-pkg-up: 7.0.1 - regexp-tree: 0.1.27 - regjsparser: 0.10.0 - semver: 7.6.3 - strip-indent: 3.0.0 - - eslint-plugin-unused-imports@4.0.1(@typescript-eslint/eslint-plugin@8.9.0(@typescript-eslint/parser@8.9.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1): - dependencies: - eslint: 8.57.1 - eslint-rule-composer: 0.3.0 - optionalDependencies: - '@typescript-eslint/eslint-plugin': 8.9.0(@typescript-eslint/parser@8.9.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3) - - eslint-rule-composer@0.3.0: {} - - eslint-scope@5.1.1: - dependencies: - esrecurse: 4.3.0 - estraverse: 4.3.0 - - eslint-scope@7.2.2: + eslint-scope@8.2.0: dependencies: esrecurse: 4.3.0 estraverse: 5.3.0 - eslint-visitor-keys@1.3.0: {} - eslint-visitor-keys@3.4.3: {} - eslint@8.57.1: + eslint-visitor-keys@4.2.0: {} + + eslint@9.14.0(jiti@1.21.6): dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.1) - '@eslint-community/regexpp': 4.11.1 - '@eslint/eslintrc': 2.1.4 - '@eslint/js': 8.57.1 - '@humanwhocodes/config-array': 0.13.0 + '@eslint-community/eslint-utils': 4.4.1(eslint@9.14.0(jiti@1.21.6)) + '@eslint-community/regexpp': 4.12.1 + '@eslint/config-array': 0.18.0 + '@eslint/core': 0.7.0 + '@eslint/eslintrc': 3.1.0 + '@eslint/js': 9.14.0 + '@eslint/plugin-kit': 0.2.2 + '@humanfs/node': 0.16.6 '@humanwhocodes/module-importer': 1.0.1 - '@nodelib/fs.walk': 1.2.8 - '@ungap/structured-clone': 1.2.0 + '@humanwhocodes/retry': 0.4.1 + '@types/estree': 1.0.6 + '@types/json-schema': 7.0.15 ajv: 6.12.6 chalk: 4.1.2 - cross-spawn: 7.0.3 + cross-spawn: 7.0.5 debug: 4.3.7 - doctrine: 3.0.0 escape-string-regexp: 4.0.0 - eslint-scope: 7.2.2 - eslint-visitor-keys: 3.4.3 - espree: 9.6.1 + eslint-scope: 8.2.0 + eslint-visitor-keys: 4.2.0 + espree: 10.3.0 esquery: 1.6.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 - file-entry-cache: 6.0.1 + file-entry-cache: 8.0.0 find-up: 5.0.0 glob-parent: 6.0.2 - globals: 13.24.0 - graphemer: 1.4.0 ignore: 5.3.2 imurmurhash: 0.1.4 is-glob: 4.0.3 - is-path-inside: 3.0.3 - js-yaml: 4.1.0 json-stable-stringify-without-jsonify: 1.0.1 - levn: 0.4.1 lodash.merge: 4.6.2 minimatch: 3.1.2 natural-compare: 1.4.0 optionator: 0.9.4 - strip-ansi: 6.0.1 text-table: 0.2.0 + optionalDependencies: + jiti: 1.21.6 transitivePeerDependencies: - supports-color - espree@6.2.1: + espree@10.3.0: dependencies: - acorn: 7.4.1 - acorn-jsx: 5.3.2(acorn@7.4.1) - eslint-visitor-keys: 1.3.0 - - espree@9.6.1: - dependencies: - acorn: 8.12.1 - acorn-jsx: 5.3.2(acorn@8.12.1) - eslint-visitor-keys: 3.4.3 + acorn: 8.14.0 + acorn-jsx: 5.3.2(acorn@8.14.0) + eslint-visitor-keys: 4.2.0 esquery@1.6.0: dependencies: @@ -3896,8 +2955,6 @@ snapshots: dependencies: estraverse: 5.3.0 - estraverse@4.3.0: {} - estraverse@5.3.0: {} estree-walker@3.0.3: @@ -3906,17 +2963,7 @@ snapshots: esutils@2.0.3: {} - execa@8.0.1: - dependencies: - cross-spawn: 7.0.3 - get-stream: 8.0.1 - human-signals: 5.0.0 - is-stream: 3.0.0 - merge-stream: 2.0.0 - npm-run-path: 5.3.0 - onetime: 6.0.0 - signal-exit: 4.1.0 - strip-final-newline: 3.0.0 + expect-type@1.1.0: {} fast-deep-equal@3.1.3: {} @@ -3936,79 +2983,40 @@ snapshots: dependencies: reusify: 1.0.4 - file-entry-cache@6.0.1: + file-entry-cache@8.0.0: dependencies: - flat-cache: 3.2.0 + flat-cache: 4.0.1 fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 - find-up@4.1.0: - dependencies: - locate-path: 5.0.0 - path-exists: 4.0.0 - find-up@5.0.0: dependencies: locate-path: 6.0.0 path-exists: 4.0.0 - flat-cache@3.2.0: + flat-cache@4.0.1: dependencies: flatted: 3.3.1 keyv: 4.5.4 - rimraf: 3.0.2 flatted@3.3.1: {} - for-each@0.3.3: - dependencies: - is-callable: 1.2.7 - foreground-child@3.3.0: dependencies: - cross-spawn: 7.0.3 + cross-spawn: 7.0.5 signal-exit: 4.1.0 fraction.js@4.3.7: {} - fs.realpath@1.0.0: {} - fsevents@2.3.3: optional: true function-bind@1.1.2: {} - function.prototype.name@1.1.6: - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.3 - functions-have-names: 1.2.3 - - functions-have-names@1.2.3: {} - gensync@1.0.0-beta.2: {} - get-func-name@2.0.2: {} - - get-intrinsic@1.2.4: - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - has-proto: 1.0.3 - has-symbols: 1.0.3 - hasown: 2.0.2 - - get-stream@8.0.1: {} - - get-symbol-description@1.0.2: - dependencies: - call-bind: 1.0.7 - es-errors: 1.3.0 - get-intrinsic: 1.2.4 - get-tsconfig@4.8.1: dependencies: resolve-pkg-maps: 1.0.0 @@ -4030,71 +3038,24 @@ snapshots: package-json-from-dist: 1.0.1 path-scurry: 1.11.1 - glob@7.2.3: - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - globals@11.12.0: {} - globals@13.24.0: + globals@14.0.0: {} + + globals@15.12.0: {} + + goober@2.1.16(csstype@3.1.3): dependencies: - type-fest: 0.20.2 - - globals@15.11.0: {} - - globalthis@1.0.4: - dependencies: - define-properties: 1.2.1 - gopd: 1.0.1 - - globby@11.1.0: - dependencies: - array-union: 2.1.0 - dir-glob: 3.0.1 - fast-glob: 3.3.2 - ignore: 5.3.2 - merge2: 1.4.1 - slash: 3.0.0 - - gopd@1.0.1: - dependencies: - get-intrinsic: 1.2.4 - - graceful-fs@4.2.11: {} + csstype: 3.1.3 graphemer@1.4.0: {} - has-bigints@1.0.2: {} - - has-flag@3.0.0: {} - has-flag@4.0.0: {} - has-property-descriptors@1.0.2: - dependencies: - es-define-property: 1.0.0 - - has-proto@1.0.3: {} - - has-symbols@1.0.3: {} - - has-tostringtag@1.0.2: - dependencies: - has-symbols: 1.0.3 - hasown@2.0.2: dependencies: function-bind: 1.1.2 - hosted-git-info@2.8.9: {} - - human-signals@5.0.0: {} - ignore@5.3.2: {} import-fresh@3.3.0: @@ -4104,143 +3065,26 @@ snapshots: imurmurhash@0.1.4: {} - indent-string@4.0.0: {} - - inflight@1.0.6: - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - - inherits@2.0.4: {} - - internal-slot@1.0.7: - dependencies: - es-errors: 1.3.0 - hasown: 2.0.2 - side-channel: 1.0.6 - - is-array-buffer@3.0.4: - dependencies: - call-bind: 1.0.7 - get-intrinsic: 1.2.4 - - is-arrayish@0.2.1: {} - - is-async-function@2.0.0: - dependencies: - has-tostringtag: 1.0.2 - - is-bigint@1.0.4: - dependencies: - has-bigints: 1.0.2 - is-binary-path@2.1.0: dependencies: binary-extensions: 2.3.0 - is-boolean-object@1.1.2: - dependencies: - call-bind: 1.0.7 - has-tostringtag: 1.0.2 - - is-builtin-module@3.2.1: - dependencies: - builtin-modules: 3.3.0 - - is-bun-module@1.2.1: - dependencies: - semver: 7.6.3 - - is-callable@1.2.7: {} - is-core-module@2.15.1: dependencies: hasown: 2.0.2 - is-data-view@1.0.1: - dependencies: - is-typed-array: 1.1.13 - - is-date-object@1.0.5: - dependencies: - has-tostringtag: 1.0.2 - is-extglob@2.1.1: {} - is-finalizationregistry@1.0.2: - dependencies: - call-bind: 1.0.7 - is-fullwidth-code-point@3.0.0: {} - is-generator-function@1.0.10: - dependencies: - has-tostringtag: 1.0.2 - is-glob@4.0.3: dependencies: is-extglob: 2.1.1 - is-map@2.0.3: {} - - is-negative-zero@2.0.3: {} - - is-number-object@1.0.7: - dependencies: - has-tostringtag: 1.0.2 - is-number@7.0.0: {} - is-path-inside@3.0.3: {} - - is-regex@1.1.4: - dependencies: - call-bind: 1.0.7 - has-tostringtag: 1.0.2 - - is-set@2.0.3: {} - - is-shared-array-buffer@1.0.3: - dependencies: - call-bind: 1.0.7 - - is-stream@3.0.0: {} - - is-string@1.0.7: - dependencies: - has-tostringtag: 1.0.2 - - is-symbol@1.0.4: - dependencies: - has-symbols: 1.0.3 - - is-typed-array@1.1.13: - dependencies: - which-typed-array: 1.1.15 - - is-weakmap@2.0.2: {} - - is-weakref@1.0.2: - dependencies: - call-bind: 1.0.7 - - is-weakset@2.0.3: - dependencies: - call-bind: 1.0.7 - get-intrinsic: 1.2.4 - - isarray@2.0.5: {} - isexe@2.0.0: {} - iterator.prototype@1.1.3: - dependencies: - define-properties: 1.2.1 - get-intrinsic: 1.2.4 - has-symbols: 1.0.3 - reflect.getprototypeof: 1.0.6 - set-function-name: 2.0.2 - jackspeak@3.4.3: dependencies: '@isaacs/cliui': 8.0.2 @@ -4251,41 +3095,20 @@ snapshots: js-tokens@4.0.0: {} - js-tokens@9.0.0: {} - js-yaml@4.1.0: dependencies: argparse: 2.0.1 - jsesc@0.5.0: {} - jsesc@3.0.2: {} json-buffer@3.0.1: {} - json-parse-even-better-errors@2.3.1: {} - - json-parse-even-better-errors@3.0.2: {} - json-schema-traverse@0.4.1: {} - json-schema@0.4.0: {} - json-stable-stringify-without-jsonify@1.0.1: {} - json5@1.0.2: - dependencies: - minimist: 1.2.8 - json5@2.2.3: {} - jsx-ast-utils@3.3.5: - dependencies: - array-includes: 3.1.8 - array.prototype.flat: 1.3.2 - object.assign: 4.1.5 - object.values: 1.2.0 - keyv@4.5.4: dependencies: json-buffer: 3.0.1 @@ -4301,15 +3124,6 @@ snapshots: lines-and-columns@1.2.4: {} - local-pkg@0.5.0: - dependencies: - mlly: 1.7.2 - pkg-types: 1.2.1 - - locate-path@5.0.0: - dependencies: - p-locate: 4.1.0 - locate-path@6.0.0: dependencies: p-locate: 5.0.0 @@ -4320,9 +3134,7 @@ snapshots: dependencies: js-tokens: 4.0.0 - loupe@2.3.7: - dependencies: - get-func-name: 2.0.2 + loupe@3.1.2: {} lru-cache@10.4.3: {} @@ -4330,16 +3142,14 @@ snapshots: dependencies: yallist: 3.1.1 + lucide-react@0.456.0(react@18.3.1): + dependencies: + react: 18.3.1 + magic-string@0.30.12: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 - make-error@1.3.6: {} - - memorystream@0.3.1: {} - - merge-stream@2.0.0: {} - merge2@1.4.1: {} micromatch@4.0.8: @@ -4347,10 +3157,6 @@ snapshots: braces: 3.0.3 picomatch: 2.3.1 - mimic-fn@4.0.0: {} - - min-indent@1.0.1: {} - minimatch@3.1.2: dependencies: brace-expansion: 1.1.11 @@ -4359,17 +3165,8 @@ snapshots: dependencies: brace-expansion: 2.0.1 - minimist@1.2.8: {} - minipass@7.1.2: {} - mlly@1.7.2: - dependencies: - acorn: 8.12.1 - pathe: 1.1.2 - pkg-types: 1.2.1 - ufo: 1.5.4 - ms@2.1.3: {} mz@2.7.0: @@ -4380,87 +3177,18 @@ snapshots: nanoid@3.3.7: {} - natural-compare-lite@1.4.0: {} - natural-compare@1.4.0: {} node-releases@2.0.18: {} - normalize-package-data@2.5.0: - dependencies: - hosted-git-info: 2.8.9 - resolve: 1.22.8 - semver: 5.7.2 - validate-npm-package-license: 3.0.4 - normalize-path@3.0.0: {} normalize-range@0.1.2: {} - npm-normalize-package-bin@3.0.1: {} - - npm-run-all2@6.2.3: - dependencies: - ansi-styles: 6.2.1 - cross-spawn: 7.0.3 - memorystream: 0.3.1 - minimatch: 9.0.5 - pidtree: 0.6.0 - read-package-json-fast: 3.0.2 - shell-quote: 1.8.1 - - npm-run-path@5.3.0: - dependencies: - path-key: 4.0.0 - object-assign@4.1.1: {} object-hash@3.0.0: {} - object-inspect@1.13.2: {} - - object-keys@1.1.1: {} - - object.assign@4.1.5: - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - has-symbols: 1.0.3 - object-keys: 1.1.1 - - object.entries@1.1.8: - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-object-atoms: 1.0.0 - - object.fromentries@2.0.8: - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.3 - es-object-atoms: 1.0.0 - - object.groupby@1.0.3: - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.3 - - object.values@1.2.0: - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-object-atoms: 1.0.0 - - once@1.4.0: - dependencies: - wrappy: 1.0.2 - - onetime@6.0.0: - dependencies: - mimic-fn: 4.0.0 - optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -4470,49 +3198,24 @@ snapshots: type-check: 0.4.0 word-wrap: 1.2.5 - p-limit@2.3.0: - dependencies: - p-try: 2.2.0 - p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 - p-limit@5.0.0: - dependencies: - yocto-queue: 1.1.1 - - p-locate@4.1.0: - dependencies: - p-limit: 2.3.0 - p-locate@5.0.0: dependencies: p-limit: 3.1.0 - p-try@2.2.0: {} - package-json-from-dist@1.0.1: {} parent-module@1.0.1: dependencies: callsites: 3.1.0 - parse-json@5.2.0: - dependencies: - '@babel/code-frame': 7.25.7 - error-ex: 1.3.2 - json-parse-even-better-errors: 2.3.1 - lines-and-columns: 1.2.4 - path-exists@4.0.0: {} - path-is-absolute@1.0.1: {} - path-key@3.1.1: {} - path-key@4.0.0: {} - path-parse@1.0.7: {} path-scurry@1.11.1: @@ -4520,32 +3223,18 @@ snapshots: lru-cache: 10.4.3 minipass: 7.1.2 - path-type@4.0.0: {} - pathe@1.1.2: {} - pathval@1.1.1: {} + pathval@2.0.0: {} - picocolors@1.1.0: {} + picocolors@1.1.1: {} picomatch@2.3.1: {} - pidtree@0.6.0: {} - pify@2.3.0: {} pirates@4.0.6: {} - pkg-types@1.2.1: - dependencies: - confbox: 0.1.8 - mlly: 1.7.2 - pathe: 1.1.2 - - pluralize@8.0.0: {} - - possible-typed-array-names@1.0.0: {} - postcss-import@15.1.0(postcss@8.4.47): dependencies: postcss: 8.4.47 @@ -4558,13 +3247,12 @@ snapshots: camelcase-css: 2.0.1 postcss: 8.4.47 - postcss-load-config@4.0.2(postcss@8.4.47)(ts-node@10.9.2(@swc/core@1.7.36)(@types/node@20.16.11)(typescript@5.6.3)): + postcss-load-config@4.0.2(postcss@8.4.47): dependencies: lilconfig: 3.1.2 yaml: 2.6.0 optionalDependencies: postcss: 8.4.47 - ts-node: 10.9.2(@swc/core@1.7.36)(@types/node@20.16.11)(typescript@5.6.3) postcss-nested@6.2.0(postcss@8.4.47): dependencies: @@ -4581,31 +3269,13 @@ snapshots: postcss@8.4.47: dependencies: nanoid: 3.3.7 - picocolors: 1.1.0 + picocolors: 1.1.1 source-map-js: 1.2.1 prelude-ls@1.2.1: {} - prettier-plugin-tailwindcss@0.6.8(@ianvs/prettier-plugin-sort-imports@4.3.1(prettier@3.3.3))(prettier@3.3.3): - dependencies: - prettier: 3.3.3 - optionalDependencies: - '@ianvs/prettier-plugin-sort-imports': 4.3.1(prettier@3.3.3) - prettier@3.3.3: {} - pretty-format@29.7.0: - dependencies: - '@jest/schemas': 29.6.3 - ansi-styles: 5.2.0 - react-is: 18.3.1 - - prop-types@15.8.1: - dependencies: - loose-envify: 1.4.0 - object-assign: 4.1.1 - react-is: 16.13.1 - punycode@2.3.1: {} queue-microtask@1.2.3: {} @@ -4616,12 +3286,6 @@ snapshots: react: 18.3.1 scheduler: 0.23.2 - react-is@16.13.1: {} - - react-is@18.3.1: {} - - react-refresh@0.14.2: {} - react@18.3.1: dependencies: loose-envify: 1.4.0 @@ -4630,53 +3294,10 @@ snapshots: dependencies: pify: 2.3.0 - read-package-json-fast@3.0.2: - dependencies: - json-parse-even-better-errors: 3.0.2 - npm-normalize-package-bin: 3.0.1 - - read-pkg-up@7.0.1: - dependencies: - find-up: 4.1.0 - read-pkg: 5.2.0 - type-fest: 0.8.1 - - read-pkg@5.2.0: - dependencies: - '@types/normalize-package-data': 2.4.4 - normalize-package-data: 2.5.0 - parse-json: 5.2.0 - type-fest: 0.6.0 - readdirp@3.6.0: dependencies: picomatch: 2.3.1 - reflect.getprototypeof@1.0.6: - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.3 - es-errors: 1.3.0 - get-intrinsic: 1.2.4 - globalthis: 1.0.4 - which-builtin-type: 1.1.4 - - regexp-tree@0.1.27: {} - - regexp.prototype.flags@1.5.3: - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-errors: 1.3.0 - set-function-name: 2.0.2 - - regjsparser@0.10.0: - dependencies: - jsesc: 0.5.0 - - requireindex@1.2.0: {} - resolve-from@4.0.0: {} resolve-pkg-maps@1.0.0: {} @@ -4687,123 +3308,59 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - resolve@2.0.0-next.5: - dependencies: - is-core-module: 2.15.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - reusify@1.0.4: {} - rimraf@3.0.2: - dependencies: - glob: 7.2.3 - - rollup@4.24.0: + rollup@4.25.0: dependencies: '@types/estree': 1.0.6 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.24.0 - '@rollup/rollup-android-arm64': 4.24.0 - '@rollup/rollup-darwin-arm64': 4.24.0 - '@rollup/rollup-darwin-x64': 4.24.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.24.0 - '@rollup/rollup-linux-arm-musleabihf': 4.24.0 - '@rollup/rollup-linux-arm64-gnu': 4.24.0 - '@rollup/rollup-linux-arm64-musl': 4.24.0 - '@rollup/rollup-linux-powerpc64le-gnu': 4.24.0 - '@rollup/rollup-linux-riscv64-gnu': 4.24.0 - '@rollup/rollup-linux-s390x-gnu': 4.24.0 - '@rollup/rollup-linux-x64-gnu': 4.24.0 - '@rollup/rollup-linux-x64-musl': 4.24.0 - '@rollup/rollup-win32-arm64-msvc': 4.24.0 - '@rollup/rollup-win32-ia32-msvc': 4.24.0 - '@rollup/rollup-win32-x64-msvc': 4.24.0 + '@rollup/rollup-android-arm-eabi': 4.25.0 + '@rollup/rollup-android-arm64': 4.25.0 + '@rollup/rollup-darwin-arm64': 4.25.0 + '@rollup/rollup-darwin-x64': 4.25.0 + '@rollup/rollup-freebsd-arm64': 4.25.0 + '@rollup/rollup-freebsd-x64': 4.25.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.25.0 + '@rollup/rollup-linux-arm-musleabihf': 4.25.0 + '@rollup/rollup-linux-arm64-gnu': 4.25.0 + '@rollup/rollup-linux-arm64-musl': 4.25.0 + '@rollup/rollup-linux-powerpc64le-gnu': 4.25.0 + '@rollup/rollup-linux-riscv64-gnu': 4.25.0 + '@rollup/rollup-linux-s390x-gnu': 4.25.0 + '@rollup/rollup-linux-x64-gnu': 4.25.0 + '@rollup/rollup-linux-x64-musl': 4.25.0 + '@rollup/rollup-win32-arm64-msvc': 4.25.0 + '@rollup/rollup-win32-ia32-msvc': 4.25.0 + '@rollup/rollup-win32-x64-msvc': 4.25.0 fsevents: 2.3.3 run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 - safe-array-concat@1.1.2: - dependencies: - call-bind: 1.0.7 - get-intrinsic: 1.2.4 - has-symbols: 1.0.3 - isarray: 2.0.5 - - safe-regex-test@1.0.3: - dependencies: - call-bind: 1.0.7 - es-errors: 1.3.0 - is-regex: 1.1.4 - scheduler@0.23.2: dependencies: loose-envify: 1.4.0 - semver@5.7.2: {} - semver@6.3.1: {} semver@7.6.3: {} - set-function-length@1.2.2: - dependencies: - define-data-property: 1.1.4 - es-errors: 1.3.0 - function-bind: 1.1.2 - get-intrinsic: 1.2.4 - gopd: 1.0.1 - has-property-descriptors: 1.0.2 - - set-function-name@2.0.2: - dependencies: - define-data-property: 1.1.4 - es-errors: 1.3.0 - functions-have-names: 1.2.3 - has-property-descriptors: 1.0.2 - shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 shebang-regex@3.0.0: {} - shell-quote@1.8.1: {} - - side-channel@1.0.6: - dependencies: - call-bind: 1.0.7 - es-errors: 1.3.0 - get-intrinsic: 1.2.4 - object-inspect: 1.13.2 - siginfo@2.0.0: {} signal-exit@4.1.0: {} - slash@3.0.0: {} - source-map-js@1.2.1: {} - spdx-correct@3.2.0: - dependencies: - spdx-expression-parse: 3.0.1 - spdx-license-ids: 3.0.20 - - spdx-exceptions@2.5.0: {} - - spdx-expression-parse@3.0.1: - dependencies: - spdx-exceptions: 2.5.0 - spdx-license-ids: 3.0.20 - - spdx-license-ids@3.0.20: {} - stackback@0.0.2: {} - std-env@3.7.0: {} + std-env@3.8.0: {} string-width@4.2.3: dependencies: @@ -4817,45 +3374,6 @@ snapshots: emoji-regex: 9.2.2 strip-ansi: 7.1.0 - string.prototype.matchall@4.0.11: - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.3 - es-errors: 1.3.0 - es-object-atoms: 1.0.0 - get-intrinsic: 1.2.4 - gopd: 1.0.1 - has-symbols: 1.0.3 - internal-slot: 1.0.7 - regexp.prototype.flags: 1.5.3 - set-function-name: 2.0.2 - side-channel: 1.0.6 - - string.prototype.repeat@1.0.0: - dependencies: - define-properties: 1.2.1 - es-abstract: 1.23.3 - - string.prototype.trim@1.2.9: - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.3 - es-object-atoms: 1.0.0 - - string.prototype.trimend@1.0.8: - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-object-atoms: 1.0.0 - - string.prototype.trimstart@1.0.8: - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-object-atoms: 1.0.0 - strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 @@ -4864,20 +3382,8 @@ snapshots: dependencies: ansi-regex: 6.1.0 - strip-bom@3.0.0: {} - - strip-final-newline@3.0.0: {} - - strip-indent@3.0.0: - dependencies: - min-indent: 1.0.1 - strip-json-comments@3.1.1: {} - strip-literal@2.1.0: - dependencies: - js-tokens: 9.0.0 - sucrase@3.35.0: dependencies: '@jridgewell/gen-mapping': 0.3.5 @@ -4888,17 +3394,19 @@ snapshots: pirates: 4.0.6 ts-interface-checker: 0.1.13 - supports-color@5.5.0: - dependencies: - has-flag: 3.0.0 - supports-color@7.2.0: dependencies: has-flag: 4.0.0 supports-preserve-symlinks-flag@1.0.0: {} - tailwindcss@3.4.14(ts-node@10.9.2(@swc/core@1.7.36)(@types/node@20.16.11)(typescript@5.6.3)): + tailwind-merge@2.5.4: {} + + tailwindcss-animate@1.0.7(tailwindcss@3.4.14): + dependencies: + tailwindcss: 3.4.14 + + tailwindcss@3.4.14: dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 @@ -4913,11 +3421,11 @@ snapshots: micromatch: 4.0.8 normalize-path: 3.0.0 object-hash: 3.0.0 - picocolors: 1.1.0 + picocolors: 1.1.1 postcss: 8.4.47 postcss-import: 15.1.0(postcss@8.4.47) postcss-js: 4.0.1(postcss@8.4.47) - postcss-load-config: 4.0.2(postcss@8.4.47)(ts-node@10.9.2(@swc/core@1.7.36)(@types/node@20.16.11)(typescript@5.6.3)) + postcss-load-config: 4.0.2(postcss@8.4.47) postcss-nested: 6.2.0(postcss@8.4.47) postcss-selector-parser: 6.1.2 resolve: 1.22.8 @@ -4925,8 +3433,6 @@ snapshots: transitivePeerDependencies: - ts-node - tapable@2.2.1: {} - text-table@0.2.0: {} thenify-all@1.6.0: @@ -4937,141 +3443,85 @@ snapshots: dependencies: any-promise: 1.3.0 + tiny-invariant@1.3.3: {} + + tiny-warning@1.0.3: {} + tinybench@2.9.0: {} - tinypool@0.8.4: {} + tinyexec@0.3.1: {} - tinyspy@2.2.1: {} + tinypool@1.0.1: {} - to-fast-properties@2.0.0: {} + tinyrainbow@1.2.0: {} + + tinyspy@3.0.2: {} to-regex-range@5.0.1: dependencies: is-number: 7.0.0 - ts-api-utils@1.3.0(typescript@5.6.3): + true-myth@8.0.1: {} + + ts-api-utils@1.4.0(typescript@5.6.3): dependencies: typescript: 5.6.3 ts-interface-checker@0.1.13: {} - ts-node@10.9.2(@swc/core@1.7.36)(@types/node@20.16.11)(typescript@5.6.3): + tsx@4.19.2: dependencies: - '@cspotcode/source-map-support': 0.8.1 - '@tsconfig/node10': 1.0.11 - '@tsconfig/node12': 1.0.11 - '@tsconfig/node14': 1.0.3 - '@tsconfig/node16': 1.0.4 - '@types/node': 20.16.11 - acorn: 8.12.1 - acorn-walk: 8.3.4 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.2 - make-error: 1.3.6 - typescript: 5.6.3 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 + esbuild: 0.23.1 + get-tsconfig: 4.8.1 optionalDependencies: - '@swc/core': 1.7.36 - - tsconfig-paths@3.15.0: - dependencies: - '@types/json5': 0.0.29 - json5: 1.0.2 - minimist: 1.2.8 - strip-bom: 3.0.0 - - tslib@1.14.1: {} - - tsutils@3.21.0(typescript@5.6.3): - dependencies: - tslib: 1.14.1 - typescript: 5.6.3 + fsevents: 2.3.3 type-check@0.4.0: dependencies: prelude-ls: 1.2.1 - type-detect@4.1.0: {} - - type-fest@0.20.2: {} - - type-fest@0.6.0: {} - - type-fest@0.8.1: {} - - typed-array-buffer@1.0.2: + typescript-eslint@8.13.0(eslint@9.14.0(jiti@1.21.6))(typescript@5.6.3): dependencies: - call-bind: 1.0.7 - es-errors: 1.3.0 - is-typed-array: 1.1.13 - - typed-array-byte-length@1.0.1: - dependencies: - call-bind: 1.0.7 - for-each: 0.3.3 - gopd: 1.0.1 - has-proto: 1.0.3 - is-typed-array: 1.1.13 - - typed-array-byte-offset@1.0.2: - dependencies: - available-typed-arrays: 1.0.7 - call-bind: 1.0.7 - for-each: 0.3.3 - gopd: 1.0.1 - has-proto: 1.0.3 - is-typed-array: 1.1.13 - - typed-array-length@1.0.6: - dependencies: - call-bind: 1.0.7 - for-each: 0.3.3 - gopd: 1.0.1 - has-proto: 1.0.3 - is-typed-array: 1.1.13 - possible-typed-array-names: 1.0.0 + '@typescript-eslint/eslint-plugin': 8.13.0(@typescript-eslint/parser@8.13.0(eslint@9.14.0(jiti@1.21.6))(typescript@5.6.3))(eslint@9.14.0(jiti@1.21.6))(typescript@5.6.3) + '@typescript-eslint/parser': 8.13.0(eslint@9.14.0(jiti@1.21.6))(typescript@5.6.3) + '@typescript-eslint/utils': 8.13.0(eslint@9.14.0(jiti@1.21.6))(typescript@5.6.3) + optionalDependencies: + typescript: 5.6.3 + transitivePeerDependencies: + - eslint + - supports-color typescript@5.6.3: {} - ufo@1.5.4: {} - - unbox-primitive@1.0.2: - dependencies: - call-bind: 1.0.7 - has-bigints: 1.0.2 - has-symbols: 1.0.3 - which-boxed-primitive: 1.0.2 - undici-types@6.19.8: {} - update-browserslist-db@1.1.1(browserslist@4.24.0): + unplugin@1.15.0: dependencies: - browserslist: 4.24.0 + acorn: 8.14.0 + webpack-virtual-modules: 0.6.2 + + update-browserslist-db@1.1.1(browserslist@4.24.2): + dependencies: + browserslist: 4.24.2 escalade: 3.2.0 - picocolors: 1.1.0 + picocolors: 1.1.1 uri-js@4.4.1: dependencies: punycode: 2.3.1 + use-sync-external-store@1.2.2(react@18.3.1): + dependencies: + react: 18.3.1 + util-deprecate@1.0.2: {} - v8-compile-cache-lib@3.0.1: {} - - validate-npm-package-license@3.0.4: - dependencies: - spdx-correct: 3.2.0 - spdx-expression-parse: 3.0.1 - - vite-node@1.6.0(@types/node@20.16.11): + vite-node@2.1.4(@types/node@22.9.0): dependencies: cac: 6.7.14 debug: 4.3.7 pathe: 1.1.2 - picocolors: 1.1.0 - vite: 5.4.9(@types/node@20.16.11) + vite: 5.4.10(@types/node@22.9.0) transitivePeerDependencies: - '@types/node' - less @@ -5083,42 +3533,43 @@ snapshots: - supports-color - terser - vite@5.4.9(@types/node@20.16.11): + vite@5.4.10(@types/node@22.9.0): dependencies: esbuild: 0.21.5 postcss: 8.4.47 - rollup: 4.24.0 + rollup: 4.25.0 optionalDependencies: - '@types/node': 20.16.11 + '@types/node': 22.9.0 fsevents: 2.3.3 - vitest@1.6.0(@types/node@20.16.11): + vitest@2.1.4(@types/node@22.9.0): dependencies: - '@vitest/expect': 1.6.0 - '@vitest/runner': 1.6.0 - '@vitest/snapshot': 1.6.0 - '@vitest/spy': 1.6.0 - '@vitest/utils': 1.6.0 - acorn-walk: 8.3.4 - chai: 4.5.0 + '@vitest/expect': 2.1.4 + '@vitest/mocker': 2.1.4(vite@5.4.10(@types/node@22.9.0)) + '@vitest/pretty-format': 2.1.4 + '@vitest/runner': 2.1.4 + '@vitest/snapshot': 2.1.4 + '@vitest/spy': 2.1.4 + '@vitest/utils': 2.1.4 + chai: 5.1.2 debug: 4.3.7 - execa: 8.0.1 - local-pkg: 0.5.0 + expect-type: 1.1.0 magic-string: 0.30.12 pathe: 1.1.2 - picocolors: 1.1.0 - std-env: 3.7.0 - strip-literal: 2.1.0 + std-env: 3.8.0 tinybench: 2.9.0 - tinypool: 0.8.4 - vite: 5.4.9(@types/node@20.16.11) - vite-node: 1.6.0(@types/node@20.16.11) + tinyexec: 0.3.1 + tinypool: 1.0.1 + tinyrainbow: 1.2.0 + vite: 5.4.10(@types/node@22.9.0) + vite-node: 2.1.4(@types/node@22.9.0) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 20.16.11 + '@types/node': 22.9.0 transitivePeerDependencies: - less - lightningcss + - msw - sass - sass-embedded - stylus @@ -5126,43 +3577,7 @@ snapshots: - supports-color - terser - which-boxed-primitive@1.0.2: - dependencies: - is-bigint: 1.0.4 - is-boolean-object: 1.1.2 - is-number-object: 1.0.7 - is-string: 1.0.7 - is-symbol: 1.0.4 - - which-builtin-type@1.1.4: - dependencies: - function.prototype.name: 1.1.6 - has-tostringtag: 1.0.2 - is-async-function: 2.0.0 - is-date-object: 1.0.5 - is-finalizationregistry: 1.0.2 - is-generator-function: 1.0.10 - is-regex: 1.1.4 - is-weakref: 1.0.2 - isarray: 2.0.5 - which-boxed-primitive: 1.0.2 - which-collection: 1.0.2 - which-typed-array: 1.1.15 - - which-collection@1.0.2: - dependencies: - is-map: 2.0.3 - is-set: 2.0.3 - is-weakmap: 2.0.2 - is-weakset: 2.0.3 - - which-typed-array@1.1.15: - dependencies: - available-typed-arrays: 1.0.7 - call-bind: 1.0.7 - for-each: 0.3.3 - gopd: 1.0.1 - has-tostringtag: 1.0.2 + webpack-virtual-modules@0.6.2: {} which@2.0.2: dependencies: @@ -5187,14 +3602,16 @@ snapshots: string-width: 5.1.2 strip-ansi: 7.1.0 - wrappy@1.0.2: {} - yallist@3.1.1: {} yaml@2.6.0: {} - yn@3.1.1: {} - yocto-queue@0.1.0: {} - yocto-queue@1.1.1: {} + zod@3.23.8: {} + + zustand@5.0.1(@types/react@18.3.12)(react@18.3.1)(use-sync-external-store@1.2.2(react@18.3.1)): + optionalDependencies: + '@types/react': 18.3.12 + react: 18.3.1 + use-sync-external-store: 1.2.2(react@18.3.1) diff --git a/frontend/postcss.config.cjs b/frontend/postcss.config.js similarity index 77% rename from frontend/postcss.config.cjs rename to frontend/postcss.config.js index 4df9d3b..2aa7205 100644 --- a/frontend/postcss.config.cjs +++ b/frontend/postcss.config.js @@ -1,6 +1,6 @@ -module.exports = { +export default { plugins: { - autoprefixer: {}, tailwindcss: {}, + autoprefixer: {}, }, }; diff --git a/frontend/prettier.config.mjs b/frontend/prettier.config.mjs index 58810b4..16bb77f 100644 --- a/frontend/prettier.config.mjs +++ b/frontend/prettier.config.mjs @@ -1,7 +1,7 @@ export default { plugins: [ - '@ianvs/prettier-plugin-sort-imports', - 'prettier-plugin-tailwindcss', + "@ianvs/prettier-plugin-sort-imports", + "prettier-plugin-tailwindcss", ], singleQuote: true, }; diff --git a/frontend/public/linkpulse.svg b/frontend/public/linkpulse.svg new file mode 100644 index 0000000..5444a84 --- /dev/null +++ b/frontend/public/linkpulse.svg @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/frontend/src/App.css b/frontend/src/App.css deleted file mode 100644 index dacd573..0000000 --- a/frontend/src/App.css +++ /dev/null @@ -1,20 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; - -:root { - --background-color: #fff; - --text-color: #111; -} - -@media (prefers-color-scheme: dark) { - :root { - --background-color: rgb(20, 20, 20); - --text-color: rgb(230, 230, 230); - } -} - -body { - background-color: var(--background-color); - color: var(--text-color); -} diff --git a/frontend/src/App.test.tsx b/frontend/src/App.test.tsx index dd62b30..fa9bb2b 100644 --- a/frontend/src/App.test.tsx +++ b/frontend/src/App.test.tsx @@ -1,5 +1,5 @@ -import { expect, test } from 'vitest'; +import { expect, test } from "vitest"; -test('App', () => { +test("App", () => { expect(1 + 1).toBe(2); }); diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx deleted file mode 100644 index a5bd609..0000000 --- a/frontend/src/App.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import { useEffect, useState } from 'react'; - -const backendUrl = import.meta.env.PROD - ? '/api' - : `http://${import.meta.env.VITE_BACKEND_TARGET}/api`; - -const Code = (props: JSX.IntrinsicElements['code']) => ( - -); - -type SeenIP = { - last_seen: string; - ip: string; - count: number; -}; - -export default function App() { - const [seenIps, setSeenIps] = useState([]); - const [error, setError] = useState(null); - - const refreshData = async () => { - try { - const response = await fetch(`${backendUrl}/ips`); - if (!response.ok) { - throw new Error(`Error: ${response.statusText}`); - } - const data = await response.json(); - - setSeenIps(data.ips); - setError(null); // Clear any previous errors - console.log('Data fetched:', data); - } catch (error) { - console.error('Error fetching data:', error); - setError(error.message); - } - }; - - // Refresh data on component mount and every 30 seconds - useEffect(() => { - refreshData(); - - const interval = setInterval( - () => { - refreshData(); - }, - (import.meta.env.DEV ? 3 : 30) * 1000, - ); - - return () => clearInterval(interval); - }, []); - - return ( -
-
-

LinkPulse

- - {error && ( -
- {error} -
- )} - -
- - - {error == null - ? seenIps.map((ip) => ( - - - - - - )) - : null} - -
- {ip.ip} - - {ip.count} time{ip.count > 1 ? 's' : ''} - {ip.last_seen}
-
-
-
- ); -} diff --git a/frontend/src/components/auth/form.tsx b/frontend/src/components/auth/form.tsx new file mode 100644 index 0000000..fbbca23 --- /dev/null +++ b/frontend/src/components/auth/form.tsx @@ -0,0 +1,125 @@ +import { Icons } from "@/components/icons"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { login } from "@/lib/auth"; +import { useUserStore } from "@/lib/state"; +import { cn } from "@/lib/utils"; +import { Link } from "@tanstack/react-router"; +import { HTMLAttributes, SyntheticEvent, useState } from "react"; + +interface UserAuthFormProps extends HTMLAttributes {} + +export function RegisterForm({ className, ...props }: UserAuthFormProps) { + const [isLoading, setIsLoading] = useState(false); + + async function onSubmit(event: SyntheticEvent) { + event.preventDefault(); + + setIsLoading(true); + // await login() + setIsLoading(false); + } + + return ( +
+
+
+
+ + +
+ +
+
+
+ ); +} + +export function LoginForm({ className, ...props }: UserAuthFormProps) { + const [isLoading, setIsLoading] = useState(false); + const { setUser } = useUserStore(); + + async function onSubmit(event: SyntheticEvent) { + event.preventDefault(); + + const email = (event.target as HTMLFormElement).email.value; + const password = (event.target as HTMLFormElement).password.value; + + setIsLoading(true); + const result = await login(email, password); + if (result.isOk) { + setUser(result.value); + } else { + alert("Login failed"); + } + setIsLoading(false); + } + + return ( +
+
+
+
+ + +
+
+ + +
+ +
+
+

+ + Register + {" "} + or{" "} + + Forgot Password + +

+
+ ); +} diff --git a/frontend/src/components/icons.tsx b/frontend/src/components/icons.tsx new file mode 100644 index 0000000..c833430 --- /dev/null +++ b/frontend/src/components/icons.tsx @@ -0,0 +1,157 @@ +type IconProps = React.HTMLAttributes; + +export const Icons = { + linkpulse: (props: IconProps) => ( + + + + ), + logo: (props: IconProps) => ( + + + + + + ), + twitter: (props: IconProps) => ( + + + + ), + gitHub: (props: IconProps) => ( + + + + ), + radix: (props: IconProps) => ( + + + + + + ), + aria: (props: IconProps) => ( + + + + ), + npm: (props: IconProps) => ( + + + + ), + yarn: (props: IconProps) => ( + + + + ), + pnpm: (props: IconProps) => ( + + + + ), + react: (props: IconProps) => ( + + + + ), + tailwind: (props: IconProps) => ( + + + + ), + google: (props: IconProps) => ( + + + + ), + apple: (props: IconProps) => ( + + + + ), + paypal: (props: IconProps) => ( + + + + ), + spinner: (props: IconProps) => ( + + + + ), +}; diff --git a/frontend/src/components/pages/authentication.tsx b/frontend/src/components/pages/authentication.tsx new file mode 100644 index 0000000..dea7caf --- /dev/null +++ b/frontend/src/components/pages/authentication.tsx @@ -0,0 +1,67 @@ +import { Icons } from "@/components/icons"; +import { buttonVariants } from "@/components/ui/button"; +import { cn } from "@/lib/utils"; +import { Link } from "@tanstack/react-router"; +import { ReactNode } from "react"; + +export function AgreementText() { + return ( +

+ By clicking continue, you agree to our{" "} + + Terms of Service + {" "} + and{" "} + + Privacy Policy + + . +

+ ); +} + +export default function AuthenticationPage({ + children, +}: { + children: ReactNode; +}) { + return ( +
+ + Linkpulse + +
+
+
+ + Linkpulse +
+
+ {/*
+

+ “This library has saved me countless hours of work and + helped me deliver stunning designs to my clients faster than + ever before.” +

+
Sofia Davis
+
*/} + {/*

+
*/} +
+
+
{children}
+
+ ); +} diff --git a/frontend/src/components/ui/button.tsx b/frontend/src/components/ui/button.tsx new file mode 100644 index 0000000..d09a695 --- /dev/null +++ b/frontend/src/components/ui/button.tsx @@ -0,0 +1,57 @@ +import * as React from "react"; +import { Slot } from "@radix-ui/react-slot"; +import { cva, type VariantProps } from "class-variance-authority"; + +import { cn } from "@/lib/utils"; + +const buttonVariants = cva( + "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", + { + variants: { + variant: { + default: + "bg-primary text-primary-foreground shadow hover:bg-primary/90", + destructive: + "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90", + outline: + "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground", + secondary: + "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80", + ghost: "hover:bg-accent hover:text-accent-foreground", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: "h-9 px-4 py-2", + sm: "h-8 rounded-md px-3 text-xs", + lg: "h-10 rounded-md px-8", + icon: "h-9 w-9", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + }, +); + +export interface ButtonProps + extends React.ButtonHTMLAttributes, + VariantProps { + asChild?: boolean; +} + +const Button = React.forwardRef( + ({ className, variant, size, asChild = false, ...props }, ref) => { + const Comp = asChild ? Slot : "button"; + return ( + + ); + }, +); +Button.displayName = "Button"; + +export { Button, buttonVariants }; diff --git a/frontend/src/components/ui/input.tsx b/frontend/src/components/ui/input.tsx new file mode 100644 index 0000000..7db5241 --- /dev/null +++ b/frontend/src/components/ui/input.tsx @@ -0,0 +1,22 @@ +import * as React from "react"; + +import { cn } from "@/lib/utils"; + +const Input = React.forwardRef>( + ({ className, type, ...props }, ref) => { + return ( + + ); + }, +); +Input.displayName = "Input"; + +export { Input }; diff --git a/frontend/src/components/ui/label.tsx b/frontend/src/components/ui/label.tsx new file mode 100644 index 0000000..44912af --- /dev/null +++ b/frontend/src/components/ui/label.tsx @@ -0,0 +1,24 @@ +import * as React from "react"; +import * as LabelPrimitive from "@radix-ui/react-label"; +import { cva, type VariantProps } from "class-variance-authority"; + +import { cn } from "@/lib/utils"; + +const labelVariants = cva( + "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70", +); + +const Label = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & + VariantProps +>(({ className, ...props }, ref) => ( + +)); +Label.displayName = LabelPrimitive.Root.displayName; + +export { Label }; diff --git a/frontend/src/index.css b/frontend/src/index.css new file mode 100644 index 0000000..9de0433 --- /dev/null +++ b/frontend/src/index.css @@ -0,0 +1,137 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +:root { + font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} +a:hover { + color: #535bf2; +} + +body { + margin: 0; + display: flex; + place-items: center; + min-width: 320px; + min-height: 100vh; +} + +h1 { + font-size: 3.2em; + line-height: 1.1; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} +button:hover { + border-color: #646cff; +} +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; +} + +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } + a:hover { + color: #747bff; + } + button { + background-color: #f9f9f9; + } +} + +@layer base { + :root { + --background: 0 0% 100%; + --foreground: 240 10% 3.9%; + --card: 0 0% 100%; + --card-foreground: 240 10% 3.9%; + --popover: 0 0% 100%; + --popover-foreground: 240 10% 3.9%; + --primary: 240 5.9% 10%; + --primary-foreground: 0 0% 98%; + --secondary: 240 4.8% 95.9%; + --secondary-foreground: 240 5.9% 10%; + --muted: 240 4.8% 95.9%; + --muted-foreground: 240 3.8% 46.1%; + --accent: 240 4.8% 95.9%; + --accent-foreground: 240 5.9% 10%; + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 0 0% 98%; + --border: 240 5.9% 90%; + --input: 240 5.9% 90%; + --ring: 240 10% 3.9%; + --chart-1: 12 76% 61%; + --chart-2: 173 58% 39%; + --chart-3: 197 37% 24%; + --chart-4: 43 74% 66%; + --chart-5: 27 87% 67%; + --radius: 0.5rem; + } + .dark { + --background: 240 10% 3.9%; + --foreground: 0 0% 98%; + --card: 240 10% 3.9%; + --card-foreground: 0 0% 98%; + --popover: 240 10% 3.9%; + --popover-foreground: 0 0% 98%; + --primary: 0 0% 98%; + --primary-foreground: 240 5.9% 10%; + --secondary: 240 3.7% 15.9%; + --secondary-foreground: 0 0% 98%; + --muted: 240 3.7% 15.9%; + --muted-foreground: 240 5% 64.9%; + --accent: 240 3.7% 15.9%; + --accent-foreground: 0 0% 98%; + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 0 0% 98%; + --border: 240 3.7% 15.9%; + --input: 240 3.7% 15.9%; + --ring: 240 4.9% 83.9%; + --chart-1: 220 70% 50%; + --chart-2: 160 60% 45%; + --chart-3: 30 80% 55%; + --chart-4: 280 65% 60%; + --chart-5: 340 75% 55%; + } +} + +@layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground; + } +} diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx deleted file mode 100644 index a4e3e6d..0000000 --- a/frontend/src/index.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import App from './App.tsx'; -import './App.css'; -import { StrictMode } from 'react'; -import { createRoot } from 'react-dom/client'; - -createRoot(document.getElementById('root')!).render( - - - , -); diff --git a/frontend/src/lib/auth.ts b/frontend/src/lib/auth.ts new file mode 100644 index 0000000..5064208 --- /dev/null +++ b/frontend/src/lib/auth.ts @@ -0,0 +1,81 @@ +import Result, { ok, err } from "true-myth/result"; +import { useUserStore } from "@/lib/state"; + +// Authentication on the frontend is managed by Zustand's state. +// Upon application load, a single request is made to acquire session state. +// Any route that requires authentication will redirect if a valid session is not acquired. +// The session state is stored in the user store. +// If any protected API call suddenly fails with a 401 status code, the user store is reset, a logout message is displayed, and the user is redirected to the login page. +// All redirects to the login page will carry a masked URL parameter that can be used to redirect the user back to the page they were on after logging in. + +const TARGET = !import.meta.env.DEV + ? `http://${import.meta.env.VITE_BACKEND_TARGET}` + : ""; + +type ErrorResponse = { + detail: string; +}; + +type SessionResponse = { + user: {}; +}; + +/** + * Retrieves the current session from the server. + * + * An Ok result will contain the session data, implying that the session is valid and the user is authenticated. + * An Err result will contain an error response, implying that the session is invalid or non-existent, and the user is not authenticated. + * + * @returns {Promise>} A promise that resolves to a Result object containing either the session data or an error response. + */ +export const getSession = async (): Promise< + Result +> => { + const response = await fetch(TARGET + "/api/session"); + if (response.ok) { + const user = await response.json(); + useUserStore.getState().setUser(user); + return ok({ user }); + } else { + useUserStore.getState().logout(); + const error = await response.json(); + return err({ detail: error.detail }); + } +}; + +export const isAuthenticated = async (): Promise => { + let state = useUserStore.getState(); + + if (state.initialized) return state.user !== null; + else { + const result = await getSession(); + return result.isOk; + } +}; + +type LoginResponse = { + email: string; + expiry: string; +}; + +export const login = async ( + email: string, + password: string, +): Promise> => { + const response = await fetch(TARGET + "/api/login", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ email, password }), + }); + + if (response.ok) { + const user = await response.json(); + useUserStore.getState().setUser(user); + return ok(user); + } else { + const error = await response.json(); + return err({ detail: error.detail }); + } +}; diff --git a/frontend/src/lib/state.ts b/frontend/src/lib/state.ts new file mode 100644 index 0000000..f76e1c8 --- /dev/null +++ b/frontend/src/lib/state.ts @@ -0,0 +1,21 @@ +import { create } from "zustand"; + +type UserState = { + initialized: boolean; + user: { + // TODO: This will eventually carry more user information (name, avatar, etc.) + email: string; + } | null; +}; + +type UserActions = { + setUser: (user: UserState["user"]) => void; + logout: () => void; +}; + +export const useUserStore = create((set) => ({ + initialized: false, + user: null, + setUser: (user) => set({ user, initialized: true }), + logout: () => set({ user: null }), +})); diff --git a/frontend/src/lib/utils.ts b/frontend/src/lib/utils.ts new file mode 100644 index 0000000..a5ef193 --- /dev/null +++ b/frontend/src/lib/utils.ts @@ -0,0 +1,6 @@ +import { clsx, type ClassValue } from "clsx"; +import { twMerge } from "tailwind-merge"; + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)); +} diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx new file mode 100644 index 0000000..d9ec9cc --- /dev/null +++ b/frontend/src/main.tsx @@ -0,0 +1,28 @@ +import { RouterProvider, createRouter } from "@tanstack/react-router"; +import { StrictMode } from "react"; +import ReactDOM from "react-dom/client"; +import "@/index.css"; + +// Import the generated route tree +import { routeTree } from "./routeTree.gen"; + +// Create a new router instance +const router = createRouter({ routeTree }); + +// Register the router instance for type safety +declare module "@tanstack/react-router" { + interface Register { + router: typeof router; + } +} + +// Render the app +const rootElement = document.getElementById("root")!; +if (!rootElement.innerHTML) { + const root = ReactDOM.createRoot(rootElement); + root.render( + + + , + ); +} diff --git a/frontend/src/routeTree.gen.ts b/frontend/src/routeTree.gen.ts new file mode 100644 index 0000000..36868a8 --- /dev/null +++ b/frontend/src/routeTree.gen.ts @@ -0,0 +1,162 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +import { createFileRoute } from '@tanstack/react-router' + +// Import Routes + +import { Route as rootRoute } from './routes/__root' +import { Route as RegisterImport } from './routes/register' +import { Route as LoginImport } from './routes/login' +import { Route as DashboardImport } from './routes/dashboard' + +// Create Virtual Routes + +const IndexLazyImport = createFileRoute('/')() + +// Create/Update Routes + +const RegisterRoute = RegisterImport.update({ + id: '/register', + path: '/register', + getParentRoute: () => rootRoute, +} as any) + +const LoginRoute = LoginImport.update({ + id: '/login', + path: '/login', + getParentRoute: () => rootRoute, +} as any) + +const DashboardRoute = DashboardImport.update({ + id: '/dashboard', + path: '/dashboard', + getParentRoute: () => rootRoute, +} as any) + +const IndexLazyRoute = IndexLazyImport.update({ + id: '/', + path: '/', + getParentRoute: () => rootRoute, +} as any).lazy(() => import('./routes/index.lazy').then((d) => d.Route)) + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/react-router' { + interface FileRoutesByPath { + '/': { + id: '/' + path: '/' + fullPath: '/' + preLoaderRoute: typeof IndexLazyImport + parentRoute: typeof rootRoute + } + '/dashboard': { + id: '/dashboard' + path: '/dashboard' + fullPath: '/dashboard' + preLoaderRoute: typeof DashboardImport + parentRoute: typeof rootRoute + } + '/login': { + id: '/login' + path: '/login' + fullPath: '/login' + preLoaderRoute: typeof LoginImport + parentRoute: typeof rootRoute + } + '/register': { + id: '/register' + path: '/register' + fullPath: '/register' + preLoaderRoute: typeof RegisterImport + parentRoute: typeof rootRoute + } + } +} + +// Create and export the route tree + +export interface FileRoutesByFullPath { + '/': typeof IndexLazyRoute + '/dashboard': typeof DashboardRoute + '/login': typeof LoginRoute + '/register': typeof RegisterRoute +} + +export interface FileRoutesByTo { + '/': typeof IndexLazyRoute + '/dashboard': typeof DashboardRoute + '/login': typeof LoginRoute + '/register': typeof RegisterRoute +} + +export interface FileRoutesById { + __root__: typeof rootRoute + '/': typeof IndexLazyRoute + '/dashboard': typeof DashboardRoute + '/login': typeof LoginRoute + '/register': typeof RegisterRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: '/' | '/dashboard' | '/login' | '/register' + fileRoutesByTo: FileRoutesByTo + to: '/' | '/dashboard' | '/login' | '/register' + id: '__root__' | '/' | '/dashboard' | '/login' | '/register' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren { + IndexLazyRoute: typeof IndexLazyRoute + DashboardRoute: typeof DashboardRoute + LoginRoute: typeof LoginRoute + RegisterRoute: typeof RegisterRoute +} + +const rootRouteChildren: RootRouteChildren = { + IndexLazyRoute: IndexLazyRoute, + DashboardRoute: DashboardRoute, + LoginRoute: LoginRoute, + RegisterRoute: RegisterRoute, +} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [ + "/", + "/dashboard", + "/login", + "/register" + ] + }, + "/": { + "filePath": "index.lazy.tsx" + }, + "/dashboard": { + "filePath": "dashboard.tsx" + }, + "/login": { + "filePath": "login.tsx" + }, + "/register": { + "filePath": "register.tsx" + } + } +} +ROUTE_MANIFEST_END */ diff --git a/frontend/src/routes/__root.tsx b/frontend/src/routes/__root.tsx new file mode 100644 index 0000000..c12b2eb --- /dev/null +++ b/frontend/src/routes/__root.tsx @@ -0,0 +1,11 @@ +import { createRootRoute, Outlet } from "@tanstack/react-router"; +import { TanStackRouterDevtools } from "@tanstack/router-devtools"; + +export const Route = createRootRoute({ + component: () => ( + <> + + + + ), +}); diff --git a/frontend/src/routes/dashboard.tsx b/frontend/src/routes/dashboard.tsx new file mode 100644 index 0000000..50f9804 --- /dev/null +++ b/frontend/src/routes/dashboard.tsx @@ -0,0 +1,28 @@ +import { useUserStore } from "@/lib/state"; +import { createFileRoute, redirect } from "@tanstack/react-router"; +import { isAuthenticated } from "@/lib/auth"; + +export const Route = createFileRoute("/dashboard")({ + component: RouteComponent, + beforeLoad: async ({ location }) => { + const authenticated = await isAuthenticated(); + + if (!authenticated) { + return redirect({ + to: "/login", + search: { redirect: location.href }, + }); + } + }, +}); + +function RouteComponent() { + const { user } = useUserStore(); + + return ( +
+

Dashboard

+

Welcome, {user?.email || "null"}

+
+ ); +} diff --git a/frontend/src/routes/index.lazy.tsx b/frontend/src/routes/index.lazy.tsx new file mode 100644 index 0000000..b1e03d1 --- /dev/null +++ b/frontend/src/routes/index.lazy.tsx @@ -0,0 +1,13 @@ +import { createLazyFileRoute } from "@tanstack/react-router"; + +export const Route = createLazyFileRoute("/")({ + component: Index, +}); + +function Index() { + return ( +
+

Welcome Home!

+
+ ); +} diff --git a/frontend/src/routes/login.tsx b/frontend/src/routes/login.tsx new file mode 100644 index 0000000..ed0b58b --- /dev/null +++ b/frontend/src/routes/login.tsx @@ -0,0 +1,35 @@ +import { createFileRoute, redirect } from "@tanstack/react-router"; + +import { LoginForm } from "@/components/auth/form"; +import AuthenticationPage from "@/components/pages/authentication"; +import { isAuthenticated } from "@/lib/auth"; + +export const Route = createFileRoute("/login")({ + beforeLoad: async ({ location }) => { + const authenticated = await isAuthenticated(); + + if (authenticated) { + return redirect({ + to: "/dashboard", + search: { redirect: location.href }, + }); + } + }, + component: Login, +}); + +function Login() { + return ( + +
+
+

Sign In

+

+ Enter your email & password below to login +

+
+ +
+
+ ); +} diff --git a/frontend/src/routes/register.tsx b/frontend/src/routes/register.tsx new file mode 100644 index 0000000..60e90dd --- /dev/null +++ b/frontend/src/routes/register.tsx @@ -0,0 +1,40 @@ +import { useUserStore } from "@/lib/state"; +import { createFileRoute, redirect } from "@tanstack/react-router"; + +import { RegisterForm } from "@/components/auth/form"; +import AuthenticationPage, { + AgreementText, +} from "@/components/pages/authentication"; + +export const Route = createFileRoute("/register")({ + beforeLoad: async ({ location }) => { + const isLoggedIn = useUserStore.getState().user !== null; + + if (isLoggedIn) { + return redirect({ + to: "/dashboard", + search: { redirect: location.href }, + }); + } + }, + component: Register, +}); + +function Register() { + return ( + +
+
+

+ Create an account +

+

+ Enter your email below to create your account +

+
+ + +
+
+ ); +} diff --git a/frontend/src/vite-env.d.ts b/frontend/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/frontend/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/frontend/tailwind.config.cjs b/frontend/tailwind.config.cjs deleted file mode 100644 index a5782a2..0000000 --- a/frontend/tailwind.config.cjs +++ /dev/null @@ -1,13 +0,0 @@ -/** @type {import('tailwindcss').Config} */ -module.exports = { - content: ['./src/**/*.{js,jsx,ts,tsx}', './*.html'], - darkMode: 'media', - mode: 'jit', - theme: { - extend: { - fontFamily: { - inter: ['Inter', 'sans-serif'], - }, - }, - }, -}; diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js new file mode 100644 index 0000000..2487604 --- /dev/null +++ b/frontend/tailwind.config.js @@ -0,0 +1,57 @@ +/** @type {import('tailwindcss').Config} */ +export default { + darkMode: ["class"], + content: ["./index.html", "./src/**/*.{ts,tsx,js,jsx}"], + theme: { + extend: { + borderRadius: { + lg: "var(--radius)", + md: "calc(var(--radius) - 2px)", + sm: "calc(var(--radius) - 4px)", + }, + colors: { + background: "hsl(var(--background))", + foreground: "hsl(var(--foreground))", + card: { + DEFAULT: "hsl(var(--card))", + foreground: "hsl(var(--card-foreground))", + }, + popover: { + DEFAULT: "hsl(var(--popover))", + foreground: "hsl(var(--popover-foreground))", + }, + primary: { + DEFAULT: "hsl(var(--primary))", + foreground: "hsl(var(--primary-foreground))", + }, + secondary: { + DEFAULT: "hsl(var(--secondary))", + foreground: "hsl(var(--secondary-foreground))", + }, + muted: { + DEFAULT: "hsl(var(--muted))", + foreground: "hsl(var(--muted-foreground))", + }, + accent: { + DEFAULT: "hsl(var(--accent))", + foreground: "hsl(var(--accent-foreground))", + }, + destructive: { + DEFAULT: "hsl(var(--destructive))", + foreground: "hsl(var(--destructive-foreground))", + }, + border: "hsl(var(--border))", + input: "hsl(var(--input))", + ring: "hsl(var(--ring))", + chart: { + 1: "hsl(var(--chart-1))", + 2: "hsl(var(--chart-2))", + 3: "hsl(var(--chart-3))", + 4: "hsl(var(--chart-4))", + 5: "hsl(var(--chart-5))", + }, + }, + }, + }, + plugins: [require("tailwindcss-animate")], +}; diff --git a/frontend/tsconfig.app.json b/frontend/tsconfig.app.json new file mode 100644 index 0000000..b6d4c6a --- /dev/null +++ b/frontend/tsconfig.app.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "Bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true, + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src"] +} diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index 6b6b7d7..fec8c8e 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -1,33 +1,13 @@ { + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ], "compilerOptions": { - "allowJs": true, - "allowImportingTsExtensions": true, - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "incremental": true, - "isolatedModules": true, - "jsx": "preserve", - "lib": ["dom", "dom.iterable", "esnext"], - "module": "nodenext", - "moduleResolution": "nodenext", - "noEmit": true, - "noImplicitOverride": true, - "noUnusedLocals": true, - "resolveJsonModule": true, - "skipLibCheck": true, - "strict": true, - "target": "es2017", - "types": ["vite/client"] - }, - "exclude": ["node_modules"], - "include": ["**/*.ts", "**/*.tsx"], - "ts-node": { - "transpileOnly": true, - "transpiler": "ts-node/transpilers/swc", - "files": true, - "compilerOptions": { - "module": "esnext", - "isolatedModules": false + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] } } } diff --git a/frontend/tsconfig.node.json b/frontend/tsconfig.node.json new file mode 100644 index 0000000..a1d6d41 --- /dev/null +++ b/frontend/tsconfig.node.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2022", + "lib": ["ES2023"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "Bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true, + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["vite.config.ts"] +} diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index fabde1a..76b1393 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -1,6 +1,14 @@ -import react from '@vitejs/plugin-react'; -import { defineConfig } from 'vite'; +import { TanStackRouterVite } from "@tanstack/router-plugin/vite"; +import react from "@vitejs/plugin-react-swc"; +import path from "path"; +import { defineConfig } from "vite"; +// https://vite.dev/config/ export default defineConfig({ - plugins: [react()], + plugins: [TanStackRouterVite(), react()], + resolve: { + alias: { + "@": path.resolve(__dirname, "./src"), + }, + }, });