From d618740c54ec2561dbb2819f190dafd5b222a2bf Mon Sep 17 00:00:00 2001 From: Charles Clarke Date: Wed, 16 Sep 2026 12:48:55 -0700 Subject: [PATCH 1/3] Added tech stack --- .dockerignore | 22 +++++ .env.example | 7 ++ .gitignore | 32 +++++++ AGENTS.md | 53 +++++++++++ README.md | 68 +++++++++++++- docker-compose.yml | 30 +++++++ docker/backend.Dockerfile | 21 +++++ infrastructure_plan.md | 185 ++++++++++++++++++++++++++++++++++++++ scripts/docker-smoke.sh | 15 ++++ 9 files changed, 432 insertions(+), 1 deletion(-) create mode 100644 .dockerignore create mode 100644 .env.example create mode 100644 .gitignore create mode 100644 AGENTS.md create mode 100644 docker-compose.yml create mode 100644 docker/backend.Dockerfile create mode 100644 infrastructure_plan.md create mode 100755 scripts/docker-smoke.sh diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..ca90dda --- /dev/null +++ b/.dockerignore @@ -0,0 +1,22 @@ +.git +.github +.agents +.env +.env.* +!.env.example +__pycache__/ +*.py[cod] +.pytest_cache/ +.ruff_cache/ +.pyright/ +.coverage +coverage.xml +htmlcov/ +node_modules/ +dist/ +build/ +reports/ +playwright-report/ +test-results/ +postgres-data/ + diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..3319492 --- /dev/null +++ b/.env.example @@ -0,0 +1,7 @@ +# Local PostgreSQL settings only. These defaults are intentionally non-secret. +# Copy to .env to override them; never commit a real .env file. +POSTGRES_DB=medcheck +POSTGRES_USER=medcheck +POSTGRES_PASSWORD=medcheck_local_only +POSTGRES_PORT=127.0.0.1:5432 + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..39e7cde --- /dev/null +++ b/.gitignore @@ -0,0 +1,32 @@ +# Environment and secrets +.env +.env.* +!.env.example + +# Python +__pycache__/ +*.py[cod] +.venv/ +.pytest_cache/ +.ruff_cache/ +.pyright/ +.coverage +coverage.xml +htmlcov/ + +# JavaScript and mobile +node_modules/ +dist/ +build/ +coverage/ +playwright-report/ +test-results/ + +# Docker/local services +postgres-data/ + +# Editor and OS files +.DS_Store +.idea/ +.vscode/ + diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..1a17d38 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,53 @@ +# Agent Guidance + +## Current status + +`infrastructure_plan.md` is the source of truth. The Docker foundation is in +place, but production application code has not been created. Do not introduce +pages, routes, API handlers, domain models, authentication, or business data +while performing infrastructure work. + +## Repository map + +- `infrastructure_plan.md` — approved decisions; revise it through the + planning skill before changing architectural choices. +- `docker/backend.Dockerfile` and `docker-compose.yml` — Docker tooling and + local PostgreSQL only. +- `scripts/docker-smoke.sh` — infrastructure-owned smoke test. +- `.github/workflows/` — not created yet. +- `backend/`, `web/`, `mobile/`, `tests/`, and `docs/` — not created yet. +- `.agents/skills/` — project-specific skills and instructions. + +## Required reading and skill selection + +Before changing files, read `infrastructure_plan.md`, this file, and relevant +local instructions. Use `infra-planner` for plan decisions, `infra-builder` +for infrastructure, `spec-driven-development` and `incremental-implementation` +for application work, `test-driven-development` for behavior changes, +`test-in-browser` or `browser-testing-with-devtools` for web verification, +`security-and-hardening` for untrusted-data/auth work, +`documentation-and-adrs` for durable decisions, `ci-cd-and-automation` for +workflows, `code-review-and-quality` before merging, and +`git-workflow-and-versioning` for every change. + +## Docker lifecycle + +Run `docker compose up --detach postgres` to start the local database and +`docker compose down --volumes` to stop it and remove its named volume. Run +`./scripts/docker-smoke.sh` for a disposable readiness test; it always cleans +up its Compose project and volume. Never place real secrets in `.env`, images, +workflow logs, or tracked files. + +## Verification and change checklist + +For Docker changes, run: + +```bash +docker build --file docker/backend.Dockerfile --tag medcheck-backend-tooling . +docker compose config --quiet +./scripts/docker-smoke.sh +git diff --check +``` + +Keep CI commands equivalent once workflows are added. Update README and this +file whenever paths, setup commands, services, or verification steps change. diff --git a/README.md b/README.md index 982a73e..0bdd95c 100644 --- a/README.md +++ b/README.md @@ -1 +1,67 @@ -# TechStartup-Template \ No newline at end of file +# Medcheck + +## Status + +Infrastructure setup has begun. The repository currently provides a pinned +Docker development-tooling image and a local PostgreSQL service; no production +Django, React, or React Native application code exists yet. + +## Repository map + +- `docker/backend.Dockerfile` — non-root Python and uv tooling image; it is not + a runnable application image until a backend entrypoint is implemented. +- `docker-compose.yml` — local PostgreSQL 17.6 service with a named volume and + readiness health check. +- `scripts/docker-smoke.sh` — disposable PostgreSQL readiness and `SELECT 1` + smoke test. +- `infrastructure_plan.md` — the approved infrastructure plan and source of + truth for future configuration. +- `.agents/skills/` — local agent skills. +- `backend/`, `web/`, `mobile/`, and `tests/` — not created yet. + +## Getting Started + +1. Install [Docker Desktop](https://www.docker.com/products/docker-desktop/) + or Docker Engine with Compose v2, then confirm `docker version` and + `docker compose version` succeed. +2. Optionally copy the non-secret local database defaults: + + ```bash + cp .env.example .env + ``` + +3. Build the development-tooling image: + + ```bash + docker build --file docker/backend.Dockerfile --tag medcheck-backend-tooling . + ``` + +4. Start PostgreSQL locally: + + ```bash + docker compose up --detach postgres + ``` + +5. Verify and clean up the Docker foundation: + + ```bash + ./scripts/docker-smoke.sh + docker compose down --volumes + ``` + +The local database is exposed only on `127.0.0.1:5432` by default. Change +`POSTGRES_PORT` in an untracked `.env` if that port is occupied. Reset local +database data with `docker compose down --volumes`. + +Python, uv, Node.js/pnpm, Android Studio/SDK, and Xcode remain host +prerequisites for their respective future application development workflows. +Docker does not replace native mobile SDKs, signing, or notarization. + +## Troubleshooting + +- **Docker socket permission denied:** ensure Docker Desktop/Engine is running + and that your user has permission to use the Docker daemon. +- **Port 5432 is occupied:** set `POSTGRES_PORT=127.0.0.1:5433` in `.env` and + restart the Compose service. +- **A stale database is causing unexpected results:** run `docker compose down + --volumes` before starting again. diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..b7412dc --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,30 @@ +name: medcheck + +services: + postgres: + image: postgres:17.6-bookworm + environment: + POSTGRES_DB: ${POSTGRES_DB:-medcheck} + POSTGRES_USER: ${POSTGRES_USER:-medcheck} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-medcheck_local_only} + PGDATA: /var/lib/postgresql/data/pgdata + ports: + - "${POSTGRES_PORT:-127.0.0.1:5432}:5432" + volumes: + - postgres-data:/var/lib/postgresql/data + networks: + - local + healthcheck: + test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"] + interval: 5s + timeout: 3s + retries: 12 + start_period: 5s + +volumes: + postgres-data: + +networks: + local: + driver: bridge + diff --git a/docker/backend.Dockerfile b/docker/backend.Dockerfile new file mode 100644 index 0000000..1cb54e8 --- /dev/null +++ b/docker/backend.Dockerfile @@ -0,0 +1,21 @@ +# syntax=docker/dockerfile:1.7 +# Development-tooling base image only. A runnable Django entrypoint belongs to +# the future backend application, not to infrastructure scaffolding. +FROM ghcr.io/astral-sh/uv:0.9.17 AS uv + +FROM python:3.13.11-slim-bookworm AS development + +ENV PYTHONDONTWRITEBYTECODE=1 \ + PYTHONUNBUFFERED=1 \ + UV_LINK_MODE=copy + +COPY --from=uv /uv /uvx /bin/ + +RUN groupadd --gid 10001 app \ + && useradd --uid 10001 --gid app --create-home --shell /usr/sbin/nologin app + +WORKDIR /workspace/backend +USER app + +# This proves the pinned toolchain is usable without inventing an app project. +CMD ["uv", "--version"] diff --git a/infrastructure_plan.md b/infrastructure_plan.md new file mode 100644 index 0000000..b3c80a3 --- /dev/null +++ b/infrastructure_plan.md @@ -0,0 +1,185 @@ +# Infrastructure Plan + +> Planning only. This document describes future infrastructure work. No installations, configuration changes, containers, workflows, deployments, or other implementation files were created by the infrastructure-planning process. + +## 1. Project and User Experience + +- **Application:** Personal, account-based application with web and mobile clients. +- **Primary users:** Individual users managing their own data. +- **Primary user task:** Not yet specified; the platform supports personal structured data and account workflows. +- **Selected platform:** React web application plus React Native mobile applications for iOS and Android. +- **User-experience rationale:** Provides a consistent service on browsers and mobile devices while keeping the backend in Python. +- **Required operating systems, browsers, or devices:** Current major browsers, supported iOS versions, and supported Android versions. +- **Offline or native-device requirements:** No strong offline requirement confirmed; mobile app release builds require native platform tooling. + +## 2. Connectivity and Application Shape + +- **Connectivity model:** Single-user web-enabled. +- **Accounts and authentication:** One account per user; authentication is required. Choose a maintained Django-compatible authentication approach during implementation. +- **Backend required:** Yes: a single Django application exposes the API and owns account data. +- **Cross-device persistence:** Hosted PostgreSQL is the source of truth. +- **Interaction between accounts:** None planned; user data remains private to its owner. +- **Primary application components:** Django API, React web client, React Native iOS/Android client, and PostgreSQL. + +## 3. Selected Technology Stack + +| Area | Selected technology | Purpose | Version policy | +|---|---|---|---| +| Primary language | Python | Backend application code | Supported stable Python release compatible with Django | +| Web language | TypeScript | Type-safe React web client | Supported stable TypeScript | +| Mobile language | TypeScript | Type-safe React Native client | Supported stable TypeScript | +| Application framework | Django with Django REST Framework | Account-aware API and backend | Current supported Django and DRF releases | +| Web framework | React with Vite | Browser client and static build | Current supported React and Vite releases | +| Mobile framework | React Native | iOS and Android client | Current supported React Native release | +| Python package manager | uv | Reproducible Python dependency management | Current supported release | +| JavaScript package manager | pnpm | Reproducible web and mobile dependencies | Current supported release | +| Build or packaging tool | Vite; React Native platform tooling | Build web assets and mobile release artifacts | Versions pinned by lockfiles | +| API layer | REST over HTTPS | Single API for web and mobile clients | Version endpoints when breaking changes are needed | + +## 4. Storage and Persistence + +- **Storage model:** Hosted relational storage. +- **Primary data store:** Managed PostgreSQL. +- **User files or object storage:** None selected; add managed object storage only if uploads are introduced. +- **Local-development storage:** PostgreSQL service container with a named volume. +- **Production hosting model:** Managed PostgreSQL separate from the backend application container. +- **Schema and migration approach:** Django migrations, reviewed and applied as part of a controlled release. +- **Backup, export, or recovery approach:** Enable managed-provider automated backups and document a user-data export path before launch. +- **Secrets and connection-string approach:** Use environment-provided secrets; never commit database URLs, credentials, or Django secret keys. +- **Reason this storage fits the access pattern:** PostgreSQL provides reliable, structured, hosted data for one user's account across all clients. + +## 5. Testing Tools + +| Test layer | Tool or library | Planned scope | Planned execution point | +|---|---|---|---| +| Unit | pytest and Django test utilities | Backend domain logic, views, serializers, and permissions | Local and pull requests | +| Integration | pytest, Django test client, Testcontainers for PostgreSQL | API, migration, and real-database behavior | Local and pull requests | +| Web component | Jest and React Testing Library | React rendering, accessibility, and interaction | Local and pull requests | +| Mobile component | Jest and React Native Testing Library | Mobile component behavior | Local and pull requests | +| Web end-to-end | Playwright | Critical account and primary user workflows | Pull requests and releases | +| Mobile end-to-end | Maestro | Critical iOS/Android workflows on supported emulators | Release and scheduled checks | + +## 6. Test Analysis + +| Capability | Tool | Planned policy | +|---|---|---| +| Backend coverage | coverage.py with pytest | Collect on pull requests and retain reports | +| Client coverage | Jest coverage (V8) | Collect on pull requests and retain reports | +| Coverage threshold or regression rule | Per-project modest threshold, initially agreed before enforcement | Block pull requests that fall below the agreed baseline | +| Mutation testing | Not initially selected | Reassess for critical backend logic after core workflows stabilize | +| Reporting | GitHub Actions artifacts and pull-request summaries | Preserve coverage output for failed or reviewed runs | + +## 7. Static Analysis and Security + +| Check | Tool | Planned enforcement | +|---|---|---| +| Python formatting and linting | Ruff | Blocking pull-request check | +| Python type checking | Pyright | Blocking pull-request check | +| Web/mobile formatting | Prettier | Blocking pull-request verification | +| Web/mobile linting | ESLint | Blocking pull-request check | +| Web/mobile type checking | TypeScript compiler | Blocking pull-request check | +| Dependency vulnerability scanning | Dependabot | Automated update proposals and review | +| Secret scanning | Gitleaks | Blocking pull-request and release check | +| Static security analysis | Bandit, Semgrep, and CodeQL | Bandit/Semgrep on pull requests; CodeQL scheduled and on release | +| Container scanning | Trivy | Scan backend image before publication | + +## 8. Development Technologies Requiring Manual Installation + +These are developer-workstation prerequisites that will not be supplied by the planned Docker environment. + +| Technology | Why it is needed | Required on which machines | Version policy | Planned installation or verification method | Why Docker does not provide it | +|---|---|---|---|---|---| +| Git | Source control | All developer machines | Supported current release | Future documented setup check | Repository work happens on the host | +| Docker Desktop or Docker Engine | Local containers | Developers working on backend/database | Supported current release | Future documented setup check | Docker is the host container runtime | +| Node.js and pnpm | React and React Native development | Web/mobile developers and CI runners | Supported Node LTS | Future documented setup check | Needed for host-facing client toolchains | +| Python and uv | Django local development | Backend developers and CI runners | Supported Python release | Future documented setup check | Needed for editor integration and non-container workflows | +| Android Studio and Android SDK | Android emulators and signed builds | Android release/development machines | React Native-compatible SDK | Future documented setup check | Android emulator, SDK, and signing integrate with the host | +| Xcode and Apple tooling | iOS simulator and signed builds | macOS/iOS release machines | React Native-compatible Xcode | Future documented setup check | Apple requires macOS-native signing and packaging | + +### Host tools intentionally not required + +- **Not required because Docker supplies them:** Local PostgreSQL server installation. +- **Not required for this platform:** Desktop-native packaging toolchains and decentralized-storage software. + +## 9. Docker Plan + +- **Planned Docker role:** Development and production deployment for the Django backend. +- **Future files that would be created during implementation:** Backend `Dockerfile`, development Compose file, `.dockerignore`, and environment-variable templates. +- **Planned images and services:** A Django backend image and local PostgreSQL service; production uses managed PostgreSQL. +- **Development container behavior:** Bind-mount backend source; use a named volume for PostgreSQL data; run dependencies within the planned development image. +- **Ports:** Document backend and PostgreSQL ports in future Compose configuration; bind database access locally only. +- **Bind mounts and named volumes:** Backend source bind mount for development; named volume for local database persistence. +- **Environment-variable and secret handling:** Local non-secret templates only; production values originate in protected hosting and GitHub environments. +- **Local database or service containers:** PostgreSQL only unless a later feature adds a justified service. +- **Production image or non-container release path:** Multi-stage, minimal, non-root backend image; Vite build deploys static web files; mobile apps use native store builds. +- **Build stages and hardening:** Multi-stage build, non-root runtime user, minimal runtime image, `.dockerignore`, health check, and no embedded secrets. +- **Planned future development command:** Document a future Compose command after Compose files exist; do not run it during planning. +- **Planned future production or packaging command:** Document future image build and mobile packaging commands after their configuration exists; do not run them during planning. + +## 10. GitHub Actions Plan + +### A. Automated pull-request checks + +- **Future workflow file:** `.github/workflows/pr-checks.yml` +- **Trigger:** `pull_request`. +- **Runner or matrix:** Ubuntu runner for backend, web, database integration, and web E2E; macOS and/or Android-capable runner only when mobile E2E is practical and budgeted. +- **Permissions:** Read-only repository contents; grant only the minimal permissions required to report checks or upload artifacts. +- **Planned jobs in order:** + 1. Checkout, set up pinned Python and Node LTS, restore dependency caches, and perform lockfile-enforced installs. + 2. Verify Ruff, Pyright, Prettier, ESLint, and TypeScript checks. + 3. Run backend unit/integration tests with PostgreSQL/Testcontainers and client component tests; collect coverage. + 4. Build Django assets as applicable and Vite web client; run Playwright critical workflows. + 5. Run Gitleaks, Bandit, Semgrep, dependency checks, and selected CodeQL analysis; upload reports and failure artifacts. +- **Service containers:** Prefer Testcontainers for real PostgreSQL integration tests; use a GitHub service container only if faster and equivalent. +- **Caching:** Cache uv and pnpm stores using lockfile keys; cache Playwright browsers using a versioned key. +- **Coverage and analysis reporting:** Publish coverage summaries and retain raw reports as artifacts; enforce the agreed modest threshold. +- **Failure artifacts:** Playwright traces/screenshots, test logs, coverage reports, and relevant scan reports. +- **Checks that should block merging:** Lockfile installs, formatting, lint/type checks, tests, threshold, build, Playwright critical path, Gitleaks, Bandit, and Semgrep. +- **Proposed branch-protection settings:** Require the blocking checks, one approving review, an up-to-date branch, and no unresolved conversations. + +### B. New-release deployment + +- **Future workflow file:** `.github/workflows/release.yml` +- **Release trigger:** Protected `v*` tag or `workflow_dispatch` targeting a protected production environment. +- **Release destination:** Managed hosting for Django backend and React web client; Apple App Store Connect for iOS; Google Play for Android. +- **Runner or matrix:** Ubuntu for validation, image build/scan, backend deployment, and web deployment; macOS for iOS signing/build; Android-capable runner for Android signing/build. +- **Planned jobs in order:** + 1. Validate the release commit using the required checks and build backend, web, iOS, and Android artifacts. + 2. Scan the backend image, publish it to the selected registry, then deploy backend and static web assets after protected-environment approval. + 3. Apply reviewed Django migrations once, run smoke checks, sign mobile builds, and upload them to App Store Connect and Google Play. + 4. Publish GitHub Release notes with checksums and links to release artifacts where appropriate. +- **Build artifacts:** Backend container digest, web build identifier, signed iOS archive, signed Android app bundle, checksums, and release notes. +- **Signing, notarization, or store requirements:** Apple Developer account, App Store Connect credentials/certificates/profiles, Google Play developer account and signing key, and protected secret storage. +- **Database migration step:** Run controlled Django migrations after a verified backup point and before traffic relies on schema changes. +- **Environment approval:** Use a protected GitHub `production` environment for backend/web deployment and release credentials. +- **Post-deployment verification:** Authenticated and unauthenticated health checks plus critical web API smoke tests; confirm store upload status. +- **Failed-release or rollback approach:** Redeploy the prior backend image and web build; use backward-compatible migrations or a reviewed migration recovery procedure; halt store rollout when needed. + +### GitHub configuration required later + +| Name | Type | Purpose | +|---|---|---| +| `production` | GitHub environment | Protected approval boundary for production deployment | +| `DATABASE_URL` | Secret | Production PostgreSQL connection string | +| `DJANGO_SECRET_KEY` | Secret | Django cryptographic secret | +| `DEPLOY_*` | Secret/token | Managed-hosting and container-registry deployment credentials | +| `APPLE_*` | Secret/certificate/account | App Store Connect API credentials, signing certificates, and provisioning data | +| `GOOGLE_PLAY_*` | Secret/account | Google Play service account credential and Android signing material | +| `CODEQL` configuration | Repository security configuration | Enable scheduled code scanning results | + +## 11. Planned Repository Artifacts - Not Created by This Skill + +- [ ] Backend application manifest/project file and Python lockfile. +- [ ] Web and mobile package manifests and pnpm lockfile. +- [ ] Backend, web, and mobile test configuration. +- [ ] Ruff, Pyright, Prettier, ESLint, TypeScript, Bandit, Semgrep, and Gitleaks configuration. +- [ ] Backend `Dockerfile`, Compose file, `.dockerignore`, and non-secret environment template. +- [ ] `.github/workflows/pr-checks.yml`. +- [ ] `.github/workflows/release.yml`. +- [ ] Managed-hosting and mobile-store release configuration. + +## 12. Assumptions and Open Items + +- **Assumptions:** The application handles private personal data, requires normal account authentication, does not currently require uploads, collaboration, or offline-first synchronization, and will use one deployable Django backend rather than microservices. +- **Decisions still requiring an external account, credential, certificate, or organizational approval:** Hosting provider and container registry; PostgreSQL provider; Apple Developer/App Store Connect account and signing assets; Google Play developer account and Android signing key; production-domain ownership. +- **Items to confirm before implementation begins:** Primary user workflow and data model, authentication provider/method, privacy and retention requirements, exact supported OS/browser versions, hosting and registry providers, coverage threshold, and mobile release ownership. diff --git a/scripts/docker-smoke.sh b/scripts/docker-smoke.sh new file mode 100755 index 0000000..582520d --- /dev/null +++ b/scripts/docker-smoke.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +compose=(docker compose -p medcheck-infra-smoke -f docker-compose.yml) + +cleanup() { + "${compose[@]}" down --volumes --remove-orphans +} +trap cleanup EXIT + +"${compose[@]}" config --quiet +"${compose[@]}" up --detach --wait postgres +"${compose[@]}" exec --no-TTY postgres \ + psql --username "${POSTGRES_USER:-medcheck}" --dbname "${POSTGRES_DB:-medcheck}" \ + --set ON_ERROR_STOP=1 --command 'SELECT 1;' From ca4b42a9fe7e17cb68451f8dbf569d2e34ab139b Mon Sep 17 00:00:00 2001 From: Charles Clarke Date: Mon, 21 Sep 2026 12:31:49 -0700 Subject: [PATCH 2/3] switched to mobile only --- .dockerignore | 30 +- .github/dependabot.yml | 18 + .github/workflows/pr-checks.yml | 85 + .gitignore | 4 +- AGENTS.md | 19 +- README.md | 43 +- backend/.python-version | 1 + backend/pyproject.toml | 45 + .../tests/infrastructure/test_toolchain.py | 9 + backend/uv.lock | 528 ++ docker/backend.Dockerfile | 5 +- infrastructure_plan.md | 66 +- web/.prettierignore | 3 + web/eslint.config.mjs | 17 + web/jest.config.cjs | 5 + web/package.json | 36 + web/playwright.config.ts | 4 + web/pnpm-lock.yaml | 5143 +++++++++++++++++ web/tests/e2e/.gitkeep | 0 web/tests/infrastructure/toolchain.test.cjs | 5 + web/tests/infrastructure/toolchain.ts | 2 + web/tsconfig.json | 11 + 22 files changed, 6006 insertions(+), 73 deletions(-) create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/pr-checks.yml create mode 100644 backend/.python-version create mode 100644 backend/pyproject.toml create mode 100644 backend/tests/infrastructure/test_toolchain.py create mode 100644 backend/uv.lock create mode 100644 web/.prettierignore create mode 100644 web/eslint.config.mjs create mode 100644 web/jest.config.cjs create mode 100644 web/package.json create mode 100644 web/playwright.config.ts create mode 100644 web/pnpm-lock.yaml create mode 100644 web/tests/e2e/.gitkeep create mode 100644 web/tests/infrastructure/toolchain.test.cjs create mode 100644 web/tests/infrastructure/toolchain.ts create mode 100644 web/tsconfig.json diff --git a/.dockerignore b/.dockerignore index ca90dda..a252907 100644 --- a/.dockerignore +++ b/.dockerignore @@ -4,19 +4,19 @@ .env .env.* !.env.example -__pycache__/ +.venv +**/.venv +__pycache__ +**/__pycache__ *.py[cod] -.pytest_cache/ -.ruff_cache/ -.pyright/ -.coverage -coverage.xml -htmlcov/ -node_modules/ -dist/ -build/ -reports/ -playwright-report/ -test-results/ -postgres-data/ - +node_modules +**/node_modules +.pnpm-store +**/.pnpm-store +dist +build +coverage +**/coverage +playwright-report +test-results +postgres-data diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..50f0d3f --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,18 @@ +version: 2 +updates: + - package-ecosystem: "uv" + directory: "/backend" + schedule: + interval: "weekly" + - package-ecosystem: "npm" + directory: "/web" + schedule: + interval: "weekly" + - package-ecosystem: "docker" + directory: "/" + schedule: + interval: "weekly" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml new file mode 100644 index 0000000..1307046 --- /dev/null +++ b/.github/workflows/pr-checks.yml @@ -0,0 +1,85 @@ +name: Pull-request checks + +on: + pull_request: + +permissions: + contents: read + +jobs: + secrets: + name: Secret scan + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: gitleaks/gitleaks-action@v2 + + backend: + name: Backend tooling + runs-on: ubuntu-latest + defaults: + run: + working-directory: backend + steps: + - uses: actions/checkout@v4 + - uses: astral-sh/setup-uv@v5 + with: + enable-cache: true + cache-dependency-glob: backend/uv.lock + - uses: actions/setup-python@v5 + with: + python-version-file: backend/.python-version + - name: Install locked dependencies + run: uv sync --all-groups --frozen + - name: Check formatting + run: uv run ruff format --check . + - name: Lint + run: uv run ruff check . + - name: Type check + run: uv run pyright + - name: Run infrastructure tests with coverage + run: uv run pytest --cov=tests --cov-report=xml + - name: Scan Python infrastructure + run: uv run bandit --quiet --recursive tests + - name: Upload backend coverage + if: always() + uses: actions/upload-artifact@v4 + with: + name: backend-coverage + path: backend/coverage.xml + if-no-files-found: ignore + + web: + name: Web tooling + runs-on: ubuntu-latest + defaults: + run: + working-directory: web + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22.14.0 + - name: Enable Corepack + run: corepack enable + - uses: actions/setup-node@v4 + with: + cache: pnpm + cache-dependency-path: web/pnpm-lock.yaml + - name: Install locked dependencies + run: pnpm install --frozen-lockfile + - name: Check formatting + run: pnpm format:check + - name: Lint + run: pnpm lint + - name: Type check + run: pnpm typecheck + - name: Run infrastructure tests with coverage + run: pnpm test + - name: Upload web coverage + if: always() + uses: actions/upload-artifact@v4 + with: + name: web-coverage + path: web/coverage + if-no-files-found: ignore diff --git a/.gitignore b/.gitignore index 39e7cde..1fc2dbd 100644 --- a/.gitignore +++ b/.gitignore @@ -14,13 +14,14 @@ __pycache__/ coverage.xml htmlcov/ -# JavaScript and mobile +# JavaScript node_modules/ dist/ build/ coverage/ playwright-report/ test-results/ +.pnpm-store/ # Docker/local services postgres-data/ @@ -29,4 +30,3 @@ postgres-data/ .DS_Store .idea/ .vscode/ - diff --git a/AGENTS.md b/AGENTS.md index 1a17d38..c1c7c5f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,8 +2,8 @@ ## Current status -`infrastructure_plan.md` is the source of truth. The Docker foundation is in -place, but production application code has not been created. Do not introduce +`infrastructure_plan.md` is the source of truth. The web-only tooling and Docker +foundation are in place, but production application code has not been created. Do not introduce pages, routes, API handlers, domain models, authentication, or business data while performing infrastructure work. @@ -11,11 +11,16 @@ while performing infrastructure work. - `infrastructure_plan.md` — approved decisions; revise it through the planning skill before changing architectural choices. -- `docker/backend.Dockerfile` and `docker-compose.yml` — Docker tooling and - local PostgreSQL only. +- `docker/backend.Dockerfile`, `docker-compose.yml`, and `.dockerignore` — + Docker tooling and local PostgreSQL only. - `scripts/docker-smoke.sh` — infrastructure-owned smoke test. -- `.github/workflows/` — not created yet. -- `backend/`, `web/`, `mobile/`, `tests/`, and `docs/` — not created yet. +- `backend/` — Python dependency/tool configuration and infrastructure-only tests; + no Django application package exists yet. +- `web/` — React/Vite dependency/tool configuration and infrastructure-only tests; + no React application entrypoint exists yet. +- `.github/workflows/pr-checks.yml` — web-only pull-request quality checks. +- `.github/workflows/release.yml` — not created; it requires a selected hosting provider. +- `docs/` — not created yet. - `.agents/skills/` — project-specific skills and instructions. ## Required reading and skill selection @@ -46,6 +51,8 @@ For Docker changes, run: docker build --file docker/backend.Dockerfile --tag medcheck-backend-tooling . docker compose config --quiet ./scripts/docker-smoke.sh +(cd backend && uv run ruff format --check . && uv run ruff check . && uv run pyright && uv run pytest --cov=tests) +(cd web && pnpm format:check && pnpm lint && pnpm typecheck && pnpm test) git diff --check ``` diff --git a/README.md b/README.md index 0bdd95c..76b322c 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@ ## Status -Infrastructure setup has begun. The repository currently provides a pinned -Docker development-tooling image and a local PostgreSQL service; no production -Django, React, or React Native application code exists yet. +The repository has a web-only development foundation: pinned backend and web +tooling, a local PostgreSQL service, and pull-request checks. No production +Django or React application code exists yet. ## Repository map @@ -14,37 +14,54 @@ Django, React, or React Native application code exists yet. readiness health check. - `scripts/docker-smoke.sh` — disposable PostgreSQL readiness and `SELECT 1` smoke test. +- `backend/` — Python/Django tooling, locked dependencies, and infrastructure + probes; no Django project or API code exists yet. +- `web/` — React/Vite tooling, locked dependencies, and infrastructure probes; + no page, component, or Vite entrypoint exists yet. +- `.github/workflows/pr-checks.yml` — web-only infrastructure quality checks. +- `.github/dependabot.yml` — weekly dependency-update configuration. - `infrastructure_plan.md` — the approved infrastructure plan and source of truth for future configuration. - `.agents/skills/` — local agent skills. -- `backend/`, `web/`, `mobile/`, and `tests/` — not created yet. +- `docs/` and production application source directories — not created yet. ## Getting Started 1. Install [Docker Desktop](https://www.docker.com/products/docker-desktop/) - or Docker Engine with Compose v2, then confirm `docker version` and - `docker compose version` succeed. + or Docker Engine with Compose v2, [Python 3.13](https://www.python.org/downloads/), + [uv](https://docs.astral.sh/uv/getting-started/installation/), and Node.js + 22 LTS with Corepack enabled. The Docker image supplies Python and uv only + for Docker work; host tools support editor and local quality-check workflows. 2. Optionally copy the non-secret local database defaults: ```bash cp .env.example .env ``` -3. Build the development-tooling image: +3. Install the locked tooling dependencies: + + ```bash + (cd backend && uv sync --all-groups --frozen) + (cd web && corepack enable && pnpm install --frozen-lockfile) + ``` + +4. Build the development-tooling image: ```bash docker build --file docker/backend.Dockerfile --tag medcheck-backend-tooling . ``` -4. Start PostgreSQL locally: +5. Start PostgreSQL locally: ```bash docker compose up --detach postgres ``` -5. Verify and clean up the Docker foundation: +6. Run the available infrastructure checks and clean up the Docker foundation: ```bash + (cd backend && uv run ruff format --check . && uv run ruff check . && uv run pyright && uv run pytest --cov=tests) + (cd web && pnpm format:check && pnpm lint && pnpm typecheck && pnpm test) ./scripts/docker-smoke.sh docker compose down --volumes ``` @@ -53,9 +70,9 @@ The local database is exposed only on `127.0.0.1:5432` by default. Change `POSTGRES_PORT` in an untracked `.env` if that port is occupied. Reset local database data with `docker compose down --volumes`. -Python, uv, Node.js/pnpm, Android Studio/SDK, and Xcode remain host -prerequisites for their respective future application development workflows. -Docker does not replace native mobile SDKs, signing, or notarization. +Vite builds and Playwright end-to-end tests are intentionally unavailable until +the future React application supplies an entrypoint and workflows. A production +release workflow is also deferred until a hosting provider is selected. ## Troubleshooting @@ -65,3 +82,5 @@ Docker does not replace native mobile SDKs, signing, or notarization. restart the Compose service. - **A stale database is causing unexpected results:** run `docker compose down --volumes` before starting again. +- **`uv` or `pnpm` is missing:** install the host prerequisite from the links + above, then rerun the locked install command. diff --git a/backend/.python-version b/backend/.python-version new file mode 100644 index 0000000..2c45fe3 --- /dev/null +++ b/backend/.python-version @@ -0,0 +1 @@ +3.13.11 diff --git a/backend/pyproject.toml b/backend/pyproject.toml new file mode 100644 index 0000000..1b603d7 --- /dev/null +++ b/backend/pyproject.toml @@ -0,0 +1,45 @@ +[project] +name = "medcheck-backend" +version = "0.0.0" +description = "Infrastructure-only backend tooling for Medcheck." +requires-python = ">=3.13,<3.14" +dependencies = [ + "Django>=5.2,<5.3", + "djangorestframework>=3.16,<3.17", + "psycopg[binary]>=3.2,<3.3", +] + +[dependency-groups] +dev = [ + "bandit>=1.8,<2", + "pyright>=1.1,<2", + "pytest>=8.3,<9", + "pytest-cov>=6,<7", + "pytest-django>=4.9,<5", + "ruff>=0.9,<1", + "testcontainers[postgres]>=4.9,<5", +] + +[tool.pytest.ini_options] +testpaths = ["tests"] +addopts = "--strict-markers" + +[tool.coverage.run] +branch = true +source = ["tests"] + +[tool.coverage.report] +show_missing = true +skip_empty = true + +[tool.ruff] +target-version = "py313" +line-length = 100 + +[tool.ruff.lint] +select = ["E", "F", "I", "UP"] + +[tool.pyright] +pythonVersion = "3.13" +include = ["tests"] +typeCheckingMode = "basic" diff --git a/backend/tests/infrastructure/test_toolchain.py b/backend/tests/infrastructure/test_toolchain.py new file mode 100644 index 0000000..23d67a8 --- /dev/null +++ b/backend/tests/infrastructure/test_toolchain.py @@ -0,0 +1,9 @@ +"""Infrastructure-only dependency smoke checks; application tests belong elsewhere.""" + +from importlib.metadata import version + + +def test_backend_toolchain_dependencies_are_installed() -> None: + # Test assertions are not production input validation. + assert version("Django") # nosec B101 + assert version("djangorestframework") # nosec B101 diff --git a/backend/uv.lock b/backend/uv.lock new file mode 100644 index 0000000..7c71063 --- /dev/null +++ b/backend/uv.lock @@ -0,0 +1,528 @@ +version = 1 +revision = 3 +requires-python = "==3.13.*" + +[[package]] +name = "asgiref" +version = "3.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e6/26/3b59f2bdae5f640389becb1f673cded775287f5fc4f816309d9ca9a3f93d/asgiref-3.12.1.tar.gz", hash = "sha256:59dcb51c272ad209d59bed5708a64a333083e86017d7fcdd67498eeab7784340", size = 42378, upload-time = "2026-07-14T09:56:18.087Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/1b/54f4ad77cd8a584fa70746c47df988e002cf1ee1eba43364d46f87803647/asgiref-3.12.1-py3-none-any.whl", hash = "sha256:fe386d1c2bff7259ea95929266d12a8cf9a8b5a1c2598402967d8792e7a7c094", size = 25478, upload-time = "2026-07-14T09:56:16.926Z" }, +] + +[[package]] +name = "bandit" +version = "1.9.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "pyyaml" }, + { name = "rich" }, + { name = "stevedore" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/aa/c3/0cb80dfe0f3076e5da7e4c5ad8e57bac6ac357ff4a6406205501cade4965/bandit-1.9.4.tar.gz", hash = "sha256:b589e5de2afe70bd4d53fa0c1da6199f4085af666fde00e8a034f152a52cd628", size = 4242677, upload-time = "2026-02-25T06:44:15.503Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/05/a4/a26d5b25671d27e03afb5401a0be5899d94ff8fab6a698b1ac5be3ec29ef/bandit-1.9.4-py3-none-any.whl", hash = "sha256:f89ffa663767f5a0585ea075f01020207e966a9c0f2b9ef56a57c7963a3f6f8e", size = 134741, upload-time = "2026-02-25T06:44:13.694Z" }, +] + +[[package]] +name = "certifi" +version = "2026.7.22" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a3/c2/24167ea9858356b47a87a50d39908bfdb72ceeefe0041586e704e5376b3a/certifi-2026.7.22.tar.gz", hash = "sha256:741e2c3b351ddf169a738da9f2c048608ff7f2c5cc02f1ebc6b118bb090d5d55", size = 138112, upload-time = "2026-07-22T03:35:12.644Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl", hash = "sha256:62f22742b58a1a33014a2b6b706588a8d7e2a88ae7bd1a6ebe8c992928483775", size = 136983, upload-time = "2026-07-22T03:35:11.276Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e5/3f/143b048436775b0f76ac3eec145c019e8173ccc2885c8f20319b996d5e83/charset_normalizer-3.5.1.tar.gz", hash = "sha256:6117b84ea48435e5356dc737f5121485c30920ba43375fa7b434fd753df0eac3", size = 171764, upload-time = "2026-08-15T08:20:44.807Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bc/61/2cb6ad133dbbb449fa2d37ccae973232f4827e799af258d15e589a3d1e9e/charset_normalizer-3.5.1-cp313-cp313-android_24_arm64_v8a.whl", hash = "sha256:4f298bdadb8f0b9e5672877f647d1be9373ef5320c9e2f049795e26cad28b6a9", size = 211584, upload-time = "2026-08-15T08:17:33.597Z" }, + { url = "https://files.pythonhosted.org/packages/18/57/a305c968be1ca13f3dd1b32f445877e97addf55d80b65c7cb35fac82b777/charset_normalizer-3.5.1-cp313-cp313-android_24_x86_64.whl", hash = "sha256:88ca277405c2d3b71c4e1c2ee0e7966e807bcba86a69d11e19ba199d18ae4491", size = 223359, upload-time = "2026-08-15T08:17:35.022Z" }, + { url = "https://files.pythonhosted.org/packages/09/0a/d3646670292ce8d8f8cc11ac067d44885e697a5591f57a9221128da5e7b3/charset_normalizer-3.5.1-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:9362dd90aa7dab48c0054a21187791ccf05473f7dba5d92b8033ae62164675e7", size = 194464, upload-time = "2026-08-15T08:17:36.452Z" }, + { url = "https://files.pythonhosted.org/packages/de/93/d51ec556e01042fed6f993ea859311bc7917b466684182fbbceb6ca24762/charset_normalizer-3.5.1-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:977cdbd483a9cff38179bea4fd754289a6f2195c7abd414aba85410b3e66cc5e", size = 197676, upload-time = "2026-08-15T08:17:37.819Z" }, + { url = "https://files.pythonhosted.org/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e90251c0c7bdd54a100a0dce3c07b7e637278c93af29dbf78ebb89a58c4bac7d", size = 340473, upload-time = "2026-08-15T08:17:39.303Z" }, + { url = "https://files.pythonhosted.org/packages/31/e7/1d994be1b93d41e9502b8b0460eaa88a1dd8df335df415db87d6c3e91ab2/charset_normalizer-3.5.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:94d78ecec2605a8d0398b0f365d5f12a63248438516f5dac536a5eff7337df4a", size = 240156, upload-time = "2026-08-15T08:17:40.66Z" }, + { url = "https://files.pythonhosted.org/packages/09/53/27923ce5cc6cbccb832037b27dca98882d9c53e9b69e866bbbef4aae7fc8/charset_normalizer-3.5.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d59b75732e9b6f27388e10c14b0259cc5f2e48c78627d185e6a177b58ad3cffe", size = 228246, upload-time = "2026-08-15T08:17:42.003Z" }, + { url = "https://files.pythonhosted.org/packages/ce/48/5a97e84d63af1d55c07439cb80e56d99a8efb4295700eb4e18c0d1615d2c/charset_normalizer-3.5.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0d929fc574b4d6fd9e7c0f5c2ede8716a41911923aa7fa5fce38e0818aa4a1ac", size = 263660, upload-time = "2026-08-15T08:17:43.627Z" }, + { url = "https://files.pythonhosted.org/packages/7a/c2/071575791dcc88316c0a9a65ce38897a82e4cfe4a325f0f7fe1b1ac47bcf/charset_normalizer-3.5.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:394fea06235c8543390050ed5f529187074b029fb027213f6c46ac11ab5d950e", size = 260354, upload-time = "2026-08-15T08:17:45.094Z" }, + { url = "https://files.pythonhosted.org/packages/fb/af/63240b0c0248c075c2535a1f1bd992821d8251b9f173abc13329661d09e4/charset_normalizer-3.5.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:62b55f6722735a6c472f88361cde6640608773d9443cebdbb51abf436a1fcdd3", size = 250638, upload-time = "2026-08-15T08:17:46.496Z" }, + { url = "https://files.pythonhosted.org/packages/4d/66/70dfad64f15be09c15ccfee81330a7e515895dbe296dd23114e9a231268a/charset_normalizer-3.5.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fa48b1b63d639f9483e0633e092f5851e2348c352f1f9bb6c8182f87884ef876", size = 244583, upload-time = "2026-08-15T08:17:47.963Z" }, + { url = "https://files.pythonhosted.org/packages/c0/24/ef36367d38b9ddd4bccbf72888c342e8de1f5ae506fa0b2dcf970e2732a1/charset_normalizer-3.5.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c71fb0d56c920c269cd3e2e3fe7c610e3f1fdb21a6ce60efa6430ff63676cea6", size = 242038, upload-time = "2026-08-15T08:17:49.481Z" }, + { url = "https://files.pythonhosted.org/packages/db/ab/55e683ba0fff2e43adafc10daa3001eac90fdaa419a97227d5a7067eedde/charset_normalizer-3.5.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:485a0d363cafefcd2538a73c7c838daa2035f09b2c9f9b5e3133f80c6aeb84c2", size = 233677, upload-time = "2026-08-15T08:17:50.845Z" }, + { url = "https://files.pythonhosted.org/packages/bd/67/0f40eaf8d1b6e7cf15e82382a2965efaca787fc1c2794b7021d37aaf5036/charset_normalizer-3.5.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5c0ea61a470e070686aa30892fed79e297d2c8d0ab46b8bcdf027d38c51da591", size = 264491, upload-time = "2026-08-15T08:17:52.61Z" }, + { url = "https://files.pythonhosted.org/packages/5c/64/12b4c2a11ee8df4fcc518c78b0d93e3a92bd3d5253d1617ce74ff0e8c7ef/charset_normalizer-3.5.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:90b7481fb62fbe172c558bc6fd1c4c98d82004a54a7551f20e11ac9bf0b8708c", size = 245196, upload-time = "2026-08-15T08:17:54.023Z" }, + { url = "https://files.pythonhosted.org/packages/37/2e/651d910af6d0fba325eee1cda37ec5443462ed25360e666c144166eb6091/charset_normalizer-3.5.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:35fe081843b35aad20ffeccec3eeffbe637b15d14f3fb22cc1b59cd8ec17e93c", size = 261660, upload-time = "2026-08-15T08:17:55.491Z" }, + { url = "https://files.pythonhosted.org/packages/90/c6/b09e05e6db7f64338e0dc067c79577b1138da86c1e38369096851d96be88/charset_normalizer-3.5.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fd0350afdc3aabd5576f60ea109228bd5538139713c7b094c5cd27c73a98bc6f", size = 252618, upload-time = "2026-08-15T08:17:57.025Z" }, + { url = "https://files.pythonhosted.org/packages/76/4e/362d4f9fdcdf5556fb2aa3ce7d4a58ebce03ed1ff03aa1d9aca8d02f13f3/charset_normalizer-3.5.1-cp313-cp313-pyemscripten_2025_0_wasm32.whl", hash = "sha256:9d9a0dc7cbe9bec24c3f767c9122c41fe5a1bc43f47cd099d00d393e09769de4", size = 140362, upload-time = "2026-08-15T08:17:58.425Z" }, + { url = "https://files.pythonhosted.org/packages/b4/d4/703be739b26acce318bd29eb3b25b7209e1b1f527f9eae3d1f1f01fdde2b/charset_normalizer-3.5.1-cp313-cp313-win32.whl", hash = "sha256:d63600d620ad0064c3a748b950ac5ea38a80190e5498532efefa4b7b3f1da1f3", size = 177755, upload-time = "2026-08-15T08:18:00.037Z" }, + { url = "https://files.pythonhosted.org/packages/8a/33/56d97ade41c8db611e727168c52ae46c9224c362ec28d4b65d7e9869e8da/charset_normalizer-3.5.1-cp313-cp313-win_amd64.whl", hash = "sha256:aea996a6aba25260827c9ea511d1addfde2da9eb686ac961838509086188b7e6", size = 199295, upload-time = "2026-08-15T08:18:01.506Z" }, + { url = "https://files.pythonhosted.org/packages/5b/75/5b20dd1e6573a01a08158fe104104fa2c8abf941745596954185726cd46c/charset_normalizer-3.5.1-cp313-cp313-win_arm64.whl", hash = "sha256:fd0a274c0e5f9a21565cd9d3dd749b61f96b7aa1e20a93aa1ba4029518f2e5c0", size = 179856, upload-time = "2026-08-15T08:18:02.929Z" }, + { url = "https://files.pythonhosted.org/packages/5b/97/fb4e82231aba271ffd775a1b4993b0defc4e3059f286ae41d9433409fe85/charset_normalizer-3.5.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:41876ee62a3dddf48ff1121ad8f0798032aa03f2fd35f21f34a4cab14f18d8d2", size = 331467, upload-time = "2026-08-15T08:19:50.959Z" }, + { url = "https://files.pythonhosted.org/packages/9f/2f/fe3f187327aac18e2d54e9d2b08e15d27bf9b642d9e51c219f130fc34d1a/charset_normalizer-3.5.1-cp37-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a6dac12ff6b846103483683f60c5f8fee205121adc58ffd87e90a90a3af69e99", size = 253057, upload-time = "2026-08-15T08:19:52.654Z" }, + { url = "https://files.pythonhosted.org/packages/d7/c7/9e48cee5c161fe24da823b61bf381921d77cb994a0a4de148e95018c1984/charset_normalizer-3.5.1-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cee5dd7c6fb5dd52a0fe2a740f9bc6e3593f5f8b1788bde49de02086f30182b2", size = 240930, upload-time = "2026-08-15T08:19:54.163Z" }, + { url = "https://files.pythonhosted.org/packages/49/e0/716601f3cc69be7b198951150c75ead1ece33c3c8036ff6ffa46029659a0/charset_normalizer-3.5.1-cp37-abi3-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:343fb4f2821043bd87095f7b08a1a181febc8e36ac64212143bbfd0a0e1bc235", size = 230822, upload-time = "2026-08-15T08:19:55.807Z" }, + { url = "https://files.pythonhosted.org/packages/d3/05/71bfc5caa0abcc45aea1f6a4d50ac68e59605ddc7666fe8494f4cd229665/charset_normalizer-3.5.1-cp37-abi3-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ae4a097991662cd4fff0ddc74e0fe7874f82e00042fa0ea00855645ed0c79598", size = 260037, upload-time = "2026-08-15T08:19:57.312Z" }, + { url = "https://files.pythonhosted.org/packages/c3/92/de7e32ed05341e7a9c4c877c318418197b7f2d66a3b68d561bf2ac57ca3e/charset_normalizer-3.5.1-cp37-abi3-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4b599739b93b2cbeded49645ae3c8d1405c29ddfbceac1545c87a3f9580a9e96", size = 255097, upload-time = "2026-08-15T08:19:59.056Z" }, + { url = "https://files.pythonhosted.org/packages/f5/7b/ade0a122600319dfa0b1000ab0f9731c94a817904cf3c5de408c73a4ede7/charset_normalizer-3.5.1-cp37-abi3-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b39b69b347e5e47a3b5b8cfc005c68c1ba347474e3960236c4944a8ecd174962", size = 250166, upload-time = "2026-08-15T08:20:00.612Z" }, + { url = "https://files.pythonhosted.org/packages/75/9c/019fbb9f4834491a160951349b1a3714439376f66e5f7cf18b4f18f0c7aa/charset_normalizer-3.5.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:a2028475ba855475b8b4d3cfeb4994269c967aea8b9892dfba907f4263a863a3", size = 241821, upload-time = "2026-08-15T08:20:02.321Z" }, + { url = "https://files.pythonhosted.org/packages/2b/b8/11d4840bfc99330cc7fbcc2681ee5a044553a6e77655508d8f9b2bff7b34/charset_normalizer-3.5.1-cp37-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:36047af20e17097c3bb9476c2b7655f2f7aa51322c0ba58c07695bedf755a950", size = 232529, upload-time = "2026-08-15T08:20:04.008Z" }, + { url = "https://files.pythonhosted.org/packages/18/96/2b3a21492d9f65171ac75d872f5018260013d00bfa0ff70ec9f179148cbd/charset_normalizer-3.5.1-cp37-abi3-musllinux_1_2_ppc64le.whl", hash = "sha256:4c4fb141a727957c93edfe5c32a26ceb6b5f6461d67146e2d39f51e16170bea8", size = 260348, upload-time = "2026-08-15T08:20:05.877Z" }, + { url = "https://files.pythonhosted.org/packages/d6/aa/a69a2028e8bd052476c245460ab19d7de595de084dd968f2d75cd50c3e25/charset_normalizer-3.5.1-cp37-abi3-musllinux_1_2_riscv64.whl", hash = "sha256:2f293479cce755c75f1697e87c409b7ae4c555c7dfecb6e988ad13abba943031", size = 247234, upload-time = "2026-08-15T08:20:07.487Z" }, + { url = "https://files.pythonhosted.org/packages/35/8a/3d130aeabcaf3d2466af76b7b141c08d9e89c9016ab4b7cdd0f7dc2d1c62/charset_normalizer-3.5.1-cp37-abi3-musllinux_1_2_s390x.whl", hash = "sha256:3588e376b3ea2eea84976f67273d679f229e24c66dce7b82ae45aef04ff6e072", size = 256917, upload-time = "2026-08-15T08:20:09.142Z" }, + { url = "https://files.pythonhosted.org/packages/80/c2/a7379b840292d0c1ab9fbd17d1f3967aa81794dc95bc74be8999d7fedcf7/charset_normalizer-3.5.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:e199fb99720074809a7720f1c0b4d919eea8b87e88713e0f8f602f7bef543d9d", size = 254846, upload-time = "2026-08-15T08:20:10.727Z" }, + { url = "https://files.pythonhosted.org/packages/01/65/d43b714731bb2f40d4053dfa00ecfc1c5a301f8e3316c5db3a09af59fe94/charset_normalizer-3.5.1-cp37-abi3-win32.whl", hash = "sha256:dd732602a7009217f658d5863d12d79d373a4de0eebc111094bcdd3bb8e0a6cc", size = 174216, upload-time = "2026-08-15T08:20:12.334Z" }, + { url = "https://files.pythonhosted.org/packages/35/4f/b911ed898b26a09789eba9c9200c999aff6c61b4bafaf4838e56d1a1e1a3/charset_normalizer-3.5.1-cp37-abi3-win_amd64.whl", hash = "sha256:70055ff39b97c99e7ae40ea3e393fb62aa2e44dbd9b29f8d14f42fb0025c3959", size = 199764, upload-time = "2026-08-15T08:20:13.908Z" }, + { url = "https://files.pythonhosted.org/packages/f0/a7/920baf467bfd9bf689f3b318340f37aee4572a71f162bd8db51da55ba4fa/charset_normalizer-3.5.1-cp37-abi3-win_arm64.whl", hash = "sha256:87e4f41d375c0b9be2fb5251aee4b8a689169e134535aed81bf085c3b647451e", size = 287318, upload-time = "2026-08-15T08:20:15.551Z" }, + { url = "https://files.pythonhosted.org/packages/cc/61/d01fc49b8dea277640b55a9e15960dbca9fdc8c9fde18e572d39c59f4019/charset_normalizer-3.5.1-py3-none-any.whl", hash = "sha256:6df0ec430f9a831772c23ca5a224cba36517a58a84bb32c32bb59a9fa67c47f6", size = 68658, upload-time = "2026-08-15T08:20:43.306Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "coverage" +version = "7.16.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/65/2d/c738872f477f5687152acae68635790387425d407ae37dd3d3a8a6692307/coverage-7.16.1.tar.gz", hash = "sha256:f83981779bcf9dfa06fa0a8d4cb43e0faec1706328ce07aa3e7b665b4ac0f210", size = 969651, upload-time = "2026-09-13T19:12:21.422Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/aa/74/c08c0c4dc9fa6bcd1d90728a63660aa1b17b488a806948598456c48f75d1/coverage-7.16.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ee5465db6e9152a7d09f3215309326878c6aa3ac509195a369f9d264ff4bfbd9", size = 223501, upload-time = "2026-09-13T19:09:37.276Z" }, + { url = "https://files.pythonhosted.org/packages/5b/c8/784986d326663285258a8e39835c46fb730cc85284f0dbcd82078586dd22/coverage-7.16.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2b8256f8b525ba233d2e4cdcdce0d6673c66fc9bf70df1fd5e67c54a74e2d245", size = 223876, upload-time = "2026-09-13T19:09:39.385Z" }, + { url = "https://files.pythonhosted.org/packages/15/76/73fb792928872bbb07e553f920ff55c65ee962c469265feb5d1d4ae5f97a/coverage-7.16.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d57cc400275b9a2892e905fc893f732b21ddb95271bf96406c88e2f6367848b5", size = 254863, upload-time = "2026-09-13T19:09:41.326Z" }, + { url = "https://files.pythonhosted.org/packages/ca/8d/1fd78899513244b065ccecdd1cfc6aa8b8f1bdee796d8c4f2aa8e8e5397d/coverage-7.16.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6b3fd0f3435ebb7a7183b32a6062a8b755f08242ced1f3f22761d30b56b3c2a5", size = 257460, upload-time = "2026-09-13T19:09:43.086Z" }, + { url = "https://files.pythonhosted.org/packages/47/1c/b23ddfcb7ef9bd7b3fdb7be9a5dccf9925ae88e556df7aa5b655283c78f2/coverage-7.16.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e5eb1762e7eb5fad34ef913e8107c7788a66f19d328e598ce95bf7217f9e5c8f", size = 258697, upload-time = "2026-09-13T19:09:45.161Z" }, + { url = "https://files.pythonhosted.org/packages/1c/c9/19d0c6ca35778a7e9415c30c46a0c64c9d4374219d004a35563132296896/coverage-7.16.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:46cd3a73e9140410de62cceb66214bce0e08fb3922b9176fbfc1522fec151b41", size = 260827, upload-time = "2026-09-13T19:09:47.061Z" }, + { url = "https://files.pythonhosted.org/packages/97/fc/5862f7344382c62b85df43d483e579168cc062e007f54d895dfa51fe3e7d/coverage-7.16.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d1ba5142d68dd2cb775cbd0ac8601819298152047803c8efe4eec6d7d7aa7878", size = 255038, upload-time = "2026-09-13T19:09:48.945Z" }, + { url = "https://files.pythonhosted.org/packages/2e/9f/5c26583199a68df8d15124b4590520903f8eb7cef17db293fea712bb0783/coverage-7.16.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c389c6f9d1d518e1249ddcb8a7f158135644ce2c508fa6cc17b680777dad5bf2", size = 256827, upload-time = "2026-09-13T19:09:50.738Z" }, + { url = "https://files.pythonhosted.org/packages/95/13/605198bff079b107336710f28a797312ab132587168600d70a290e7ecd2e/coverage-7.16.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cdc57746c7ac0ea063351b4d651c3bb4dd4fd35e64dbb8e90c10e14eb03c4080", size = 254794, upload-time = "2026-09-13T19:09:52.577Z" }, + { url = "https://files.pythonhosted.org/packages/43/b7/0bbb32dc5ccdac766a13763fdfbffd7d73fc80349a69230c46c6b71e7508/coverage-7.16.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5597180ed7670cc94c04c65347418a467d3a43d5f0cf52fcac647f5425f42037", size = 258947, upload-time = "2026-09-13T19:09:54.372Z" }, + { url = "https://files.pythonhosted.org/packages/13/bd/65c31ddd43ff4e61b63721b3dad17cca412dba6e2ce89f92abdf75734339/coverage-7.16.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:a9647a0ac46255b8fef59a433a2161f03e5483f3a35e1cbd9dfe4600baff0c6b", size = 254613, upload-time = "2026-09-13T19:09:56.198Z" }, + { url = "https://files.pythonhosted.org/packages/25/20/d278115f2ba522b3e3128c6852be265f4e0df7202b2effca4db96cf0217d/coverage-7.16.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e306e98186b9cd109121f3583aeb7978797ad21d948f22944c5c08845cd554d0", size = 256388, upload-time = "2026-09-13T19:09:58.095Z" }, + { url = "https://files.pythonhosted.org/packages/e1/ca/d43aa396fb3a2f71c9411b99d926475f5acaf5c124f605c592865c80c8d5/coverage-7.16.1-cp313-cp313-win32.whl", hash = "sha256:48a78a66fcce49d7f6156524bf979c0ac633d584199717c68c6ffa949fc14e6a", size = 225550, upload-time = "2026-09-13T19:09:59.998Z" }, + { url = "https://files.pythonhosted.org/packages/0e/30/df2f6114f6a17cffe94721bd1d298f77f86aad493717fa5bc03cb291a1a6/coverage-7.16.1-cp313-cp313-win_amd64.whl", hash = "sha256:7af03247d598a353bbbbe1b925deb735276e4d845e7197c4073dc89352b236fa", size = 226091, upload-time = "2026-09-13T19:10:02.331Z" }, + { url = "https://files.pythonhosted.org/packages/ee/31/6f90d8aab72a112492bd50e3b5485b53b772b1f5fa70da0a620e723caae6/coverage-7.16.1-cp313-cp313-win_arm64.whl", hash = "sha256:166adae25b05b04c9a84135912066d9c97482115af38df1a419a38aacc6b6f5d", size = 225481, upload-time = "2026-09-13T19:10:04.151Z" }, + { url = "https://files.pythonhosted.org/packages/96/1a/d6d16babd0a5fe4c3fae40702158c570351694e74516d8d81b86c5637448/coverage-7.16.1-py3-none-any.whl", hash = "sha256:3d8bd4e58b6a5c2018d808f297905393c6c61da466a48c3f0596a76a4900ebe4", size = 215264, upload-time = "2026-09-13T19:12:18.895Z" }, +] + +[[package]] +name = "django" +version = "5.2.17" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "asgiref" }, + { name = "sqlparse" }, + { name = "tzdata", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d5/d8/43e9d000519adceb189620b6869ff88031e046df91c2e9da72f8f6918399/django-5.2.17.tar.gz", hash = "sha256:9d4d93be539a18ab80d058eb515900e10951e04c537c5a6b394fc49528d3251f", size = 10889740, upload-time = "2026-08-04T15:04:03.173Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/df/f8/ce120525ca78f12b07daf65786679c5d0b54a75285a8958d3ae55e39da35/django-5.2.17-py3-none-any.whl", hash = "sha256:f04fb3b36ee119e1af4fa1d397d5fd6cf12700f49321e84d4f4c642c5b1973db", size = 8315563, upload-time = "2026-08-04T15:03:59.1Z" }, +] + +[[package]] +name = "djangorestframework" +version = "3.16.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8a/95/5376fe618646fde6899b3cdc85fd959716bb67542e273a76a80d9f326f27/djangorestframework-3.16.1.tar.gz", hash = "sha256:166809528b1aced0a17dc66c24492af18049f2c9420dbd0be29422029cfc3ff7", size = 1089735, upload-time = "2025-08-06T17:50:53.251Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b0/ce/bf8b9d3f415be4ac5588545b5fcdbbb841977db1c1d923f7568eeabe1689/djangorestframework-3.16.1-py3-none-any.whl", hash = "sha256:33a59f47fb9c85ede792cbf88bde71893bcda0667bc573f784649521f1102cec", size = 1080442, upload-time = "2025-08-06T17:50:50.667Z" }, +] + +[[package]] +name = "docker" +version = "7.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pywin32", marker = "sys_platform == 'win32'" }, + { name = "requests" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/88/7f/731ff914b0255d3d065f45fd4e626d4b8c95dbcbaada049f337a6ac16410/docker-7.2.0.tar.gz", hash = "sha256:cebb93773d334f778e023a7ee352a8d6e13ab1bd3b863a4d4a59dec897df43ac", size = 118731, upload-time = "2026-07-09T14:53:46.39Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/75/23/529140fe1aab80fc6992f93a706deec709140a6397439139a054e1515c45/docker-7.2.0-py3-none-any.whl", hash = "sha256:a3f45fdeb9165e2d25d9a1d02ddf3bc70fb572cf5ebbf9b58558c22caf29b71f", size = 148775, upload-time = "2026-07-09T14:53:45.224Z" }, +] + +[[package]] +name = "idna" +version = "3.20" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f5/08/8eea9d4b8302028f3abb2c0813953f7aec26d33b7a8960ed760e65ff29fa/idna-3.20.tar.gz", hash = "sha256:a7db850025b95ded1eae8a46181a1a6c56c92c96f0e2b005d9ff8dc0210cab44", size = 216463, upload-time = "2026-09-17T14:11:04.752Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl", hash = "sha256:ab7ae7122974553370f0bdb919e1a960b2cd1bc1ef0276416d896db81c14582c", size = 69583, upload-time = "2026-09-17T14:11:03.168Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, +] + +[[package]] +name = "markdown-it-py" +version = "4.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mdurl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/ff/7841249c247aa650a76b9ee4bbaeae59370dc8bfd2f6c01f3630c35eb134/markdown_it_py-4.2.0.tar.gz", hash = "sha256:04a21681d6fbb623de53f6f364d352309d4094dd4194040a10fd51833e418d49", size = 82454, upload-time = "2026-05-07T12:08:28.36Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl", hash = "sha256:9f7ebbcd14fe59494226453aed97c1070d83f8d24b6fc3a3bcf9a38092641c4a", size = 91687, upload-time = "2026-05-07T12:08:27.182Z" }, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, +] + +[[package]] +name = "medcheck-backend" +version = "0.0.0" +source = { virtual = "." } +dependencies = [ + { name = "django" }, + { name = "djangorestframework" }, + { name = "psycopg", extra = ["binary"] }, +] + +[package.dev-dependencies] +dev = [ + { name = "bandit" }, + { name = "pyright" }, + { name = "pytest" }, + { name = "pytest-cov" }, + { name = "pytest-django" }, + { name = "ruff" }, + { name = "testcontainers" }, +] + +[package.metadata] +requires-dist = [ + { name = "django", specifier = ">=5.2,<5.3" }, + { name = "djangorestframework", specifier = ">=3.16,<3.17" }, + { name = "psycopg", extras = ["binary"], specifier = ">=3.2,<3.3" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "bandit", specifier = ">=1.8,<2" }, + { name = "pyright", specifier = ">=1.1,<2" }, + { name = "pytest", specifier = ">=8.3,<9" }, + { name = "pytest-cov", specifier = ">=6,<7" }, + { name = "pytest-django", specifier = ">=4.9,<5" }, + { name = "ruff", specifier = ">=0.9,<1" }, + { name = "testcontainers", extras = ["postgres"], specifier = ">=4.9,<5" }, +] + +[[package]] +name = "nodeenv" +version = "1.10.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", size = 55611, upload-time = "2025-12-20T14:08:54.006Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438, upload-time = "2025-12-20T14:08:52.782Z" }, +] + +[[package]] +name = "packaging" +version = "26.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/fa/3944b40b07da9ce895c0e6303a5ab7d53da063554f534556b134a54d6093/packaging-26.3.tar.gz", hash = "sha256:94edc256424af38762eb31306eed28beb9f0efc50a8837492c9d6fd6004aed79", size = 313412, upload-time = "2026-08-04T18:15:28.737Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl", hash = "sha256:d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c", size = 129956, upload-time = "2026-08-04T18:15:27.159Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + +[[package]] +name = "psycopg" +version = "3.2.13" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "tzdata", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/44/05/d4a05988f15fcf90e0088c735b1f2fc04a30b7fc65461d6ec278f5f2f17a/psycopg-3.2.13.tar.gz", hash = "sha256:309adaeda61d44556046ec9a83a93f42bbe5310120b1995f3af49ab6d9f13c1d", size = 160626, upload-time = "2025-11-21T22:34:32.328Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a9/14/f2724bd1986158a348316e86fdd0837a838b14a711df3f00e47fba597447/psycopg-3.2.13-py3-none-any.whl", hash = "sha256:a481374514f2da627157f767a9336705ebefe93ea7a0522a6cbacba165da179a", size = 206797, upload-time = "2025-11-21T22:29:39.733Z" }, +] + +[package.optional-dependencies] +binary = [ + { name = "psycopg-binary", marker = "implementation_name != 'pypy'" }, +] + +[[package]] +name = "psycopg-binary" +version = "3.2.13" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/28/ec/ef37bb44dc02fcc6c0a3eeb93f4baaac13bcb228633fe38ad3fb5a3f6449/psycopg_binary-3.2.13-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dbae6ab1966e2b61d97e47220556c330c4608bb4cfb3a124aa0595c39995c068", size = 3995628, upload-time = "2025-11-21T22:31:45.921Z" }, + { url = "https://files.pythonhosted.org/packages/6d/ad/4748f5f1a40248af16dba087dbec50bd335ee025cc1fb9bf64773378ceff/psycopg_binary-3.2.13-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:fae933e4564386199fc54845d85413eedb49760e0bcd2b621fde2dd1825b99b3", size = 4069024, upload-time = "2025-11-21T22:31:50.202Z" }, + { url = "https://files.pythonhosted.org/packages/cf/c2/f02ec6bbc30c7fcd3b39823d2d624b42fae480edeb6e50eb3276281d5635/psycopg_binary-3.2.13-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:13e2f8894d410678529ff9f1211f96c5a93ff142f992b302682b42d924428b61", size = 4615127, upload-time = "2025-11-21T22:31:56.517Z" }, + { url = "https://files.pythonhosted.org/packages/f0/0d/a54fc2cdd672c84175d6869cc823d6ec2a8909318d491f3c24e6077983f2/psycopg_binary-3.2.13-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f26f7009375cf1e92180e5c517c52da1054f7e690dde90e0ed00fa8b5736bcd4", size = 4710267, upload-time = "2025-11-21T22:32:04.585Z" }, + { url = "https://files.pythonhosted.org/packages/9d/b7/067de1acaf3d312253351f3af4121f972584bd36cada6378d4b0cdcebd38/psycopg_binary-3.2.13-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea2fdbcc9142933a47c66970e0df8b363e3bd1ea4c5ce376f2f3d94a9aeec847", size = 4400795, upload-time = "2025-11-21T22:32:08.883Z" }, + { url = "https://files.pythonhosted.org/packages/64/b5/030e6b1ebfc4d3a8fca03adc5fc827982643bad0b01a1268538d17c08ed3/psycopg_binary-3.2.13-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac92d6bc1d4a41c7459953a9aa727b9966e937e94c9e072527317fd2a67d488b", size = 3851239, upload-time = "2025-11-21T22:32:12.333Z" }, + { url = "https://files.pythonhosted.org/packages/79/6f/0541845364a7de9eae6807060da6a04b22a8eb2e803606d285d9250fbe93/psycopg_binary-3.2.13-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:8b843c00478739e95c46d6d3472b13123b634685f107831a9bfc41503a06ecbd", size = 3525084, upload-time = "2025-11-21T22:32:15.946Z" }, + { url = "https://files.pythonhosted.org/packages/83/ae/6507890dc30a4bbd9d938d4ff3a4079d009a5ad8170af51c7f762438fdbf/psycopg_binary-3.2.13-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2f63868cc96bc18486cebec24445affbdd7f7debf28fac466ea935a8b5a4753b", size = 3576787, upload-time = "2025-11-21T22:32:19.922Z" }, + { url = "https://files.pythonhosted.org/packages/9d/64/3d1c2f1fd09b60cdfbe68b9a810b357ba505eff6e4bdb1a2d9f6729da64c/psycopg_binary-3.2.13-cp313-cp313-win_amd64.whl", hash = "sha256:594dfbca3326e997ae738d3d339004e8416b1f7390f52ce8dc2d692393e8fa96", size = 2905584, upload-time = "2025-11-21T22:32:23.399Z" }, +] + +[[package]] +name = "pygments" +version = "2.21.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/49/2e/ced460408999b33da6b31b0021b0f37d329e202d4169aeb164493778f25b/pygments-2.21.0.tar.gz", hash = "sha256:610ca751c9bc2492b38eb9a38a7fbc93edbbb2d7182edaf34e66ae493dee5c8c", size = 5005329, upload-time = "2026-08-17T08:02:48.824Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl", hash = "sha256:2363c69b61c4a97c838da3b130dcd6468f4848992b21a82f2a63ec34377137d9", size = 1250147, upload-time = "2026-08-17T08:02:44.912Z" }, +] + +[[package]] +name = "pyright" +version = "1.1.414" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nodeenv" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e1/1b/244c7b710031ada80f27e579ec20d28a2285dfc318fed0339866b1047f12/pyright-1.1.414.tar.gz", hash = "sha256:523c0a97c60da6333234955c277730c9cf4f5bd6d5399e7b7d2b0fc5d3599524", size = 4154638, upload-time = "2026-09-10T12:26:53.181Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d7/ba/18b6e682ead424ad24bcc134339ae5d1b931cd9ae260540592a058a91279/pyright-1.1.414-py3-none-any.whl", hash = "sha256:2a6b4b3298c9eec174c5ed83bd338de6eee82df2992f3e1930e6199d381be36f", size = 6225049, upload-time = "2026-09-10T12:26:51.427Z" }, +] + +[[package]] +name = "pytest" +version = "8.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/5c/00a0e072241553e1a7496d638deababa67c5058571567b92a7eaa258397c/pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", size = 1519618, upload-time = "2025-09-04T14:34:22.711Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79", size = 365750, upload-time = "2025-09-04T14:34:20.226Z" }, +] + +[[package]] +name = "pytest-cov" +version = "6.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "coverage" }, + { name = "pluggy" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/30/4c/f883ab8f0daad69f47efdf95f55a66b51a8b939c430dadce0611508d9e99/pytest_cov-6.3.0.tar.gz", hash = "sha256:35c580e7800f87ce892e687461166e1ac2bcb8fb9e13aea79032518d6e503ff2", size = 70398, upload-time = "2025-09-06T15:40:14.361Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/80/b4/bb7263e12aade3842b938bc5c6958cae79c5ee18992f9b9349019579da0f/pytest_cov-6.3.0-py3-none-any.whl", hash = "sha256:440db28156d2468cafc0415b4f8e50856a0d11faefa38f30906048fe490f1749", size = 25115, upload-time = "2025-09-06T15:40:12.44Z" }, +] + +[[package]] +name = "pytest-django" +version = "4.14.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/44/f6/3851312120c2bf2f19cafff931e75059aad1ba670703cd751e2fde9bc942/pytest_django-4.14.0.tar.gz", hash = "sha256:26787dd3f422cfbab8f55b80a776e2edea7a11092cb74e960bef1312515708ef", size = 94700, upload-time = "2026-08-10T14:13:08.319Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9c/03/850bffad2b581c440ca51c039d74504d5a422c94bda0bdb8a8ba5068d48b/pytest_django-4.14.0-py3-none-any.whl", hash = "sha256:c533b08d89cc675efcd5398eea270b34547e35f9a3608e2c9748dd88428ea187", size = 27067, upload-time = "2026-08-10T14:13:06.998Z" }, +] + +[[package]] +name = "python-dotenv" +version = "1.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6a/53/ed9d74092561d4b01a2ef1349d52cdbc135e526c245f366b089cfca6de49/python_dotenv-1.2.3.tar.gz", hash = "sha256:a20a594dabeaa385725aa239d5244871c143ecb356add8a20fcf23773a6c3a35", size = 58945, upload-time = "2026-08-16T16:54:54.067Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl", hash = "sha256:904552145e8bfed22162c09dab1c2b9b54fefa7b23ba780f4f26ca0316b0f0d9", size = 22780, upload-time = "2026-08-16T16:54:52.473Z" }, +] + +[[package]] +name = "pywin32" +version = "312" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2d/41/12fbfd7f36ed2146d8bc9de96c2741296bf0d490b98508496cff322e274c/pywin32-312-cp313-cp313-win32.whl", hash = "sha256:7a27df850933d16a8eabfbaeb73d52b273e2da667f80d70b01a89d1f6828d02c", size = 6370184, upload-time = "2026-06-04T07:49:36.253Z" }, + { url = "https://files.pythonhosted.org/packages/ba/db/36a78e3403099d31d9746d13fdcde5accc43c1155f375a34d15983a479a7/pywin32-312-cp313-cp313-win_amd64.whl", hash = "sha256:c53e878d15a1c44788082bfe712a905433473aa38f86375b7cf8b45e3acbaaf9", size = 6914298, upload-time = "2026-06-04T07:49:38.876Z" }, + { url = "https://files.pythonhosted.org/packages/84/37/c1697194092b76de9ed47ca124323f02c57ffc8a45c06f88a3d5acaf01eb/pywin32-312-cp313-cp313-win_arm64.whl", hash = "sha256:59aba5d5940842075343a5ddc6b11f1cdf0d1567fe745290359dfbcc7c2eb831", size = 6727640, upload-time = "2026-06-04T07:49:41.083Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, + { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, + { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, + { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" }, + { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" }, + { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" }, + { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" }, + { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, + { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, + { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, +] + +[[package]] +name = "requests" +version = "2.34.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ac/c3/e2a2b89f2d3e2179abd6d00ebd70bff6273f37fb3e0cc209f48b39d00cbf/requests-2.34.2.tar.gz", hash = "sha256:f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed", size = 142856, upload-time = "2026-05-14T19:25:27.735Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl", hash = "sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0", size = 73075, upload-time = "2026-05-14T19:25:26.443Z" }, +] + +[[package]] +name = "rich" +version = "15.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown-it-py" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c0/8f/0722ca900cc807c13a6a0c696dacf35430f72e0ec571c4275d2371fca3e9/rich-15.0.0.tar.gz", hash = "sha256:edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36", size = 230680, upload-time = "2026-04-12T08:24:00.75Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb", size = 310654, upload-time = "2026-04-12T08:24:02.83Z" }, +] + +[[package]] +name = "ruff" +version = "0.16.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/78/449cb84790bd5cc3823b2652ee405a4558856e5c4195aee3a16bf7b3eb5d/ruff-0.16.8.tar.gz", hash = "sha256:9247bf92b5f04d825c8639a4fe423ec2e4222acd9222e58412b0dab7e442798b", size = 4938814, upload-time = "2026-09-16T15:54:46.688Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ac/25/6071aabc530e9be7e2c195e8fe3f7aea2735405b6cf447212832d7811831/ruff-0.16.8-py3-none-linux_armv6l.whl", hash = "sha256:6ffbd6d87383c1edf5f6fa890f10200950240d7c1a16052a19a09d3a2307dd38", size = 10048966, upload-time = "2026-09-16T15:53:57.605Z" }, + { url = "https://files.pythonhosted.org/packages/54/98/07f90ecbc74dd5fb5764f11f2bc774d6a7cffef92d2ff5f5b4e9e23c754e/ruff-0.16.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:42ed6b878ed61e3acca92f2730a17acff39286944ea82398544696366a6f925e", size = 10165498, upload-time = "2026-09-16T15:54:01.14Z" }, + { url = "https://files.pythonhosted.org/packages/fe/1f/e6a712e3b47cad4a40600134105ed193cb773f618a42eb7ba323cb812cc0/ruff-0.16.8-py3-none-macosx_11_0_arm64.whl", hash = "sha256:7ea781c7f2afba8c6a505ea0fb3f994020249e0c450635f5381286fea6b46170", size = 9830004, upload-time = "2026-09-16T15:54:03.998Z" }, + { url = "https://files.pythonhosted.org/packages/23/f2/311a08776d75d81c7676e20b6b020ae63cbe881fcdc7a8dd64e6e18bdd93/ruff-0.16.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8efeae3bbe414a5efefda11a792dfb51ef90ac48d50c4830de2f644caf3e8659", size = 9986558, upload-time = "2026-09-16T15:54:06.804Z" }, + { url = "https://files.pythonhosted.org/packages/f3/ed/37b6cb3d3ba8c73e68ae3eb1d502383beb5aa05a582bb7bb3a922f929f54/ruff-0.16.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3a79b795469fef7fc6e908b218eed2eb17332afd85031db6480dc864560e69b2", size = 9877332, upload-time = "2026-09-16T15:54:09.552Z" }, + { url = "https://files.pythonhosted.org/packages/22/cc/40873a8f36ad084cc540d55fcca7077264d5b13b24659e9180c176fb2b08/ruff-0.16.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3fdc5563cdc50555e6fba39322850860e9267c1b3d12c26a74729d8604c3c812", size = 10507125, upload-time = "2026-09-16T15:54:12.152Z" }, + { url = "https://files.pythonhosted.org/packages/c3/e4/fc91a642b78ccbab6b9477720f3644ae7a10a9bcce69a934679cd64f62bc/ruff-0.16.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:34508983c70665578dab88f5223d8e6228307e1135398ca8bfc8b7e9501e282b", size = 11336694, upload-time = "2026-09-16T15:54:15.489Z" }, + { url = "https://files.pythonhosted.org/packages/c2/3d/bbd2a9a600a4e73dc3e7548a249c8d1671273464b55822c6fae50f602dff/ruff-0.16.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:644bb578569e0ffc575741232bd385dacdd6fbe123f1a729e7a225f54aa3957f", size = 10774448, upload-time = "2026-09-16T15:54:18.16Z" }, + { url = "https://files.pythonhosted.org/packages/1a/41/d83af9879a7b6e8bf5fe16b1da0b134049d2f5d3afac12defb0897cb84bd/ruff-0.16.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15e7d226246961db9235098333caa13063906d3851136b84c2900b82f5daa1df", size = 10323796, upload-time = "2026-09-16T15:54:20.743Z" }, + { url = "https://files.pythonhosted.org/packages/f5/2c/cefd07bfe914b84943ea769ade8d607bd22750b965d3228eefd7cebd15d0/ruff-0.16.8-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:a2bf6bc3e9ebdd4449abc6f06cf64b98051a2c61cf94d2fe9596518c881f1a1e", size = 10514115, upload-time = "2026-09-16T15:54:23.497Z" }, + { url = "https://files.pythonhosted.org/packages/f3/9d/76a2e26c79a23be6e6e3664c57bec9e9fc8de155cfb9e4b67ea91b64f9d7/ruff-0.16.8-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:6ca111ba0849539165e9e59d2b442542f3c1e8060ebbdea82494f1ffbccb1e1f", size = 10072582, upload-time = "2026-09-16T15:54:26.185Z" }, + { url = "https://files.pythonhosted.org/packages/2e/d4/f42edddb39668af1a559ceafa3823aedd65633a48dc9768e775485faa2c1/ruff-0.16.8-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:359a1e5b495448ee1e91018064382ebc86f90e8aac2fed222c7d0e4e8df85fd2", size = 9879644, upload-time = "2026-09-16T15:54:29.278Z" }, + { url = "https://files.pythonhosted.org/packages/f8/d4/913e3195d95e0378786c6656945c865f534a3560e29139da4882aff630d1/ruff-0.16.8-py3-none-musllinux_1_2_i686.whl", hash = "sha256:59e8f5681349474110b24d62e93cfda6593f5fa3473446ca3705200cac1a08b9", size = 10231569, upload-time = "2026-09-16T15:54:32.036Z" }, + { url = "https://files.pythonhosted.org/packages/2b/c4/8aa6ea0bdcedbd1bf87397e2fc4ed8406448ea5842f8660bc6e5f163039d/ruff-0.16.8-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:efa3e7a16d1baaa79957888dfdf8be9ef2e44db81cb032af06d76632ab59e773", size = 10663666, upload-time = "2026-09-16T15:54:34.838Z" }, + { url = "https://files.pythonhosted.org/packages/3d/02/7f10ef4700bc223c30a3fdd10631a29830c45524b810a3c7ed947af64591/ruff-0.16.8-py3-none-win32.whl", hash = "sha256:55793ba85c69921e89be061426d91a78652d6e50317c962240922747a4eb713f", size = 10093472, upload-time = "2026-09-16T15:54:37.47Z" }, + { url = "https://files.pythonhosted.org/packages/1e/5d/a509c07d714b6da88f2c518b4637cf6f1d46b074be8f0f1e5fb9ff5126fe/ruff-0.16.8-py3-none-win_amd64.whl", hash = "sha256:a6b85621fd3c81e31fc5f5add09c9c078b430db3595ca632efafdec9e64ebfaa", size = 10586899, upload-time = "2026-09-16T15:54:40.488Z" }, + { url = "https://files.pythonhosted.org/packages/fe/a0/50787329e4f20bf9dc9f6230015d46ec69c51a97ace5bc202dae4755365d/ruff-0.16.8-py3-none-win_arm64.whl", hash = "sha256:d075e820af612102ce217f07cc93e69f9490b10ec13ea85fa87bd03d996cef8a", size = 10386316, upload-time = "2026-09-16T15:54:43.332Z" }, +] + +[[package]] +name = "sqlparse" +version = "0.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5f/d3/3f06a1006f2261d1342aefb3c71eed02f5d4ca5bdbecd86ebc12ad38306e/sqlparse-0.6.0.tar.gz", hash = "sha256:113c35c75365ab9cc9c7231d68c6428fb11c085fc8e9eb1ad659b7ddbf6cd2b9", size = 178477, upload-time = "2026-08-13T19:16:06.396Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/50/f00935da0ec7cbf325f8dc4f772ae46fbc7b672dd62876e73f0a94adda57/sqlparse-0.6.0-py3-none-any.whl", hash = "sha256:b861c0288ce2fa56209a9a6412d2e066ac664b3873b89c26c9d8415e8e32996f", size = 50070, upload-time = "2026-08-13T19:16:04.062Z" }, +] + +[[package]] +name = "stevedore" +version = "5.9.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/db/a1/3b8ed9c1fc3aa6eebb57732d924ddaa0500ecc3b638d0454816320994383/stevedore-5.9.1.tar.gz", hash = "sha256:e97a2667923efda926e8713fde6a73616df68210a3cbc6f02b48967b676fd8bf", size = 518111, upload-time = "2026-08-20T15:25:14.754Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c5/97/bba6e7ec2f5498b9dcb7b1b6400086b80ae5a8ebaff4b25e8c8add75f439/stevedore-5.9.1-py3-none-any.whl", hash = "sha256:5c8ff3a9f336cc1a06ac0f597bc79d11a2f950bfd32e290ca56b5a301fafafbf", size = 54931, upload-time = "2026-08-20T15:25:13.602Z" }, +] + +[[package]] +name = "testcontainers" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "docker" }, + { name = "python-dotenv" }, + { name = "typing-extensions" }, + { name = "urllib3" }, + { name = "wrapt" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4b/13/2cc466bddf26d0085f30a2b2bd56b7f8708b54a54db833eec97c5c69129b/testcontainers-4.15.0.tar.gz", hash = "sha256:085cde086337632e19002719460b7b80bbab2bdd51bb3ea04f77d0de96504706", size = 95340, upload-time = "2026-07-24T23:08:01.731Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/7e/424aac8b355597835deb333e757a0e94b5ccf38ad00f07fe6ed1f4e17c88/testcontainers-4.15.0-py3-none-any.whl", hash = "sha256:8796c14e76604031ad39cf0ed3b8e9806283a1fbf5270965c2b1c594caa31b74", size = 160771, upload-time = "2026-07-24T23:08:00.13Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/cc/6253133b5bb138fc3306cebfbda2c520f545d36b5be2c7255cc528bb45d6/typing_extensions-4.16.0.tar.gz", hash = "sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5", size = 113555, upload-time = "2026-07-02T08:40:05.92Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8", size = 45571, upload-time = "2026-07-02T08:40:04.659Z" }, +] + +[[package]] +name = "tzdata" +version = "2026.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e4/31/3d74fa778a63b98b7374323befcc0be5ab3bd94afd4096a0124e7379152c/tzdata-2026.4.tar.gz", hash = "sha256:f1b8bd365d8d210c55353f4d7f8d6d8561c0ba50d704b700d195a9424bba0d79", size = 199350, upload-time = "2026-09-12T12:56:03.251Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f9/bc/8737e8d54cf51106118039b83f485a4783112fab49ea9d044b234978a46e/tzdata-2026.4-py2.py3-none-any.whl", hash = "sha256:c2169a8b0a7a5e9674da5a135ccdfb2b3e671b333ed9fed17b41f73c34476e81", size = 347494, upload-time = "2026-09-12T12:56:01.67Z" }, +] + +[[package]] +name = "urllib3" +version = "2.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e3/05/b17359e1cefb4f909b5e40b1b90a496d987258916dbbf88e842c729f510e/urllib3-2.8.0.tar.gz", hash = "sha256:63bf2ead4c879426ebf22ef2a781eeb4aa3b4ae798a0435506f8687fd5bb9b63", size = 458972, upload-time = "2026-09-15T19:29:36.253Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl", hash = "sha256:0cf3cae568d36aa9576b28dfb35f11328f1cb974ca7647d9475ebb86c75ac6e3", size = 135717, upload-time = "2026-09-15T19:29:34.577Z" }, +] + +[[package]] +name = "wrapt" +version = "2.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/42/a6/6375d56c44d590ef24acf0f8f5bf7ed768ff7a510b959306ec412611e90f/wrapt-2.4.1.tar.gz", hash = "sha256:fd6390aab9e8aa40c52eff3c180f098e8d9f5894b1fd4c4fd2c207067b33ed16", size = 164597, upload-time = "2026-09-10T23:12:16.811Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5c/1a/9b5aa3c2391aa6d00fffa085c2219e8fc91cd4d2b9b080d2b4e4b6b93f42/wrapt-2.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:55f36bb1461f93beaf18d818e568b5de343dd8fade7456773d201a38ee723bd3", size = 98597, upload-time = "2026-09-10T23:10:23.723Z" }, + { url = "https://files.pythonhosted.org/packages/fe/07/dc98150c2f9ee5b5fcbd841765e178ea6cc6c43733ab8d1f5181a4fb9f3d/wrapt-2.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:53e15cd74bd6b84d7fa90b93dda7334d85f4641fae97632de8aa61d268dfd145", size = 98842, upload-time = "2026-09-10T23:10:25.109Z" }, + { url = "https://files.pythonhosted.org/packages/08/c2/0e772a570e8d75c1b3ec45930a3023492fa68223f8f5e3485af4844c10c3/wrapt-2.4.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:be6cdd7121adc89a6f52e3c2f4e26a2d4dcdc1c0fde47e3156234db8939e4cdc", size = 234642, upload-time = "2026-09-10T23:10:26.644Z" }, + { url = "https://files.pythonhosted.org/packages/76/25/4ce4d02dd95ff9ed972a2fc396d04fec636daa5a4ac18cc73a3dc20aa6c3/wrapt-2.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:03b5598edd435373278731d0d53449ce7a9626bc48d5548e4a71124ee3e526a1", size = 235484, upload-time = "2026-09-10T23:10:28.098Z" }, + { url = "https://files.pythonhosted.org/packages/fd/80/436ef1df620ef8edd9ef057b4d55a0cd704435ff66852a0ef26cbaa02a58/wrapt-2.4.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fdc997819a6df4c65bdb0a1c5601c98b479ee34cc2f94ffa98a767034ad6366d", size = 214371, upload-time = "2026-09-10T23:10:29.841Z" }, + { url = "https://files.pythonhosted.org/packages/6a/2c/cc5b7503843399087db3106a7cf60d60d0900f69539e96148b9fff116291/wrapt-2.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3bfc6907ebed560d2d3f677c3b17bf6199679163b6c6e475035c9dca497d1697", size = 232347, upload-time = "2026-09-10T23:10:31.511Z" }, + { url = "https://files.pythonhosted.org/packages/86/fb/17668b1ca572c44b458c09d76064d35f5f57d5ac7629248871604bef816c/wrapt-2.4.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:a0c3b217332cf0c4df085fec41c126bf7507d6c1ca0efb3ba8d2b3fd234d4e73", size = 212792, upload-time = "2026-09-10T23:10:32.968Z" }, + { url = "https://files.pythonhosted.org/packages/b8/2b/0c5de10d7259e07c478c44bf2fbe179c6878727d09edf0632b97884801db/wrapt-2.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a23b89621cfeb3329b1a290596bf402e61d7d5a647a65ca8ea735e48771b71d4", size = 223585, upload-time = "2026-09-10T23:10:34.43Z" }, + { url = "https://files.pythonhosted.org/packages/aa/36/013dce1c687f8f1c87b1e78f403d04c80ae9b2ae77de4ddba16069a3e7d1/wrapt-2.4.1-cp313-cp313-win32.whl", hash = "sha256:bc67d4872af5ab2dc1b88904097b92ac00e7658fdf010dee36807807fe882ac4", size = 93425, upload-time = "2026-09-10T23:10:35.901Z" }, + { url = "https://files.pythonhosted.org/packages/b7/1d/d53bcf5910209a45191c8bc173ff0e00830416547d8038772dc444932ee0/wrapt-2.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:1fe758b9c2d49138231ec3efabd106fec665f86fec50b3d02d7edd75f08a69ca", size = 98569, upload-time = "2026-09-10T23:10:37.316Z" }, + { url = "https://files.pythonhosted.org/packages/e8/1f/759d0c522918f9dfb620136622d8e1ce619570adda0de8fa2cfbb55cbb86/wrapt-2.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:0c974c36e8205255a3947dad9c2fe000431b57dd522946e56c192174a7f92a0f", size = 95272, upload-time = "2026-09-10T23:10:38.657Z" }, + { url = "https://files.pythonhosted.org/packages/4f/a2/edcfc8d9a30375791b775715f8501364588f65b494ec4f6930568a19e765/wrapt-2.4.1-py3-none-any.whl", hash = "sha256:1e84ec5d89a0a07a0ef6bcd343f5c8ecdc95601d71de3058cdc63274e86c193c", size = 75317, upload-time = "2026-09-10T23:12:14.82Z" }, +] diff --git a/docker/backend.Dockerfile b/docker/backend.Dockerfile index 1cb54e8..05ece9d 100644 --- a/docker/backend.Dockerfile +++ b/docker/backend.Dockerfile @@ -11,7 +11,10 @@ ENV PYTHONDONTWRITEBYTECODE=1 \ COPY --from=uv /uv /uvx /bin/ -RUN groupadd --gid 10001 app \ +RUN apt-get update \ + && apt-get install --yes --no-install-recommends libatomic1 \ + && rm --recursive --force /var/lib/apt/lists/* \ + && groupadd --gid 10001 app \ && useradd --uid 10001 --gid app --create-home --shell /usr/sbin/nologin app WORKDIR /workspace/backend diff --git a/infrastructure_plan.md b/infrastructure_plan.md index b3c80a3..145fd05 100644 --- a/infrastructure_plan.md +++ b/infrastructure_plan.md @@ -4,13 +4,13 @@ ## 1. Project and User Experience -- **Application:** Personal, account-based application with web and mobile clients. +- **Application:** Personal, account-based web application. - **Primary users:** Individual users managing their own data. - **Primary user task:** Not yet specified; the platform supports personal structured data and account workflows. -- **Selected platform:** React web application plus React Native mobile applications for iOS and Android. -- **User-experience rationale:** Provides a consistent service on browsers and mobile devices while keeping the backend in Python. -- **Required operating systems, browsers, or devices:** Current major browsers, supported iOS versions, and supported Android versions. -- **Offline or native-device requirements:** No strong offline requirement confirmed; mobile app release builds require native platform tooling. +- **Selected platform:** React web application. +- **User-experience rationale:** Provides direct browser access while keeping the backend in Python. +- **Required operating systems, browsers, or devices:** Current major browsers. +- **Offline or native-device requirements:** No strong offline or native-device requirement confirmed. ## 2. Connectivity and Application Shape @@ -19,7 +19,7 @@ - **Backend required:** Yes: a single Django application exposes the API and owns account data. - **Cross-device persistence:** Hosted PostgreSQL is the source of truth. - **Interaction between accounts:** None planned; user data remains private to its owner. -- **Primary application components:** Django API, React web client, React Native iOS/Android client, and PostgreSQL. +- **Primary application components:** Django API, React web client, and PostgreSQL. ## 3. Selected Technology Stack @@ -27,14 +27,12 @@ |---|---|---|---| | Primary language | Python | Backend application code | Supported stable Python release compatible with Django | | Web language | TypeScript | Type-safe React web client | Supported stable TypeScript | -| Mobile language | TypeScript | Type-safe React Native client | Supported stable TypeScript | | Application framework | Django with Django REST Framework | Account-aware API and backend | Current supported Django and DRF releases | | Web framework | React with Vite | Browser client and static build | Current supported React and Vite releases | -| Mobile framework | React Native | iOS and Android client | Current supported React Native release | | Python package manager | uv | Reproducible Python dependency management | Current supported release | -| JavaScript package manager | pnpm | Reproducible web and mobile dependencies | Current supported release | -| Build or packaging tool | Vite; React Native platform tooling | Build web assets and mobile release artifacts | Versions pinned by lockfiles | -| API layer | REST over HTTPS | Single API for web and mobile clients | Version endpoints when breaking changes are needed | +| JavaScript package manager | pnpm | Reproducible web dependencies | Current supported release | +| Build tool | Vite | Build web assets | Versions pinned by lockfiles | +| API layer | REST over HTTPS | API for the web client | Version endpoints when breaking changes are needed | ## 4. Storage and Persistence @@ -55,9 +53,7 @@ | Unit | pytest and Django test utilities | Backend domain logic, views, serializers, and permissions | Local and pull requests | | Integration | pytest, Django test client, Testcontainers for PostgreSQL | API, migration, and real-database behavior | Local and pull requests | | Web component | Jest and React Testing Library | React rendering, accessibility, and interaction | Local and pull requests | -| Mobile component | Jest and React Native Testing Library | Mobile component behavior | Local and pull requests | | Web end-to-end | Playwright | Critical account and primary user workflows | Pull requests and releases | -| Mobile end-to-end | Maestro | Critical iOS/Android workflows on supported emulators | Release and scheduled checks | ## 6. Test Analysis @@ -75,9 +71,9 @@ |---|---|---| | Python formatting and linting | Ruff | Blocking pull-request check | | Python type checking | Pyright | Blocking pull-request check | -| Web/mobile formatting | Prettier | Blocking pull-request verification | -| Web/mobile linting | ESLint | Blocking pull-request check | -| Web/mobile type checking | TypeScript compiler | Blocking pull-request check | +| Web formatting | Prettier | Blocking pull-request verification | +| Web linting | ESLint | Blocking pull-request check | +| Web type checking | TypeScript compiler | Blocking pull-request check | | Dependency vulnerability scanning | Dependabot | Automated update proposals and review | | Secret scanning | Gitleaks | Blocking pull-request and release check | | Static security analysis | Bandit, Semgrep, and CodeQL | Bandit/Semgrep on pull requests; CodeQL scheduled and on release | @@ -91,10 +87,8 @@ These are developer-workstation prerequisites that will not be supplied by the p |---|---|---|---|---|---| | Git | Source control | All developer machines | Supported current release | Future documented setup check | Repository work happens on the host | | Docker Desktop or Docker Engine | Local containers | Developers working on backend/database | Supported current release | Future documented setup check | Docker is the host container runtime | -| Node.js and pnpm | React and React Native development | Web/mobile developers and CI runners | Supported Node LTS | Future documented setup check | Needed for host-facing client toolchains | +| Node.js and pnpm | React web development | Web developers and CI runners | Supported Node LTS | Future documented setup check | Needed for the host-facing web toolchain | | Python and uv | Django local development | Backend developers and CI runners | Supported Python release | Future documented setup check | Needed for editor integration and non-container workflows | -| Android Studio and Android SDK | Android emulators and signed builds | Android release/development machines | React Native-compatible SDK | Future documented setup check | Android emulator, SDK, and signing integrate with the host | -| Xcode and Apple tooling | iOS simulator and signed builds | macOS/iOS release machines | React Native-compatible Xcode | Future documented setup check | Apple requires macOS-native signing and packaging | ### Host tools intentionally not required @@ -111,10 +105,10 @@ These are developer-workstation prerequisites that will not be supplied by the p - **Bind mounts and named volumes:** Backend source bind mount for development; named volume for local database persistence. - **Environment-variable and secret handling:** Local non-secret templates only; production values originate in protected hosting and GitHub environments. - **Local database or service containers:** PostgreSQL only unless a later feature adds a justified service. -- **Production image or non-container release path:** Multi-stage, minimal, non-root backend image; Vite build deploys static web files; mobile apps use native store builds. +- **Production image or non-container release path:** Multi-stage, minimal, non-root backend image; Vite build deploys static web files. - **Build stages and hardening:** Multi-stage build, non-root runtime user, minimal runtime image, `.dockerignore`, health check, and no embedded secrets. - **Planned future development command:** Document a future Compose command after Compose files exist; do not run it during planning. -- **Planned future production or packaging command:** Document future image build and mobile packaging commands after their configuration exists; do not run them during planning. +- **Planned future production command:** Document a future image build command after its configuration exists; do not run it during planning. ## 10. GitHub Actions Plan @@ -122,7 +116,7 @@ These are developer-workstation prerequisites that will not be supplied by the p - **Future workflow file:** `.github/workflows/pr-checks.yml` - **Trigger:** `pull_request`. -- **Runner or matrix:** Ubuntu runner for backend, web, database integration, and web E2E; macOS and/or Android-capable runner only when mobile E2E is practical and budgeted. +- **Runner or matrix:** Ubuntu runner for backend, web, database integration, and web E2E. - **Permissions:** Read-only repository contents; grant only the minimal permissions required to report checks or upload artifacts. - **Planned jobs in order:** 1. Checkout, set up pinned Python and Node LTS, restore dependency caches, and perform lockfile-enforced installs. @@ -141,19 +135,19 @@ These are developer-workstation prerequisites that will not be supplied by the p - **Future workflow file:** `.github/workflows/release.yml` - **Release trigger:** Protected `v*` tag or `workflow_dispatch` targeting a protected production environment. -- **Release destination:** Managed hosting for Django backend and React web client; Apple App Store Connect for iOS; Google Play for Android. -- **Runner or matrix:** Ubuntu for validation, image build/scan, backend deployment, and web deployment; macOS for iOS signing/build; Android-capable runner for Android signing/build. +- **Release destination:** Managed hosting for the Django backend and React web client. +- **Runner or matrix:** Ubuntu for validation, image build/scan, backend deployment, and web deployment. - **Planned jobs in order:** - 1. Validate the release commit using the required checks and build backend, web, iOS, and Android artifacts. + 1. Validate the release commit using the required checks and build backend and web artifacts. 2. Scan the backend image, publish it to the selected registry, then deploy backend and static web assets after protected-environment approval. - 3. Apply reviewed Django migrations once, run smoke checks, sign mobile builds, and upload them to App Store Connect and Google Play. + 3. Apply reviewed Django migrations once and run smoke checks. 4. Publish GitHub Release notes with checksums and links to release artifacts where appropriate. -- **Build artifacts:** Backend container digest, web build identifier, signed iOS archive, signed Android app bundle, checksums, and release notes. -- **Signing, notarization, or store requirements:** Apple Developer account, App Store Connect credentials/certificates/profiles, Google Play developer account and signing key, and protected secret storage. +- **Build artifacts:** Backend container digest, web build identifier, checksums, and release notes. +- **Signing, notarization, or store requirements:** Protected secret storage for hosting and registry deployment credentials. - **Database migration step:** Run controlled Django migrations after a verified backup point and before traffic relies on schema changes. - **Environment approval:** Use a protected GitHub `production` environment for backend/web deployment and release credentials. -- **Post-deployment verification:** Authenticated and unauthenticated health checks plus critical web API smoke tests; confirm store upload status. -- **Failed-release or rollback approach:** Redeploy the prior backend image and web build; use backward-compatible migrations or a reviewed migration recovery procedure; halt store rollout when needed. +- **Post-deployment verification:** Authenticated and unauthenticated health checks plus critical web API smoke tests. +- **Failed-release or rollback approach:** Redeploy the prior backend image and web build; use backward-compatible migrations or a reviewed migration recovery procedure. ### GitHub configuration required later @@ -163,23 +157,21 @@ These are developer-workstation prerequisites that will not be supplied by the p | `DATABASE_URL` | Secret | Production PostgreSQL connection string | | `DJANGO_SECRET_KEY` | Secret | Django cryptographic secret | | `DEPLOY_*` | Secret/token | Managed-hosting and container-registry deployment credentials | -| `APPLE_*` | Secret/certificate/account | App Store Connect API credentials, signing certificates, and provisioning data | -| `GOOGLE_PLAY_*` | Secret/account | Google Play service account credential and Android signing material | | `CODEQL` configuration | Repository security configuration | Enable scheduled code scanning results | ## 11. Planned Repository Artifacts - Not Created by This Skill - [ ] Backend application manifest/project file and Python lockfile. -- [ ] Web and mobile package manifests and pnpm lockfile. -- [ ] Backend, web, and mobile test configuration. +- [ ] Web package manifest and pnpm lockfile. +- [ ] Backend and web test configuration. - [ ] Ruff, Pyright, Prettier, ESLint, TypeScript, Bandit, Semgrep, and Gitleaks configuration. - [ ] Backend `Dockerfile`, Compose file, `.dockerignore`, and non-secret environment template. - [ ] `.github/workflows/pr-checks.yml`. - [ ] `.github/workflows/release.yml`. -- [ ] Managed-hosting and mobile-store release configuration. +- [ ] Managed-hosting release configuration. ## 12. Assumptions and Open Items - **Assumptions:** The application handles private personal data, requires normal account authentication, does not currently require uploads, collaboration, or offline-first synchronization, and will use one deployable Django backend rather than microservices. -- **Decisions still requiring an external account, credential, certificate, or organizational approval:** Hosting provider and container registry; PostgreSQL provider; Apple Developer/App Store Connect account and signing assets; Google Play developer account and Android signing key; production-domain ownership. -- **Items to confirm before implementation begins:** Primary user workflow and data model, authentication provider/method, privacy and retention requirements, exact supported OS/browser versions, hosting and registry providers, coverage threshold, and mobile release ownership. +- **Decisions still requiring an external account, credential, certificate, or organizational approval:** Hosting provider and container registry; PostgreSQL provider; production-domain ownership. +- **Items to confirm before implementation begins:** Primary user workflow and data model, authentication provider/method, privacy and retention requirements, exact supported browser versions, hosting and registry providers, and coverage threshold. diff --git a/web/.prettierignore b/web/.prettierignore new file mode 100644 index 0000000..99a8969 --- /dev/null +++ b/web/.prettierignore @@ -0,0 +1,3 @@ +.pnpm-store/ +coverage/ +node_modules/ diff --git a/web/eslint.config.mjs b/web/eslint.config.mjs new file mode 100644 index 0000000..f7812ae --- /dev/null +++ b/web/eslint.config.mjs @@ -0,0 +1,17 @@ +import eslint from "@eslint/js"; + +export default [ + { + ignores: [".pnpm-store/**", "coverage/**", "node_modules/**"], + }, + eslint.configs.recommended, + { + files: ["tests/**/*.test.cjs"], + languageOptions: { + globals: { + expect: "readonly", + test: "readonly", + }, + }, + }, +]; diff --git a/web/jest.config.cjs b/web/jest.config.cjs new file mode 100644 index 0000000..229808a --- /dev/null +++ b/web/jest.config.cjs @@ -0,0 +1,5 @@ +/** Infrastructure-only Jest configuration; application test setup comes later. */ +module.exports = { + collectCoverageFrom: ["tests/infrastructure/**/*.cjs"], + testMatch: ["/tests/**/*.test.cjs"], +}; diff --git a/web/package.json b/web/package.json new file mode 100644 index 0000000..1e69afb --- /dev/null +++ b/web/package.json @@ -0,0 +1,36 @@ +{ + "name": "medcheck-web", + "version": "0.0.0", + "private": true, + "packageManager": "pnpm@10.4.1", + "description": "Infrastructure-only web tooling for Medcheck.", + "engines": { + "node": ">=22 <23", + "pnpm": ">=10 <11" + }, + "scripts": { + "format:check": "prettier --check .", + "lint": "eslint . --max-warnings=0", + "typecheck": "tsc --noEmit --project tsconfig.json", + "test": "jest --coverage", + "test:e2e": "playwright test", + "build": "echo 'A Vite build is unavailable until the web application entrypoint is implemented.' >&2; exit 1" + }, + "dependencies": { + "react": "^19.0.0", + "react-dom": "^19.0.0" + }, + "devDependencies": { + "@eslint/js": "^10.0.0", + "@playwright/test": "^1.50.0", + "@types/jest": "^29.5.0", + "@types/react": "^19.0.0", + "@types/react-dom": "^19.0.0", + "eslint": "^10.0.0", + "jest": "^29.7.0", + "prettier": "^3.0.0", + "typescript": "^5.0.0", + "typescript-eslint": "^8.0.0", + "vite": "^6.0.0" + } +} diff --git a/web/playwright.config.ts b/web/playwright.config.ts new file mode 100644 index 0000000..6431494 --- /dev/null +++ b/web/playwright.config.ts @@ -0,0 +1,4 @@ +import { defineConfig } from "@playwright/test"; + +// No web server is defined until the application entrypoint exists. +export default defineConfig({ testDir: "tests/e2e" }); diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml new file mode 100644 index 0000000..024e0d7 --- /dev/null +++ b/web/pnpm-lock.yaml @@ -0,0 +1,5143 @@ +lockfileVersion: "9.0" + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + .: + dependencies: + react: + specifier: ^19.0.0 + version: 19.3.0 + react-dom: + specifier: ^19.0.0 + version: 19.3.0(react@19.3.0) + devDependencies: + "@eslint/js": + specifier: ^10.0.0 + version: 10.0.1(eslint@10.11.0) + "@playwright/test": + specifier: ^1.50.0 + version: 1.63.0 + "@types/jest": + specifier: ^29.5.0 + version: 29.5.14 + "@types/react": + specifier: ^19.0.0 + version: 19.3.0 + "@types/react-dom": + specifier: ^19.0.0 + version: 19.3.0(@types/react@19.3.0) + eslint: + specifier: ^10.0.0 + version: 10.11.0 + jest: + specifier: ^29.7.0 + version: 29.7.0(@types/node@26.6.2) + prettier: + specifier: ^3.0.0 + version: 3.9.8 + typescript: + specifier: ^5.0.0 + version: 5.9.3 + typescript-eslint: + specifier: ^8.0.0 + version: 8.70.1(eslint@10.11.0)(typescript@5.9.3) + vite: + specifier: ^6.0.0 + version: 6.4.3(@types/node@26.6.2) + +packages: + "@babel/code-frame@7.29.7": + resolution: + { + integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==, + } + engines: { node: ">=6.9.0" } + + "@babel/compat-data@7.29.7": + resolution: + { + integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==, + } + engines: { node: ">=6.9.0" } + + "@babel/core@7.29.7": + resolution: + { + integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==, + } + engines: { node: ">=6.9.0" } + + "@babel/generator@7.29.8": + resolution: + { + integrity: sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==, + } + engines: { node: ">=6.9.0" } + + "@babel/helper-compilation-targets@7.29.7": + resolution: + { + integrity: sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==, + } + engines: { node: ">=6.9.0" } + + "@babel/helper-globals@7.29.7": + resolution: + { + integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==, + } + engines: { node: ">=6.9.0" } + + "@babel/helper-module-imports@7.29.7": + resolution: + { + integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==, + } + engines: { node: ">=6.9.0" } + + "@babel/helper-module-transforms@7.29.7": + resolution: + { + integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0 + + "@babel/helper-plugin-utils@7.29.7": + resolution: + { + integrity: sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==, + } + engines: { node: ">=6.9.0" } + + "@babel/helper-string-parser@7.29.7": + resolution: + { + integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==, + } + engines: { node: ">=6.9.0" } + + "@babel/helper-validator-identifier@7.29.7": + resolution: + { + integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==, + } + engines: { node: ">=6.9.0" } + + "@babel/helper-validator-option@7.29.7": + resolution: + { + integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==, + } + engines: { node: ">=6.9.0" } + + "@babel/helpers@7.29.7": + resolution: + { + integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==, + } + engines: { node: ">=6.9.0" } + + "@babel/parser@7.29.9": + resolution: + { + integrity: sha512-CjXrNHTnvqBVqHgdBysY3vk2T8tpJHb5/RMeHJBTyVa9xgugCB0CJTx/3oO8RV2QRQP391RWpB7D6hLjm8V9uA==, + } + engines: { node: ">=6.0.0" } + hasBin: true + + "@babel/plugin-syntax-async-generators@7.8.4": + resolution: + { + integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==, + } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-syntax-bigint@7.8.3": + resolution: + { + integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==, + } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-syntax-class-properties@7.12.13": + resolution: + { + integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==, + } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-syntax-class-static-block@7.14.5": + resolution: + { + integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-syntax-import-attributes@7.29.7": + resolution: + { + integrity: sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-syntax-import-meta@7.10.4": + resolution: + { + integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==, + } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-syntax-json-strings@7.8.3": + resolution: + { + integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==, + } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-syntax-jsx@7.29.7": + resolution: + { + integrity: sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-syntax-logical-assignment-operators@7.10.4": + resolution: + { + integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==, + } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-syntax-nullish-coalescing-operator@7.8.3": + resolution: + { + integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==, + } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-syntax-numeric-separator@7.10.4": + resolution: + { + integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==, + } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-syntax-object-rest-spread@7.8.3": + resolution: + { + integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==, + } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-syntax-optional-catch-binding@7.8.3": + resolution: + { + integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==, + } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-syntax-optional-chaining@7.8.3": + resolution: + { + integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==, + } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-syntax-private-property-in-object@7.14.5": + resolution: + { + integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-syntax-top-level-await@7.14.5": + resolution: + { + integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-syntax-typescript@7.29.7": + resolution: + { + integrity: sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/template@7.29.7": + resolution: + { + integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==, + } + engines: { node: ">=6.9.0" } + + "@babel/traverse@7.29.8": + resolution: + { + integrity: sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==, + } + engines: { node: ">=6.9.0" } + + "@babel/types@7.29.8": + resolution: + { + integrity: sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==, + } + engines: { node: ">=6.9.0" } + + "@bcoe/v8-coverage@0.2.3": + resolution: + { + integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==, + } + + "@cacheable/memory@2.2.0": + resolution: + { + integrity: sha512-CTLKqLItRCEixEAewD3/j9DB3/o96gpTPD4eJ1v+DGOlxZRZncRQkGYqqnAGCscYd6RNeXfGeiuCphsPtqyIfQ==, + } + + "@cacheable/utils@2.5.0": + resolution: + { + integrity: sha512-buipgOVDkkPXNR5+xBpDw7Zk2n1EvU7qBJCNUcL7rhQ//kfpOXPAvQ511Os0vpLYJ1pZnvudNytkQt2hst3wqA==, + } + + "@esbuild/aix-ppc64@0.25.12": + resolution: + { + integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==, + } + engines: { node: ">=18" } + cpu: [ppc64] + os: [aix] + + "@esbuild/android-arm64@0.25.12": + resolution: + { + integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==, + } + engines: { node: ">=18" } + cpu: [arm64] + os: [android] + + "@esbuild/android-arm@0.25.12": + resolution: + { + integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==, + } + engines: { node: ">=18" } + cpu: [arm] + os: [android] + + "@esbuild/android-x64@0.25.12": + resolution: + { + integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==, + } + engines: { node: ">=18" } + cpu: [x64] + os: [android] + + "@esbuild/darwin-arm64@0.25.12": + resolution: + { + integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==, + } + engines: { node: ">=18" } + cpu: [arm64] + os: [darwin] + + "@esbuild/darwin-x64@0.25.12": + resolution: + { + integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==, + } + engines: { node: ">=18" } + cpu: [x64] + os: [darwin] + + "@esbuild/freebsd-arm64@0.25.12": + resolution: + { + integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==, + } + engines: { node: ">=18" } + cpu: [arm64] + os: [freebsd] + + "@esbuild/freebsd-x64@0.25.12": + resolution: + { + integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==, + } + engines: { node: ">=18" } + cpu: [x64] + os: [freebsd] + + "@esbuild/linux-arm64@0.25.12": + resolution: + { + integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==, + } + engines: { node: ">=18" } + cpu: [arm64] + os: [linux] + + "@esbuild/linux-arm@0.25.12": + resolution: + { + integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==, + } + engines: { node: ">=18" } + cpu: [arm] + os: [linux] + + "@esbuild/linux-ia32@0.25.12": + resolution: + { + integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==, + } + engines: { node: ">=18" } + cpu: [ia32] + os: [linux] + + "@esbuild/linux-loong64@0.25.12": + resolution: + { + integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==, + } + engines: { node: ">=18" } + cpu: [loong64] + os: [linux] + + "@esbuild/linux-mips64el@0.25.12": + resolution: + { + integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==, + } + engines: { node: ">=18" } + cpu: [mips64el] + os: [linux] + + "@esbuild/linux-ppc64@0.25.12": + resolution: + { + integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==, + } + engines: { node: ">=18" } + cpu: [ppc64] + os: [linux] + + "@esbuild/linux-riscv64@0.25.12": + resolution: + { + integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==, + } + engines: { node: ">=18" } + cpu: [riscv64] + os: [linux] + + "@esbuild/linux-s390x@0.25.12": + resolution: + { + integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==, + } + engines: { node: ">=18" } + cpu: [s390x] + os: [linux] + + "@esbuild/linux-x64@0.25.12": + resolution: + { + integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==, + } + engines: { node: ">=18" } + cpu: [x64] + os: [linux] + + "@esbuild/netbsd-arm64@0.25.12": + resolution: + { + integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==, + } + engines: { node: ">=18" } + cpu: [arm64] + os: [netbsd] + + "@esbuild/netbsd-x64@0.25.12": + resolution: + { + integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==, + } + engines: { node: ">=18" } + cpu: [x64] + os: [netbsd] + + "@esbuild/openbsd-arm64@0.25.12": + resolution: + { + integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==, + } + engines: { node: ">=18" } + cpu: [arm64] + os: [openbsd] + + "@esbuild/openbsd-x64@0.25.12": + resolution: + { + integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==, + } + engines: { node: ">=18" } + cpu: [x64] + os: [openbsd] + + "@esbuild/openharmony-arm64@0.25.12": + resolution: + { + integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==, + } + engines: { node: ">=18" } + cpu: [arm64] + os: [openharmony] + + "@esbuild/sunos-x64@0.25.12": + resolution: + { + integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==, + } + engines: { node: ">=18" } + cpu: [x64] + os: [sunos] + + "@esbuild/win32-arm64@0.25.12": + resolution: + { + integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==, + } + engines: { node: ">=18" } + cpu: [arm64] + os: [win32] + + "@esbuild/win32-ia32@0.25.12": + resolution: + { + integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==, + } + engines: { node: ">=18" } + cpu: [ia32] + os: [win32] + + "@esbuild/win32-x64@0.25.12": + resolution: + { + integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==, + } + engines: { node: ">=18" } + cpu: [x64] + os: [win32] + + "@eslint-community/eslint-utils@4.10.1": + resolution: + { + integrity: sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==, + } + 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.12.2": + resolution: + { + integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==, + } + engines: { node: ^12.0.0 || ^14.0.0 || >=16.0.0 } + + "@eslint/config-array@0.23.5": + resolution: + { + integrity: sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==, + } + engines: { node: ^20.19.0 || ^22.13.0 || >=24 } + + "@eslint/config-helpers@0.7.0": + resolution: + { + integrity: sha512-DObd/KKUsU+FaFv4PLxSRenpXfQWmPXXP3pPZ6/K1PCrMu2vQpMDMuQe/BqYeoLcz8ro0bVDF1RxOJgfVEdhUw==, + } + engines: { node: ^20.19.0 || ^22.13.0 || >=24 } + + "@eslint/core@1.2.1": + resolution: + { + integrity: sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==, + } + engines: { node: ^20.19.0 || ^22.13.0 || >=24 } + + "@eslint/js@10.0.1": + resolution: + { + integrity: sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==, + } + engines: { node: ^20.19.0 || ^22.13.0 || >=24 } + peerDependencies: + eslint: ^10.0.0 + peerDependenciesMeta: + eslint: + optional: true + + "@eslint/object-schema@3.0.5": + resolution: + { + integrity: sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==, + } + engines: { node: ^20.19.0 || ^22.13.0 || >=24 } + + "@eslint/plugin-kit@0.7.3": + resolution: + { + integrity: sha512-IkO+/KEUvwbVpiURZg+P7zF74z5Jxe0UgJxVni+RtoHQ6IZieXaO02kmadomap/q+l6bc/jdPGGqTjhuZnuz1Q==, + } + engines: { node: ^20.19.0 || ^22.13.0 || >=24 } + + "@humanfs/core@0.19.2": + resolution: + { + integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==, + } + engines: { node: ">=18.18.0" } + + "@humanfs/node@0.16.8": + resolution: + { + integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==, + } + engines: { node: ">=18.18.0" } + + "@humanfs/types@0.15.0": + resolution: + { + integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==, + } + engines: { node: ">=18.18.0" } + + "@humanwhocodes/module-importer@1.0.1": + resolution: + { + integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==, + } + engines: { node: ">=12.22" } + + "@humanwhocodes/retry@0.4.3": + resolution: + { + integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==, + } + engines: { node: ">=18.18" } + + "@istanbuljs/load-nyc-config@1.1.0": + resolution: + { + integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==, + } + engines: { node: ">=8" } + + "@istanbuljs/schema@0.1.6": + resolution: + { + integrity: sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==, + } + engines: { node: ">=8" } + + "@jest/console@29.7.0": + resolution: + { + integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + "@jest/core@29.7.0": + resolution: + { + integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + "@jest/environment@29.7.0": + resolution: + { + integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + "@jest/expect-utils@29.7.0": + resolution: + { + integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + "@jest/expect@29.7.0": + resolution: + { + integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + "@jest/fake-timers@29.7.0": + resolution: + { + integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + "@jest/globals@29.7.0": + resolution: + { + integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + "@jest/reporters@29.7.0": + resolution: + { + integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + "@jest/schemas@29.6.3": + resolution: + { + integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + "@jest/source-map@29.6.3": + resolution: + { + integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + "@jest/test-result@29.7.0": + resolution: + { + integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + "@jest/test-sequencer@29.7.0": + resolution: + { + integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + "@jest/transform@29.7.0": + resolution: + { + integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + "@jest/types@29.6.3": + resolution: + { + integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + "@jridgewell/gen-mapping@0.3.13": + resolution: + { + integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==, + } + + "@jridgewell/remapping@2.3.5": + resolution: + { + integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==, + } + + "@jridgewell/resolve-uri@3.1.2": + resolution: + { + integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==, + } + engines: { node: ">=6.0.0" } + + "@jridgewell/sourcemap-codec@1.6.0": + resolution: + { + integrity: sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==, + } + + "@jridgewell/trace-mapping@0.3.31": + resolution: + { + integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==, + } + + "@keyv/bigmap@1.3.1": + resolution: + { + integrity: sha512-WbzE9sdmQtKy8vrNPa9BRnwZh5UF4s1KTmSK0KUVLo3eff5BlQNNWDnFOouNpKfPKDnms9xynJjsMYjMaT/aFQ==, + } + engines: { node: ">= 18" } + peerDependencies: + keyv: ^5.6.0 + + "@keyv/serialize@1.1.1": + resolution: + { + integrity: sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==, + } + + "@napi-rs/lzma-linux-x64-gnu@1.5.1": + resolution: + { + integrity: sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==, + } + engines: { node: ^22.20 || ^24.12 || >=25 } + cpu: [x64] + os: [linux] + + "@playwright/test@1.63.0": + resolution: + { + integrity: sha512-oxMK4vllB9RK5NQ2l1pq1IfOf2AvnEuj/vYGDj0H2nMtmtZpKtCwt/l00GEO6xjGfpBNAvjovvYdCm50dRQkpQ==, + } + engines: { node: ">=20" } + hasBin: true + + "@rollup/rollup-android-arm-eabi@4.63.4": + resolution: + { + integrity: sha512-I+BSHzTAhKN2n7ZwGZsegGcZjDpLqFOMAtJz/u6uFGe0pUFbq56dEHjqJV/ZUdRJtNXNxA+hREUatZBvMR3Oiw==, + } + cpu: [arm] + os: [android] + + "@rollup/rollup-android-arm64@4.63.4": + resolution: + { + integrity: sha512-pu3BdjS2LtEzRu2elmGzS3fIeWSZy4BMDIaLNwjorO76+k2d0LMluijhsDx3KQyQBQ/lLUZCQA9/s6csvUfuhw==, + } + cpu: [arm64] + os: [android] + + "@rollup/rollup-darwin-arm64@4.63.4": + resolution: + { + integrity: sha512-xfSrj9MHnWK9GaSqT9U0ImHtH/N8WZlHLx4cZHiuLcqs640hvZ3hLPd5UR2AZS57FaE8HrRUSpltbZdWRxHiDA==, + } + cpu: [arm64] + os: [darwin] + + "@rollup/rollup-darwin-x64@4.63.4": + resolution: + { + integrity: sha512-bqU99PLJb/dqb3S0GIMdeuyAEETSUgZBoqXYd3Sd+WCsV+MmPhnN6JrotWyir31+QgH7EvvE5/mwGJlEoci8Fw==, + } + cpu: [x64] + os: [darwin] + + "@rollup/rollup-freebsd-arm64@4.63.4": + resolution: + { + integrity: sha512-JinsFZ5G40oXQb+sUuiA5x689vhr6dDYK0H0NL+rwKdL6CqnmYN8PE4ZwfRSoIjrCxqTQG/SLfTtSvHeGxoVlw==, + } + cpu: [arm64] + os: [freebsd] + + "@rollup/rollup-freebsd-x64@4.63.4": + resolution: + { + integrity: sha512-GAdA4UxpiNm27cLHr2GqXBpAD0x9FqwYBY7/YSP0Ss0/PNi4k8gbviqpIpYbVSRBaS2ZcegXEzgTQMbRNCwxCw==, + } + cpu: [x64] + os: [freebsd] + + "@rollup/rollup-linux-arm-gnueabihf@4.63.4": + resolution: + { + integrity: sha512-qDd6NoA1znaLjp4jR5U/KWCdLAKDJNB8W9ChbbDaKbo0xA+Atln5HK6LFCZ4oJQpemtRZA288DCirFRjrspptw==, + } + cpu: [arm] + os: [linux] + + "@rollup/rollup-linux-arm-musleabihf@4.63.4": + resolution: + { + integrity: sha512-WtB5Tz5KTNINb8ZA+8sQ7bmjuS1JrRT7YverYIhUGdWWDlpzVWmIwuZE+jidkEXUn1l0zrEkaIMa8dHF3NGcsA==, + } + cpu: [arm] + os: [linux] + + "@rollup/rollup-linux-arm64-gnu@4.63.4": + resolution: + { + integrity: sha512-VcQ3L1tjnkKzWjryAVaFhHEWcqOfICX9uxVVoDzm2t0DpgKRHd2zOpVrJc0xsWeBZcBFyYROCIBdyR/fS174pg==, + } + cpu: [arm64] + os: [linux] + + "@rollup/rollup-linux-arm64-musl@4.63.4": + resolution: + { + integrity: sha512-6+ZQX6P5s0cMDN2Ypb8Lbm2+/sZYmZjdaYny992ujUU9UKi/4CWoJWsl1pNvjWJHNHGK51m+jKGLlh1ylb2ifQ==, + } + cpu: [arm64] + os: [linux] + + "@rollup/rollup-linux-loong64-gnu@4.63.4": + resolution: + { + integrity: sha512-D72ZnvkFkBXOfzMMQLcwfPLyGkKb7HZ9/mf97B7v6/P5Lbv4oFOtSY/uHbS8lH6uKUOxoKiuokdb50XZSzzbJw==, + } + cpu: [loong64] + os: [linux] + + "@rollup/rollup-linux-loong64-musl@4.63.4": + resolution: + { + integrity: sha512-piU6BxeqA3O9KSu3kRCIQQtNqFFaTu21SEV4FwaRZowpnj3bLaWPZHw+xFqCs0XlJ+aOH3PTRWGoglH+mKA/OA==, + } + cpu: [loong64] + os: [linux] + + "@rollup/rollup-linux-ppc64-gnu@4.63.4": + resolution: + { + integrity: sha512-/5PGpHwqt2EEEOUs1XwzubE/ucr0dWDQ+to3zqi4Ds7EWpwtQ79wXc4JBoxqj/OwpawTsKWzJxHfSuBOq3DrWA==, + } + cpu: [ppc64] + os: [linux] + + "@rollup/rollup-linux-ppc64-musl@4.63.4": + resolution: + { + integrity: sha512-cX3beZDLWt7G2oJF+nhChiT+qtaihs+S2xi7ziGmVB+2pwPng6D0Ed0HmElQOgv2UsUmSJJLGwpBao/3TDx3VA==, + } + cpu: [ppc64] + os: [linux] + + "@rollup/rollup-linux-riscv64-gnu@4.63.4": + resolution: + { + integrity: sha512-1uz2mGWHyptR7DgHHrlbdRAjXK7v7elGZ9lMja910/RP+ZYbX6xAmCiU9UZSX4hqmgtHMv6lr5l3kq1HIOpcag==, + } + cpu: [riscv64] + os: [linux] + + "@rollup/rollup-linux-riscv64-musl@4.63.4": + resolution: + { + integrity: sha512-nLS8topojxyz7SRpKR2IODRpQ0XPZ+xaOXvT3+hqK/Uy8Lo5HFgkkIBiIrCu5tL5YqzTvgovGw55PwpahTAGig==, + } + cpu: [riscv64] + os: [linux] + + "@rollup/rollup-linux-s390x-gnu@4.63.4": + resolution: + { + integrity: sha512-gs7DRKotr3l3q+jGPQBjH0ng1FjlEDm5ueQrkw5JtQvtLyEIcLASqAEaor56BhkKRzk+IcQzrcanBdb/bBQn8g==, + } + cpu: [s390x] + os: [linux] + + "@rollup/rollup-linux-x64-gnu@4.63.4": + resolution: + { + integrity: sha512-791ET7W17NnScOZM7h4dX5hYspxE28htPFsb1awY/NRR8+PRNkS53e475rDdxXXDrP+kwnCcNWg9CX5ztn/Aqw==, + } + cpu: [x64] + os: [linux] + + "@rollup/rollup-linux-x64-musl@4.63.4": + resolution: + { + integrity: sha512-iwZQRcmj7g88g3tzefIrQY7qvmuA/cfYwhrDtTBhsmukO4U2huVO5W+86XacUMRvdSFVAc6kZUZy21JaRwiB9w==, + } + cpu: [x64] + os: [linux] + + "@rollup/rollup-openbsd-x64@4.63.4": + resolution: + { + integrity: sha512-dVHFp9gRWrdTpnqQuGfCwd7hOQDatK1VCP2iWhLY/cGrOQs/ucFzJ6A5SRqbXX12ZDI8EUuejSM5kwg+ja7Png==, + } + cpu: [x64] + os: [openbsd] + + "@rollup/rollup-openharmony-arm64@4.63.4": + resolution: + { + integrity: sha512-t3NlauOW6gxZVVFcBEnO62Cb4wbyDFL416gTg1uFI/2tgqYQlf69FbSE115Ajre9I+c26Lk4mcmdFUsS/DGifQ==, + } + cpu: [arm64] + os: [openharmony] + + "@rollup/rollup-win32-arm64-msvc@4.63.4": + resolution: + { + integrity: sha512-xWuIaSye5FWZF8+UYtVEcHtRJDN5kN9Kfgxx3Kq8XIov9KSKbc1fiqQCm90SKrgQbUXZelbnUhnlUJmfSE7P9A==, + } + cpu: [arm64] + os: [win32] + + "@rollup/rollup-win32-ia32-msvc@4.63.4": + resolution: + { + integrity: sha512-9ALJJUOg/ZflMJepVo2PlgsGxSaxN7SQ4Z8GoZfVlarWr6r3rkHUNsd/zAio7p4YMtChSMXPionxej4Hkf6CXQ==, + } + cpu: [ia32] + os: [win32] + + "@rollup/rollup-win32-x64-gnu@4.63.4": + resolution: + { + integrity: sha512-blj9z5qx/Pv4WU0W1NMFDB97e0JH5ed+aZGywW8WCvp/NhWX/4PFAq5uu6Q0AebNn+Vo6KzUYDT++JzTT5ojlQ==, + } + cpu: [x64] + os: [win32] + + "@rollup/rollup-win32-x64-msvc@4.63.4": + resolution: + { + integrity: sha512-Erx822VRBwLa124shbj+wNXe//BOgMEctDV0m1aqTQdNO1S69DgNUCFKC1RCeZfixs1J31l6igk1ziyXErbigQ==, + } + cpu: [x64] + os: [win32] + + "@sinclair/typebox@0.27.12": + resolution: + { + integrity: sha512-hhyNJ+nbR6ZR7pToHvllEFun9TL0sbL+tk/ON75lo+Xas054uez98qRbsuNt7MBCyZKK4+8Yli/OAGZhmfBZ/g==, + } + + "@sinonjs/commons@3.0.1": + resolution: + { + integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==, + } + + "@sinonjs/fake-timers@10.3.0": + resolution: + { + integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==, + } + + "@types/babel__core@7.20.5": + resolution: + { + integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==, + } + + "@types/babel__generator@7.27.0": + resolution: + { + integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==, + } + + "@types/babel__template@7.4.4": + resolution: + { + integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==, + } + + "@types/babel__traverse@7.28.0": + resolution: + { + integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==, + } + + "@types/esrecurse@4.3.1": + resolution: + { + integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==, + } + + "@types/estree@1.0.9": + resolution: + { + integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==, + } + + "@types/graceful-fs@4.1.9": + resolution: + { + integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==, + } + + "@types/istanbul-lib-coverage@2.0.6": + resolution: + { + integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==, + } + + "@types/istanbul-lib-report@3.0.3": + resolution: + { + integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==, + } + + "@types/istanbul-reports@3.0.4": + resolution: + { + integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==, + } + + "@types/jest@29.5.14": + resolution: + { + integrity: sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==, + } + + "@types/json-schema@7.0.15": + resolution: + { + integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==, + } + + "@types/node@26.6.2": + resolution: + { + integrity: sha512-X1P21scMv4zGKLYqjdGjaKa7COa0RKVYYZZN/NfvLQ1JegxFhdhpZG/Lyn8AXx6CDUavKAd11v6BvfpkDByK8g==, + } + + "@types/react-dom@19.3.0": + resolution: + { + integrity: sha512-ZI7bU42mZXXKHn/qNLEw2IrbiINU7X5+vfgdixBHkCNpYWXjKgfQ/P+uyGb5CjOLB9UcnTeg3rylQtV2hym44Q==, + } + peerDependencies: + "@types/react": ^19.3.0 + + "@types/react@19.3.0": + resolution: + { + integrity: sha512-N0rFCuH9YoxG9/m61l9MfpJKfmLOVU0em7ipIz6TRgSSkvReLB9vL85GB+yr8Bs5leqpvg96JSwF4ZS1s4viQg==, + } + + "@types/stack-utils@2.0.3": + resolution: + { + integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==, + } + + "@types/yargs-parser@21.0.3": + resolution: + { + integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==, + } + + "@types/yargs@17.0.35": + resolution: + { + integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==, + } + + "@typescript-eslint/eslint-plugin@8.70.1": + resolution: + { + integrity: sha512-nDNrUQ/4ruSNYbu749TRY7cfrzPtoLHEXSNBI8aaNY32LlZCajixqRf3FqcKC4p5Cam4VOHYx/t+i5+nKXvrqA==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + peerDependencies: + "@typescript-eslint/parser": ^8.70.1 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: ">=4.8.4 <6.1.0" + + "@typescript-eslint/parser@8.70.1": + resolution: + { + integrity: sha512-nO974WLllwhSFWQXnMLj6nDGa8f0khKEz1JzpPJ1u7Vm/4X1X6ZHajpoknU4bb41vJyMB0HHVyS2GqdhWfIXZw==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: ">=4.8.4 <6.1.0" + + "@typescript-eslint/project-service@8.70.1": + resolution: + { + integrity: sha512-62xOgboPfwc3/IgPSX/W6oQR3ZbF04194FPGUGH8HL8iLFHbt/456/8Ph1wLNUgVF+s94FlHoipBsz+v7+LMnA==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + peerDependencies: + typescript: ">=4.8.4 <6.1.0" + + "@typescript-eslint/scope-manager@8.70.1": + resolution: + { + integrity: sha512-Pa0EeSeAusQc1WbjQMac+YfenewYTBu0KjgYvkUKwhXaHUKbFog23Dm/rp0DX/6tyYOQ3Xl1a+3EcFNZynGHCw==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + "@typescript-eslint/tsconfig-utils@8.70.1": + resolution: + { + integrity: sha512-jumze1fPI+sDOaM2TWGQdn39PDxTr7TZGeuyLkAbNyx2vtMT3uRnVKChN0hfht5V2TugphJzF6bYXvBcE09qqg==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + peerDependencies: + typescript: ">=4.8.4 <6.1.0" + + "@typescript-eslint/type-utils@8.70.1": + resolution: + { + integrity: sha512-7zKTnyvaVWqzLZHPFQtX1hVHqgkMC+WebPWakNCSyrQVbIP1AM0L0TlBZtACldIRb6PptI8Odk+jyZ5kP3B1VA==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: ">=4.8.4 <6.1.0" + + "@typescript-eslint/types@8.70.1": + resolution: + { + integrity: sha512-Dm1ypdhhrGCTyyehxElhgJ6kgk8MVCv5qXdoOVqPr1uqk42jX8KjrZqhROvdShczA8qrDoYiOWn1ykWlx2k81Q==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + "@typescript-eslint/typescript-estree@8.70.1": + resolution: + { + integrity: sha512-TU8PwyGN0PQJUcE96mw8eCQ44SmxGdQlJmlWakHaHQ15eIuuvye5yNtmh/i6oS88jzXVQB71xdNkbkB/fMwL0g==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + peerDependencies: + typescript: ">=4.8.4 <6.1.0" + + "@typescript-eslint/utils@8.70.1": + resolution: + { + integrity: sha512-Esgul8MsnKnRLdYU2Eb2cRV9bS5HJYtKj1ByJnOzzG2M58DGdSUQ1jUuILxipqcpB2h9WLrbD5GijIWUjX/Tqw==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: ">=4.8.4 <6.1.0" + + "@typescript-eslint/visitor-keys@8.70.1": + resolution: + { + integrity: sha512-Vwj9lUIW5Xq3wQ9w6gv3R86g1hMK8f2zNOdGTAgeXUMMXFK78G9ruCjjqutHMNJc0+CH7LYRnHeUB9IT8wFmcw==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + acorn-jsx@5.3.2: + resolution: + { + integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==, + } + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.18.0: + resolution: + { + integrity: sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==, + } + engines: { node: ">=0.4.0" } + hasBin: true + + ajv@6.15.0: + resolution: + { + integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==, + } + + ansi-escapes@4.3.2: + resolution: + { + integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==, + } + engines: { node: ">=8" } + + ansi-regex@5.0.1: + resolution: + { + integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==, + } + engines: { node: ">=8" } + + 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" } + + anymatch@3.1.3: + resolution: + { + integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==, + } + engines: { node: ">= 8" } + + argparse@1.0.10: + resolution: + { + integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==, + } + + babel-jest@29.7.0: + resolution: + { + integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + peerDependencies: + "@babel/core": ^7.8.0 + + babel-plugin-istanbul@6.1.1: + resolution: + { + integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==, + } + engines: { node: ">=8" } + + babel-plugin-jest-hoist@29.6.3: + resolution: + { + integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + babel-preset-current-node-syntax@1.2.0: + resolution: + { + integrity: sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==, + } + peerDependencies: + "@babel/core": ^7.0.0 || ^8.0.0-0 + + babel-preset-jest@29.6.3: + resolution: + { + integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + peerDependencies: + "@babel/core": ^7.0.0 + + balanced-match@1.0.2: + resolution: + { + integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==, + } + + balanced-match@4.0.4: + resolution: + { + integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==, + } + engines: { node: 18 || 20 || >=22 } + + baseline-browser-mapping@2.11.25: + resolution: + { + integrity: sha512-gMmEShwwq7FJqMwvfRwvCl00v4kN+KOfJqXn+f4nrufak5gNHJOksd/60Dvjuz7sI8Y5WiSFBa8FEYr+zoyqCw==, + } + engines: { node: ">=6.0.0" } + hasBin: true + + brace-expansion@1.1.21: + resolution: + { + integrity: sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==, + } + + brace-expansion@5.0.12: + resolution: + { + integrity: sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==, + } + engines: { node: 20 || >=22 } + + braces@3.0.3: + resolution: + { + integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==, + } + engines: { node: ">=8" } + + browserslist@4.29.0: + resolution: + { + integrity: sha512-3GSvyjvDI4Dur1Meg2BekJquu5uF+9R9a1+5M1Mde192eZoXbeXjzgOsgqPS2V8D5wrrip0gR5Hf/GhWQ9ZzaA==, + } + engines: { node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7 } + hasBin: true + + bser@2.1.1: + resolution: + { + integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==, + } + + buffer-from@1.1.2: + resolution: + { + integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==, + } + + cacheable@2.5.0: + resolution: + { + integrity: sha512-60cyAOytib/OzBw1JNSoSV/boK1AtHryDIjvVBk7XbN4ugfkM3+Sry7fEjNgPMGgOjuaZPAp8ruZ0Cxafwyq9g==, + } + + callsites@3.1.0: + resolution: + { + integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==, + } + engines: { node: ">=6" } + + camelcase@5.3.1: + resolution: + { + integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==, + } + engines: { node: ">=6" } + + camelcase@6.3.0: + resolution: + { + integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==, + } + engines: { node: ">=10" } + + caniuse-lite@1.0.30001810: + resolution: + { + integrity: sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==, + } + + chalk@4.1.2: + resolution: + { + integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==, + } + engines: { node: ">=10" } + + char-regex@1.0.2: + resolution: + { + integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==, + } + engines: { node: ">=10" } + + ci-info@3.9.0: + resolution: + { + integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==, + } + engines: { node: ">=8" } + + cjs-module-lexer@1.4.3: + resolution: + { + integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==, + } + + cliui@8.0.1: + resolution: + { + integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==, + } + engines: { node: ">=12" } + + co@4.6.0: + resolution: + { + integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==, + } + engines: { iojs: ">= 1.0.0", node: ">= 0.12.0" } + + collect-v8-coverage@1.0.3: + resolution: + { + integrity: sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==, + } + + color-convert@2.0.1: + resolution: + { + integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==, + } + engines: { node: ">=7.0.0" } + + color-name@1.1.4: + resolution: + { + integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==, + } + + concat-map@0.0.1: + resolution: + { + integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==, + } + + convert-source-map@2.0.0: + resolution: + { + integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==, + } + + create-jest@29.7.0: + resolution: + { + integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + hasBin: true + + cross-spawn@7.0.6: + resolution: + { + integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==, + } + engines: { node: ">= 8" } + + csstype@3.2.3: + resolution: + { + integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==, + } + + debug@4.4.3: + resolution: + { + integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==, + } + engines: { node: ">=6.0" } + peerDependencies: + supports-color: "*" + peerDependenciesMeta: + supports-color: + optional: true + + dedent@1.7.2: + resolution: + { + integrity: sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==, + } + peerDependencies: + babel-plugin-macros: ^3.1.0 + peerDependenciesMeta: + babel-plugin-macros: + optional: true + + deep-is@0.1.4: + resolution: + { + integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==, + } + + deepmerge@4.3.1: + resolution: + { + integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==, + } + engines: { node: ">=0.10.0" } + + detect-newline@3.1.0: + resolution: + { + integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==, + } + engines: { node: ">=8" } + + diff-sequences@29.6.3: + resolution: + { + integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + electron-to-chromium@1.5.433: + resolution: + { + integrity: sha512-5lCAbyZBjtmUt/RAGHRqrL2q0oEFRThDAsZHHDn9XHa89Qw7gMYOeSicBTy+AHfvo0r6vwsZvqNJTQIQy1BLzA==, + } + + emittery@0.13.1: + resolution: + { + integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==, + } + engines: { node: ">=12" } + + emoji-regex@8.0.0: + resolution: + { + integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==, + } + + error-ex@1.3.4: + resolution: + { + integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==, + } + + es-errors@1.3.0: + resolution: + { + integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==, + } + engines: { node: ">= 0.4" } + + esbuild@0.25.12: + resolution: + { + integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==, + } + engines: { node: ">=18" } + hasBin: true + + escalade@3.2.0: + resolution: + { + integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==, + } + engines: { node: ">=6" } + + escape-string-regexp@2.0.0: + resolution: + { + integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==, + } + engines: { node: ">=8" } + + escape-string-regexp@4.0.0: + resolution: + { + integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==, + } + engines: { node: ">=10" } + + eslint-scope@9.1.2: + resolution: + { + integrity: sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==, + } + engines: { node: ^20.19.0 || ^22.13.0 || >=24 } + + 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-visitor-keys@5.0.1: + resolution: + { + integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==, + } + engines: { node: ^20.19.0 || ^22.13.0 || >=24 } + + eslint@10.11.0: + resolution: + { + integrity: sha512-P7a6UEEqb9G95MYAtqkmsTbVXIYyzIfl6NGOIJk162PaahFxFyeGcrlXYFSiagECg4sEm8IseJdZBKR3rx6MsQ==, + } + engines: { node: ^20.19.0 || ^22.13.0 || >=24 } + hasBin: true + peerDependencies: + jiti: "*" + peerDependenciesMeta: + jiti: + optional: true + + espree@11.2.0: + resolution: + { + integrity: sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==, + } + engines: { node: ^20.19.0 || ^22.13.0 || >=24 } + + esprima@4.0.1: + resolution: + { + integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==, + } + engines: { node: ">=4" } + hasBin: true + + esquery@1.7.0: + resolution: + { + integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==, + } + engines: { node: ">=0.10" } + + esrecurse@4.3.0: + resolution: + { + integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==, + } + engines: { node: ">=4.0" } + + estraverse@5.3.0: + resolution: + { + integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==, + } + engines: { node: ">=4.0" } + + esutils@2.0.3: + resolution: + { + integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==, + } + engines: { node: ">=0.10.0" } + + execa@5.1.1: + resolution: + { + integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==, + } + engines: { node: ">=10" } + + exit@0.1.2: + resolution: + { + integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==, + } + engines: { node: ">= 0.8.0" } + + expect@29.7.0: + resolution: + { + integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + fast-deep-equal@3.1.3: + resolution: + { + integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==, + } + + fast-json-stable-stringify@2.1.0: + resolution: + { + integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==, + } + + fast-levenshtein@2.0.6: + resolution: + { + integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==, + } + + fb-watchman@2.0.2: + resolution: + { + integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==, + } + + fdir@6.5.0: + resolution: + { + integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==, + } + engines: { node: ">=12.0.0" } + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + file-entry-cache@11.1.5: + resolution: + { + integrity: sha512-+PFTHITI08JIGhnNpGNI8T8inUpgZfk3GNEqfT9R2zZV2iFXg3CvqzSl/uEhs7TSGujYRELEANyDvS8Fj7+S7Q==, + } + + 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@6.1.23: + resolution: + { + integrity: sha512-f++BY9pTk+983xK1FLzlLpmM0i0z+jHmx3QESGkURMXujQZz1k5wzwX6hjnQ8goaD0B+sYnDK1yZ6MTyZfUaqA==, + } + + flatted@3.4.4: + resolution: + { + integrity: sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==, + } + + 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 } + os: [darwin] + + function-bind@1.1.2: + resolution: + { + integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==, + } + + gensync@1.0.0-beta.2: + resolution: + { + integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==, + } + engines: { node: ">=6.9.0" } + + get-caller-file@2.0.5: + resolution: + { + integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==, + } + engines: { node: 6.* || 8.* || >= 10.* } + + get-package-type@0.1.0: + resolution: + { + integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==, + } + engines: { node: ">=8.0.0" } + + get-stream@6.0.1: + resolution: + { + integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==, + } + engines: { node: ">=10" } + + glob-parent@6.0.2: + resolution: + { + integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==, + } + engines: { node: ">=10.13.0" } + + glob@7.2.3: + resolution: + { + integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==, + } + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + + graceful-fs@4.2.11: + resolution: + { + integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==, + } + + has-flag@4.0.0: + resolution: + { + integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==, + } + engines: { node: ">=8" } + + hashery@1.5.1: + resolution: + { + integrity: sha512-iZyKG96/JwPz1N55vj2Ie2vXbhu440zfUfJvSwEqEbeLluk7NnapfGqa7LH0mOsnDxTF85Mx8/dyR6HfqcbmbQ==, + } + engines: { node: ">=20" } + + hasown@2.0.4: + resolution: + { + integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==, + } + engines: { node: ">= 0.4" } + + hookified@1.15.1: + resolution: + { + integrity: sha512-MvG/clsADq1GPM2KGo2nyfaWVyn9naPiXrqIe4jYjXNZQt238kWyOGrsyc/DmRAQ+Re6yeo6yX/yoNCG5KAEVg==, + } + + hookified@2.2.0: + resolution: + { + integrity: sha512-p/LgFzRN5FeoD3DLS6bkUapeye6E4SI6yJs6KetENd18S+FBthqYq2amJUWpt5z0EQwwHemidjY5OqJGEKm5uA==, + } + + html-escaper@2.0.2: + resolution: + { + integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==, + } + + human-signals@2.1.0: + resolution: + { + integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==, + } + engines: { node: ">=10.17.0" } + + ignore@5.3.2: + resolution: + { + integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==, + } + engines: { node: ">= 4" } + + ignore@7.0.9: + resolution: + { + integrity: sha512-brTTsvFRt5C1gGHtPst/281UjPD5t9fBqbgoMPlVWy11ZLTPfu7HxK4ZYqO9H7o/yC9rSTCI85EaQ4OoY12qYw==, + } + engines: { node: ">= 4" } + + import-local@3.2.0: + resolution: + { + integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==, + } + engines: { node: ">=8" } + hasBin: true + + imurmurhash@0.1.4: + resolution: + { + integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==, + } + engines: { node: ">=0.8.19" } + + 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==, + } + + is-arrayish@0.2.1: + resolution: + { + integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==, + } + + is-core-module@2.17.0: + resolution: + { + integrity: sha512-J/vG0zBCbIKOQFfufSwyXdMrsohyJIUNkrnmo6WZGzoM7tr/lsbfW5b2BvisL6zsyMzK9UxV9L6c7AoFbyXHOA==, + } + engines: { node: ">= 0.4" } + + is-extglob@2.1.1: + resolution: + { + integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==, + } + engines: { node: ">=0.10.0" } + + is-fullwidth-code-point@3.0.0: + resolution: + { + integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==, + } + engines: { node: ">=8" } + + is-generator-fn@2.1.0: + resolution: + { + integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==, + } + engines: { node: ">=6" } + + is-glob@4.0.3: + resolution: + { + integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==, + } + engines: { node: ">=0.10.0" } + + is-number@7.0.0: + resolution: + { + integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==, + } + engines: { node: ">=0.12.0" } + + is-stream@2.0.1: + resolution: + { + integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==, + } + engines: { node: ">=8" } + + isexe@2.0.0: + resolution: + { + integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==, + } + + istanbul-lib-coverage@3.2.2: + resolution: + { + integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==, + } + engines: { node: ">=8" } + + istanbul-lib-instrument@5.2.1: + resolution: + { + integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==, + } + engines: { node: ">=8" } + + istanbul-lib-instrument@6.0.3: + resolution: + { + integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==, + } + engines: { node: ">=10" } + + istanbul-lib-report@3.0.1: + resolution: + { + integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==, + } + engines: { node: ">=10" } + + istanbul-lib-source-maps@4.0.1: + resolution: + { + integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==, + } + engines: { node: ">=10" } + + istanbul-reports@3.2.0: + resolution: + { + integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==, + } + engines: { node: ">=8" } + + jest-changed-files@29.7.0: + resolution: + { + integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-circus@29.7.0: + resolution: + { + integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-cli@29.7.0: + resolution: + { + integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + jest-config@29.7.0: + resolution: + { + integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + peerDependencies: + "@types/node": "*" + ts-node: ">=9.0.0" + peerDependenciesMeta: + "@types/node": + optional: true + ts-node: + optional: true + + jest-diff@29.7.0: + resolution: + { + integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-docblock@29.7.0: + resolution: + { + integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-each@29.7.0: + resolution: + { + integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-environment-node@29.7.0: + resolution: + { + integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-get-type@29.6.3: + resolution: + { + integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-haste-map@29.7.0: + resolution: + { + integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-leak-detector@29.7.0: + resolution: + { + integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-matcher-utils@29.7.0: + resolution: + { + integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-message-util@29.7.0: + resolution: + { + integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-mock@29.7.0: + resolution: + { + integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-pnp-resolver@1.2.3: + resolution: + { + integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==, + } + engines: { node: ">=6" } + peerDependencies: + jest-resolve: "*" + peerDependenciesMeta: + jest-resolve: + optional: true + + jest-regex-util@29.6.3: + resolution: + { + integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-resolve-dependencies@29.7.0: + resolution: + { + integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-resolve@29.7.0: + resolution: + { + integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-runner@29.7.0: + resolution: + { + integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-runtime@29.7.0: + resolution: + { + integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-snapshot@29.7.0: + resolution: + { + integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-util@29.7.0: + resolution: + { + integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-validate@29.7.0: + resolution: + { + integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-watcher@29.7.0: + resolution: + { + integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-worker@29.7.0: + resolution: + { + integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest@29.7.0: + resolution: + { + integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + js-tokens@4.0.0: + resolution: + { + integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==, + } + + js-yaml@3.15.2: + resolution: + { + integrity: sha512-6EuL879VkRA+1Cz578mKMiKvjPNEuk6+r1JaFzoSWejZmtf7xWbIyw1e3KkxlkzTIt9Taw6JBhEppG7utc1P+w==, + } + hasBin: true + + jsesc@3.1.0: + resolution: + { + integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==, + } + engines: { node: ">=6" } + hasBin: true + + json-parse-even-better-errors@2.3.1: + resolution: + { + integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==, + } + + json-schema-traverse@0.4.1: + resolution: + { + integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==, + } + + json-stable-stringify-without-jsonify@1.0.1: + resolution: + { + integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==, + } + + json5@2.2.3: + resolution: + { + integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==, + } + engines: { node: ">=6" } + hasBin: true + + keyv@5.6.0: + resolution: + { + integrity: sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==, + } + + kleur@3.0.3: + resolution: + { + integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==, + } + engines: { node: ">=6" } + + leven@3.1.0: + resolution: + { + integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==, + } + engines: { node: ">=6" } + + levn@0.4.1: + resolution: + { + integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==, + } + engines: { node: ">= 0.8.0" } + + lines-and-columns@1.2.4: + resolution: + { + integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==, + } + + 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" } + + lru-cache@5.1.1: + resolution: + { + integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==, + } + + make-dir@4.0.0: + resolution: + { + integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==, + } + engines: { node: ">=10" } + + makeerror@1.0.12: + resolution: + { + integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==, + } + + merge-stream@2.0.0: + resolution: + { + integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==, + } + + micromatch@4.0.8: + resolution: + { + integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==, + } + engines: { node: ">=8.6" } + + mimic-fn@2.1.0: + resolution: + { + integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==, + } + engines: { node: ">=6" } + + minimatch@10.2.6: + resolution: + { + integrity: sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==, + } + engines: { node: 18 || 20 || >=22 } + + minimatch@3.1.5: + resolution: + { + integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==, + } + + ms@2.1.3: + resolution: + { + integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==, + } + + nanoid@3.3.19: + resolution: + { + integrity: sha512-Y2tUNy4ouw6tq5oDSKeQYGOyhkUBhNOcGV/02KC+6kd9eDGqdZd++mjMiIDilrBYvjEnCYvVtsuHCuP+okSfug==, + } + engines: { node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1 } + hasBin: true + + natural-compare@1.4.0: + resolution: + { + integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==, + } + + node-int64@0.4.0: + resolution: + { + integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==, + } + + node-releases@2.0.56: + resolution: + { + integrity: sha512-x0InOIyzgdk+eyaWaRJFH5snEtiImgBgblZ2CyPrLmqqcuMQkEvcDPHbzqbD8eDsSeJbVOjn+crzyzHaM4D+/A==, + } + engines: { node: ">=18" } + + normalize-path@3.0.0: + resolution: + { + integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==, + } + engines: { node: ">=0.10.0" } + + npm-run-path@4.0.1: + resolution: + { + integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==, + } + engines: { node: ">=8" } + + once@1.4.0: + resolution: + { + integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==, + } + + onetime@5.1.2: + resolution: + { + integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==, + } + engines: { node: ">=6" } + + 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-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" } + + 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-parse@1.0.7: + resolution: + { + integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==, + } + + picocolors@1.1.1: + resolution: + { + integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==, + } + + picomatch@2.3.2: + resolution: + { + integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==, + } + engines: { node: ">=8.6" } + + picomatch@4.0.7: + resolution: + { + integrity: sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==, + } + engines: { node: ">=12" } + + pirates@4.0.7: + resolution: + { + integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==, + } + engines: { node: ">= 6" } + + pkg-dir@4.2.0: + resolution: + { + integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==, + } + engines: { node: ">=8" } + + playwright-core@1.63.0: + resolution: + { + integrity: sha512-rYCsBF/M5HjUch52bbtVONEFjv6Xu8sm8h72dNlR5bzIE1fvC/bxgspzkjSfU+MweEMmPM8KJebG6nnyxo5mCg==, + } + engines: { node: ">=20" } + hasBin: true + + playwright@1.63.0: + resolution: + { + integrity: sha512-+7ziBLidS4NaNCdt57SUDT+wYmmd5fmiQejUic/kb+YsYSCPyOOE9sebzMjNmQrsnNpDJqd4WHvV/8lfKfUDUg==, + } + engines: { node: ">=20" } + hasBin: true + + postcss@8.5.28: + resolution: + { + integrity: sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A==, + } + engines: { node: ^10 || ^12 || >=14 } + + prelude-ls@1.2.1: + resolution: + { + integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==, + } + engines: { node: ">= 0.8.0" } + + prettier@3.9.8: + resolution: + { + integrity: sha512-WRFq3Wn3WId7LLROfMLdH7xaFr2jR62wU8nLO6rQUOLOxNZUviyJQs1M0iIhLexSFy+L+w0ch66wtoO2jRjG0A==, + } + 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 } + + prompts@2.4.2: + resolution: + { + integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==, + } + engines: { node: ">= 6" } + + punycode@2.3.1: + resolution: + { + integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==, + } + engines: { node: ">=6" } + + pure-rand@6.1.0: + resolution: + { + integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==, + } + + qified@0.10.1: + resolution: + { + integrity: sha512-+Owyggi9IxT1ePKGafcI87ubSmxol6smwJ+RAHDQlx9+9cPwFWDiKFFCPuWhr9ignlGpZ9vDQLw67N4dcTVFEA==, + } + engines: { node: ">=20" } + + react-dom@19.3.0: + resolution: + { + integrity: sha512-JDk8dgif51OjFoDE70+OT9ICyYr+69HlmihNwp1+Nsfbna3t5sIiCa9ZJktDmQ4/1b/rn26hIAR2uYXDMr5r0Q==, + } + peerDependencies: + react: ^19.3.0 + + react-is@18.3.1: + resolution: + { + integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==, + } + + react@19.3.0: + resolution: + { + integrity: sha512-E8LUcbtBWt20bbl2YoHfx4ZDBdxVTfOKtCZn9cDSJ4l6/nuoApcpIBcj47t2wZoVX8g2ZHuMHbiShgCR1T5Sog==, + } + engines: { node: ">=0.10.0" } + + require-directory@2.1.1: + resolution: + { + integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==, + } + engines: { node: ">=0.10.0" } + + resolve-cwd@3.0.0: + resolution: + { + integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==, + } + engines: { node: ">=8" } + + resolve-from@5.0.0: + resolution: + { + integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==, + } + engines: { node: ">=8" } + + resolve.exports@2.0.3: + resolution: + { + integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==, + } + engines: { node: ">=10" } + + resolve@1.22.12: + resolution: + { + integrity: sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==, + } + engines: { node: ">= 0.4" } + hasBin: true + + rollup@4.63.4: + resolution: + { + integrity: sha512-4U0liVayNIoLp3GFl1FcI8561WepLnZ1rqfraGh7S9B3Ur5F9S283y8Futii7RUU2C/97tOBmBy7nYvhoiOpbQ==, + } + engines: { node: ">=18.0.0", npm: ">=8.0.0" } + hasBin: true + + scheduler@0.28.0: + resolution: + { + integrity: sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw==, + } + + semver@6.3.1: + resolution: + { + integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==, + } + hasBin: true + + semver@7.8.5: + resolution: + { + integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==, + } + engines: { node: ">=10" } + hasBin: true + + shebang-command@2.0.0: + resolution: + { + integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==, + } + engines: { node: ">=8" } + + shebang-regex@3.0.0: + resolution: + { + integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==, + } + engines: { node: ">=8" } + + signal-exit@3.0.7: + resolution: + { + integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==, + } + + sisteransi@1.0.5: + resolution: + { + integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==, + } + + 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" } + + source-map-support@0.5.13: + resolution: + { + integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==, + } + + source-map@0.6.1: + resolution: + { + integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==, + } + engines: { node: ">=0.10.0" } + + sprintf-js@1.0.3: + resolution: + { + integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==, + } + + stack-utils@2.0.6: + resolution: + { + integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==, + } + engines: { node: ">=10" } + + string-length@4.0.2: + resolution: + { + integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==, + } + engines: { node: ">=10" } + + string-width@4.2.3: + resolution: + { + integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==, + } + engines: { node: ">=8" } + + strip-ansi@6.0.1: + resolution: + { + integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==, + } + engines: { node: ">=8" } + + strip-bom@4.0.0: + resolution: + { + integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==, + } + engines: { node: ">=8" } + + strip-final-newline@2.0.0: + resolution: + { + integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==, + } + engines: { node: ">=6" } + + strip-json-comments@3.1.1: + resolution: + { + integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==, + } + engines: { node: ">=8" } + + supports-color@7.2.0: + resolution: + { + integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==, + } + engines: { node: ">=8" } + + supports-color@8.1.1: + resolution: + { + integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==, + } + engines: { node: ">=10" } + + supports-preserve-symlinks-flag@1.0.0: + resolution: + { + integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==, + } + engines: { node: ">= 0.4" } + + test-exclude@6.0.0: + resolution: + { + integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==, + } + engines: { node: ">=8" } + + tinyglobby@0.2.17: + resolution: + { + integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==, + } + engines: { node: ">=12.0.0" } + + tmpl@1.0.5: + resolution: + { + integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==, + } + + to-regex-range@5.0.1: + resolution: + { + integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==, + } + engines: { node: ">=8.0" } + + ts-api-utils@2.5.0: + resolution: + { + integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==, + } + engines: { node: ">=18.12" } + peerDependencies: + typescript: ">=4.8.4" + + type-check@0.4.0: + resolution: + { + integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==, + } + engines: { node: ">= 0.8.0" } + + type-detect@4.0.8: + resolution: + { + integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==, + } + engines: { node: ">=4" } + + type-fest@0.21.3: + resolution: + { + integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==, + } + engines: { node: ">=10" } + + typescript-eslint@8.70.1: + resolution: + { + integrity: sha512-AcWG7KDjZ2THNXsgwttMaGmzVi0VFRlFYfqFHYQRbDpF3owuYbuiL8c7UUrd2k8s3PoSfIQrWfrGXfcElrWLYA==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: ">=4.8.4 <6.1.0" + + typescript@5.9.3: + resolution: + { + integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==, + } + engines: { node: ">=14.17" } + hasBin: true + + undici-types@8.9.0: + resolution: + { + integrity: sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==, + } + + update-browserslist-db@1.3.3: + resolution: + { + integrity: sha512-pJ2sYawQS0R/WI928Gj5GlPhTGzbMelq0+4INtSYNDV9ErKJcX6xjGWkoG/VnB3dpUm00zALaqkrUD77pO5TDQ==, + } + hasBin: true + peerDependencies: + browserslist: ">= 4.21.0" + + uri-js@4.4.1: + resolution: + { + integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==, + } + + v8-to-istanbul@9.3.0: + resolution: + { + integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==, + } + engines: { node: ">=10.12.0" } + + vite@6.4.3: + resolution: + { + integrity: sha512-NTKlcQjlAK7MlQoyb6LgaqHc8sso/pVyUJYWMws3jg21uTJw/LddqIFPcPqP6PzpgbIcZyKI85sFE4HBrQDA8A==, + } + engines: { node: ^18.0.0 || ^20.0.0 || >=22.0.0 } + hasBin: true + peerDependencies: + "@types/node": ^18.0.0 || ^20.0.0 || >=22.0.0 + jiti: ">=1.21.0" + less: "*" + lightningcss: ^1.21.0 + sass: "*" + sass-embedded: "*" + stylus: "*" + sugarss: "*" + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + "@types/node": + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + walker@1.0.8: + resolution: + { + integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==, + } + + which@2.0.2: + resolution: + { + integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==, + } + engines: { node: ">= 8" } + hasBin: true + + word-wrap@1.2.5: + resolution: + { + integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==, + } + engines: { node: ">=0.10.0" } + + wrap-ansi@7.0.0: + resolution: + { + integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==, + } + engines: { node: ">=10" } + + wrappy@1.0.2: + resolution: + { + integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==, + } + + write-file-atomic@4.0.2: + resolution: + { + integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==, + } + engines: { node: ^12.13.0 || ^14.15.0 || >=16.0.0 } + + y18n@5.0.8: + resolution: + { + integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==, + } + engines: { node: ">=10" } + + yallist@3.1.1: + resolution: + { + integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==, + } + + yargs-parser@21.1.1: + resolution: + { + integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==, + } + engines: { node: ">=12" } + + yargs@17.7.3: + resolution: + { + integrity: sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==, + } + engines: { node: ">=12" } + + yocto-queue@0.1.0: + resolution: + { + integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==, + } + engines: { node: ">=10" } + +snapshots: + "@babel/code-frame@7.29.7": + dependencies: + "@babel/helper-validator-identifier": 7.29.7 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + "@babel/compat-data@7.29.7": {} + + "@babel/core@7.29.7": + dependencies: + "@babel/code-frame": 7.29.7 + "@babel/generator": 7.29.8 + "@babel/helper-compilation-targets": 7.29.7 + "@babel/helper-module-transforms": 7.29.7(@babel/core@7.29.7) + "@babel/helpers": 7.29.7 + "@babel/parser": 7.29.9 + "@babel/template": 7.29.7 + "@babel/traverse": 7.29.8 + "@babel/types": 7.29.8 + "@jridgewell/remapping": 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + "@babel/generator@7.29.8": + dependencies: + "@babel/parser": 7.29.9 + "@babel/types": 7.29.8 + "@jridgewell/gen-mapping": 0.3.13 + "@jridgewell/trace-mapping": 0.3.31 + jsesc: 3.1.0 + + "@babel/helper-compilation-targets@7.29.7": + dependencies: + "@babel/compat-data": 7.29.7 + "@babel/helper-validator-option": 7.29.7 + browserslist: 4.29.0 + lru-cache: 5.1.1 + semver: 6.3.1 + + "@babel/helper-globals@7.29.7": {} + + "@babel/helper-module-imports@7.29.7": + dependencies: + "@babel/traverse": 7.29.8 + "@babel/types": 7.29.8 + transitivePeerDependencies: + - supports-color + + "@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)": + dependencies: + "@babel/core": 7.29.7 + "@babel/helper-module-imports": 7.29.7 + "@babel/helper-validator-identifier": 7.29.7 + "@babel/traverse": 7.29.8 + transitivePeerDependencies: + - supports-color + + "@babel/helper-plugin-utils@7.29.7": {} + + "@babel/helper-string-parser@7.29.7": {} + + "@babel/helper-validator-identifier@7.29.7": {} + + "@babel/helper-validator-option@7.29.7": {} + + "@babel/helpers@7.29.7": + dependencies: + "@babel/template": 7.29.7 + "@babel/types": 7.29.8 + + "@babel/parser@7.29.9": + dependencies: + "@babel/types": 7.29.8 + + "@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.29.7)": + dependencies: + "@babel/core": 7.29.7 + "@babel/helper-plugin-utils": 7.29.7 + + "@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.29.7)": + dependencies: + "@babel/core": 7.29.7 + "@babel/helper-plugin-utils": 7.29.7 + + "@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.29.7)": + dependencies: + "@babel/core": 7.29.7 + "@babel/helper-plugin-utils": 7.29.7 + + "@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.29.7)": + dependencies: + "@babel/core": 7.29.7 + "@babel/helper-plugin-utils": 7.29.7 + + "@babel/plugin-syntax-import-attributes@7.29.7(@babel/core@7.29.7)": + dependencies: + "@babel/core": 7.29.7 + "@babel/helper-plugin-utils": 7.29.7 + + "@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.29.7)": + dependencies: + "@babel/core": 7.29.7 + "@babel/helper-plugin-utils": 7.29.7 + + "@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.29.7)": + dependencies: + "@babel/core": 7.29.7 + "@babel/helper-plugin-utils": 7.29.7 + + "@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7)": + dependencies: + "@babel/core": 7.29.7 + "@babel/helper-plugin-utils": 7.29.7 + + "@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.29.7)": + dependencies: + "@babel/core": 7.29.7 + "@babel/helper-plugin-utils": 7.29.7 + + "@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.29.7)": + dependencies: + "@babel/core": 7.29.7 + "@babel/helper-plugin-utils": 7.29.7 + + "@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.29.7)": + dependencies: + "@babel/core": 7.29.7 + "@babel/helper-plugin-utils": 7.29.7 + + "@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.29.7)": + dependencies: + "@babel/core": 7.29.7 + "@babel/helper-plugin-utils": 7.29.7 + + "@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.29.7)": + dependencies: + "@babel/core": 7.29.7 + "@babel/helper-plugin-utils": 7.29.7 + + "@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.29.7)": + dependencies: + "@babel/core": 7.29.7 + "@babel/helper-plugin-utils": 7.29.7 + + "@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.29.7)": + dependencies: + "@babel/core": 7.29.7 + "@babel/helper-plugin-utils": 7.29.7 + + "@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.29.7)": + dependencies: + "@babel/core": 7.29.7 + "@babel/helper-plugin-utils": 7.29.7 + + "@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.7)": + dependencies: + "@babel/core": 7.29.7 + "@babel/helper-plugin-utils": 7.29.7 + + "@babel/template@7.29.7": + dependencies: + "@babel/code-frame": 7.29.7 + "@babel/parser": 7.29.9 + "@babel/types": 7.29.8 + + "@babel/traverse@7.29.8": + dependencies: + "@babel/code-frame": 7.29.7 + "@babel/generator": 7.29.8 + "@babel/helper-globals": 7.29.7 + "@babel/parser": 7.29.9 + "@babel/template": 7.29.7 + "@babel/types": 7.29.8 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + "@babel/types@7.29.8": + dependencies: + "@babel/helper-string-parser": 7.29.7 + "@babel/helper-validator-identifier": 7.29.7 + + "@bcoe/v8-coverage@0.2.3": {} + + "@cacheable/memory@2.2.0": + dependencies: + "@cacheable/utils": 2.5.0 + "@keyv/bigmap": 1.3.1(keyv@5.6.0) + hookified: 1.15.1 + keyv: 5.6.0 + + "@cacheable/utils@2.5.0": + dependencies: + hashery: 1.5.1 + keyv: 5.6.0 + + "@esbuild/aix-ppc64@0.25.12": + optional: true + + "@esbuild/android-arm64@0.25.12": + optional: true + + "@esbuild/android-arm@0.25.12": + optional: true + + "@esbuild/android-x64@0.25.12": + optional: true + + "@esbuild/darwin-arm64@0.25.12": + optional: true + + "@esbuild/darwin-x64@0.25.12": + optional: true + + "@esbuild/freebsd-arm64@0.25.12": + optional: true + + "@esbuild/freebsd-x64@0.25.12": + optional: true + + "@esbuild/linux-arm64@0.25.12": + optional: true + + "@esbuild/linux-arm@0.25.12": + optional: true + + "@esbuild/linux-ia32@0.25.12": + optional: true + + "@esbuild/linux-loong64@0.25.12": + optional: true + + "@esbuild/linux-mips64el@0.25.12": + optional: true + + "@esbuild/linux-ppc64@0.25.12": + optional: true + + "@esbuild/linux-riscv64@0.25.12": + optional: true + + "@esbuild/linux-s390x@0.25.12": + optional: true + + "@esbuild/linux-x64@0.25.12": + optional: true + + "@esbuild/netbsd-arm64@0.25.12": + optional: true + + "@esbuild/netbsd-x64@0.25.12": + optional: true + + "@esbuild/openbsd-arm64@0.25.12": + optional: true + + "@esbuild/openbsd-x64@0.25.12": + optional: true + + "@esbuild/openharmony-arm64@0.25.12": + optional: true + + "@esbuild/sunos-x64@0.25.12": + optional: true + + "@esbuild/win32-arm64@0.25.12": + optional: true + + "@esbuild/win32-ia32@0.25.12": + optional: true + + "@esbuild/win32-x64@0.25.12": + optional: true + + "@eslint-community/eslint-utils@4.10.1(eslint@10.11.0)": + dependencies: + eslint: 10.11.0 + eslint-visitor-keys: 3.4.3 + + "@eslint-community/regexpp@4.12.2": {} + + "@eslint/config-array@0.23.5": + dependencies: + "@eslint/object-schema": 3.0.5 + debug: 4.4.3 + minimatch: 10.2.6 + transitivePeerDependencies: + - supports-color + + "@eslint/config-helpers@0.7.0": + dependencies: + "@eslint/core": 1.2.1 + + "@eslint/core@1.2.1": + dependencies: + "@types/json-schema": 7.0.15 + + "@eslint/js@10.0.1(eslint@10.11.0)": + optionalDependencies: + eslint: 10.11.0 + + "@eslint/object-schema@3.0.5": {} + + "@eslint/plugin-kit@0.7.3": + dependencies: + "@eslint/core": 1.2.1 + levn: 0.4.1 + + "@humanfs/core@0.19.2": + dependencies: + "@humanfs/types": 0.15.0 + + "@humanfs/node@0.16.8": + dependencies: + "@humanfs/core": 0.19.2 + "@humanfs/types": 0.15.0 + "@humanwhocodes/retry": 0.4.3 + + "@humanfs/types@0.15.0": {} + + "@humanwhocodes/module-importer@1.0.1": {} + + "@humanwhocodes/retry@0.4.3": {} + + "@istanbuljs/load-nyc-config@1.1.0": + dependencies: + camelcase: 5.3.1 + find-up: 4.1.0 + get-package-type: 0.1.0 + js-yaml: 3.15.2 + resolve-from: 5.0.0 + + "@istanbuljs/schema@0.1.6": {} + + "@jest/console@29.7.0": + dependencies: + "@jest/types": 29.6.3 + "@types/node": 26.6.2 + chalk: 4.1.2 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + slash: 3.0.0 + + "@jest/core@29.7.0": + dependencies: + "@jest/console": 29.7.0 + "@jest/reporters": 29.7.0 + "@jest/test-result": 29.7.0 + "@jest/transform": 29.7.0 + "@jest/types": 29.6.3 + "@types/node": 26.6.2 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + ci-info: 3.9.0 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-changed-files: 29.7.0 + jest-config: 29.7.0(@types/node@26.6.2) + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-resolve-dependencies: 29.7.0 + jest-runner: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + jest-watcher: 29.7.0 + micromatch: 4.0.8 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + - ts-node + + "@jest/environment@29.7.0": + dependencies: + "@jest/fake-timers": 29.7.0 + "@jest/types": 29.6.3 + "@types/node": 26.6.2 + jest-mock: 29.7.0 + + "@jest/expect-utils@29.7.0": + dependencies: + jest-get-type: 29.6.3 + + "@jest/expect@29.7.0": + dependencies: + expect: 29.7.0 + jest-snapshot: 29.7.0 + transitivePeerDependencies: + - supports-color + + "@jest/fake-timers@29.7.0": + dependencies: + "@jest/types": 29.6.3 + "@sinonjs/fake-timers": 10.3.0 + "@types/node": 26.6.2 + jest-message-util: 29.7.0 + jest-mock: 29.7.0 + jest-util: 29.7.0 + + "@jest/globals@29.7.0": + dependencies: + "@jest/environment": 29.7.0 + "@jest/expect": 29.7.0 + "@jest/types": 29.6.3 + jest-mock: 29.7.0 + transitivePeerDependencies: + - supports-color + + "@jest/reporters@29.7.0": + dependencies: + "@bcoe/v8-coverage": 0.2.3 + "@jest/console": 29.7.0 + "@jest/test-result": 29.7.0 + "@jest/transform": 29.7.0 + "@jest/types": 29.6.3 + "@jridgewell/trace-mapping": 0.3.31 + "@types/node": 26.6.2 + chalk: 4.1.2 + collect-v8-coverage: 1.0.3 + exit: 0.1.2 + glob: 7.2.3 + graceful-fs: 4.2.11 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-instrument: 6.0.3 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 4.0.1 + istanbul-reports: 3.2.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + jest-worker: 29.7.0 + slash: 3.0.0 + string-length: 4.0.2 + strip-ansi: 6.0.1 + v8-to-istanbul: 9.3.0 + transitivePeerDependencies: + - supports-color + + "@jest/schemas@29.6.3": + dependencies: + "@sinclair/typebox": 0.27.12 + + "@jest/source-map@29.6.3": + dependencies: + "@jridgewell/trace-mapping": 0.3.31 + callsites: 3.1.0 + graceful-fs: 4.2.11 + + "@jest/test-result@29.7.0": + dependencies: + "@jest/console": 29.7.0 + "@jest/types": 29.6.3 + "@types/istanbul-lib-coverage": 2.0.6 + collect-v8-coverage: 1.0.3 + + "@jest/test-sequencer@29.7.0": + dependencies: + "@jest/test-result": 29.7.0 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + slash: 3.0.0 + + "@jest/transform@29.7.0": + dependencies: + "@babel/core": 7.29.7 + "@jest/types": 29.6.3 + "@jridgewell/trace-mapping": 0.3.31 + babel-plugin-istanbul: 6.1.1 + chalk: 4.1.2 + convert-source-map: 2.0.0 + fast-json-stable-stringify: 2.1.0 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-regex-util: 29.6.3 + jest-util: 29.7.0 + micromatch: 4.0.8 + pirates: 4.0.7 + slash: 3.0.0 + write-file-atomic: 4.0.2 + transitivePeerDependencies: + - supports-color + + "@jest/types@29.6.3": + dependencies: + "@jest/schemas": 29.6.3 + "@types/istanbul-lib-coverage": 2.0.6 + "@types/istanbul-reports": 3.0.4 + "@types/node": 26.6.2 + "@types/yargs": 17.0.35 + chalk: 4.1.2 + + "@jridgewell/gen-mapping@0.3.13": + dependencies: + "@jridgewell/sourcemap-codec": 1.6.0 + "@jridgewell/trace-mapping": 0.3.31 + + "@jridgewell/remapping@2.3.5": + dependencies: + "@jridgewell/gen-mapping": 0.3.13 + "@jridgewell/trace-mapping": 0.3.31 + + "@jridgewell/resolve-uri@3.1.2": {} + + "@jridgewell/sourcemap-codec@1.6.0": {} + + "@jridgewell/trace-mapping@0.3.31": + dependencies: + "@jridgewell/resolve-uri": 3.1.2 + "@jridgewell/sourcemap-codec": 1.6.0 + + "@keyv/bigmap@1.3.1(keyv@5.6.0)": + dependencies: + hashery: 1.5.1 + hookified: 1.15.1 + keyv: 5.6.0 + + "@keyv/serialize@1.1.1": {} + + "@napi-rs/lzma-linux-x64-gnu@1.5.1": + optional: true + + "@playwright/test@1.63.0": + dependencies: + playwright: 1.63.0 + + "@rollup/rollup-android-arm-eabi@4.63.4": + optional: true + + "@rollup/rollup-android-arm64@4.63.4": + optional: true + + "@rollup/rollup-darwin-arm64@4.63.4": + optional: true + + "@rollup/rollup-darwin-x64@4.63.4": + optional: true + + "@rollup/rollup-freebsd-arm64@4.63.4": + optional: true + + "@rollup/rollup-freebsd-x64@4.63.4": + optional: true + + "@rollup/rollup-linux-arm-gnueabihf@4.63.4": + optional: true + + "@rollup/rollup-linux-arm-musleabihf@4.63.4": + optional: true + + "@rollup/rollup-linux-arm64-gnu@4.63.4": + optional: true + + "@rollup/rollup-linux-arm64-musl@4.63.4": + optional: true + + "@rollup/rollup-linux-loong64-gnu@4.63.4": + optional: true + + "@rollup/rollup-linux-loong64-musl@4.63.4": + optional: true + + "@rollup/rollup-linux-ppc64-gnu@4.63.4": + optional: true + + "@rollup/rollup-linux-ppc64-musl@4.63.4": + optional: true + + "@rollup/rollup-linux-riscv64-gnu@4.63.4": + optional: true + + "@rollup/rollup-linux-riscv64-musl@4.63.4": + optional: true + + "@rollup/rollup-linux-s390x-gnu@4.63.4": + optional: true + + "@rollup/rollup-linux-x64-gnu@4.63.4": + optional: true + + "@rollup/rollup-linux-x64-musl@4.63.4": + optional: true + + "@rollup/rollup-openbsd-x64@4.63.4": + optional: true + + "@rollup/rollup-openharmony-arm64@4.63.4": + optional: true + + "@rollup/rollup-win32-arm64-msvc@4.63.4": + optional: true + + "@rollup/rollup-win32-ia32-msvc@4.63.4": + optional: true + + "@rollup/rollup-win32-x64-gnu@4.63.4": + optional: true + + "@rollup/rollup-win32-x64-msvc@4.63.4": + optional: true + + "@sinclair/typebox@0.27.12": {} + + "@sinonjs/commons@3.0.1": + dependencies: + type-detect: 4.0.8 + + "@sinonjs/fake-timers@10.3.0": + dependencies: + "@sinonjs/commons": 3.0.1 + + "@types/babel__core@7.20.5": + dependencies: + "@babel/parser": 7.29.9 + "@babel/types": 7.29.8 + "@types/babel__generator": 7.27.0 + "@types/babel__template": 7.4.4 + "@types/babel__traverse": 7.28.0 + + "@types/babel__generator@7.27.0": + dependencies: + "@babel/types": 7.29.8 + + "@types/babel__template@7.4.4": + dependencies: + "@babel/parser": 7.29.9 + "@babel/types": 7.29.8 + + "@types/babel__traverse@7.28.0": + dependencies: + "@babel/types": 7.29.8 + + "@types/esrecurse@4.3.1": {} + + "@types/estree@1.0.9": {} + + "@types/graceful-fs@4.1.9": + dependencies: + "@types/node": 26.6.2 + + "@types/istanbul-lib-coverage@2.0.6": {} + + "@types/istanbul-lib-report@3.0.3": + dependencies: + "@types/istanbul-lib-coverage": 2.0.6 + + "@types/istanbul-reports@3.0.4": + dependencies: + "@types/istanbul-lib-report": 3.0.3 + + "@types/jest@29.5.14": + dependencies: + expect: 29.7.0 + pretty-format: 29.7.0 + + "@types/json-schema@7.0.15": {} + + "@types/node@26.6.2": + dependencies: + undici-types: 8.9.0 + + "@types/react-dom@19.3.0(@types/react@19.3.0)": + dependencies: + "@types/react": 19.3.0 + + "@types/react@19.3.0": + dependencies: + csstype: 3.2.3 + + "@types/stack-utils@2.0.3": {} + + "@types/yargs-parser@21.0.3": {} + + "@types/yargs@17.0.35": + dependencies: + "@types/yargs-parser": 21.0.3 + + "@typescript-eslint/eslint-plugin@8.70.1(@typescript-eslint/parser@8.70.1(eslint@10.11.0)(typescript@5.9.3))(eslint@10.11.0)(typescript@5.9.3)": + dependencies: + "@eslint-community/regexpp": 4.12.2 + "@typescript-eslint/parser": 8.70.1(eslint@10.11.0)(typescript@5.9.3) + "@typescript-eslint/scope-manager": 8.70.1 + "@typescript-eslint/type-utils": 8.70.1(eslint@10.11.0)(typescript@5.9.3) + "@typescript-eslint/utils": 8.70.1(eslint@10.11.0)(typescript@5.9.3) + "@typescript-eslint/visitor-keys": 8.70.1 + eslint: 10.11.0 + ignore: 7.0.9 + natural-compare: 1.4.0 + ts-api-utils: 2.5.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + "@typescript-eslint/parser@8.70.1(eslint@10.11.0)(typescript@5.9.3)": + dependencies: + "@typescript-eslint/scope-manager": 8.70.1 + "@typescript-eslint/types": 8.70.1 + "@typescript-eslint/typescript-estree": 8.70.1(typescript@5.9.3) + "@typescript-eslint/visitor-keys": 8.70.1 + debug: 4.4.3 + eslint: 10.11.0 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + "@typescript-eslint/project-service@8.70.1(typescript@5.9.3)": + dependencies: + "@typescript-eslint/tsconfig-utils": 8.70.1(typescript@5.9.3) + "@typescript-eslint/types": 8.70.1 + debug: 4.4.3 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + "@typescript-eslint/scope-manager@8.70.1": + dependencies: + "@typescript-eslint/types": 8.70.1 + "@typescript-eslint/visitor-keys": 8.70.1 + + "@typescript-eslint/tsconfig-utils@8.70.1(typescript@5.9.3)": + dependencies: + typescript: 5.9.3 + + "@typescript-eslint/type-utils@8.70.1(eslint@10.11.0)(typescript@5.9.3)": + dependencies: + "@typescript-eslint/types": 8.70.1 + "@typescript-eslint/typescript-estree": 8.70.1(typescript@5.9.3) + "@typescript-eslint/utils": 8.70.1(eslint@10.11.0)(typescript@5.9.3) + debug: 4.4.3 + eslint: 10.11.0 + ts-api-utils: 2.5.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + "@typescript-eslint/types@8.70.1": {} + + "@typescript-eslint/typescript-estree@8.70.1(typescript@5.9.3)": + dependencies: + "@typescript-eslint/project-service": 8.70.1(typescript@5.9.3) + "@typescript-eslint/tsconfig-utils": 8.70.1(typescript@5.9.3) + "@typescript-eslint/types": 8.70.1 + "@typescript-eslint/visitor-keys": 8.70.1 + debug: 4.4.3 + minimatch: 10.2.6 + semver: 7.8.5 + tinyglobby: 0.2.17 + ts-api-utils: 2.5.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + "@typescript-eslint/utils@8.70.1(eslint@10.11.0)(typescript@5.9.3)": + dependencies: + "@eslint-community/eslint-utils": 4.10.1(eslint@10.11.0) + "@typescript-eslint/scope-manager": 8.70.1 + "@typescript-eslint/types": 8.70.1 + "@typescript-eslint/typescript-estree": 8.70.1(typescript@5.9.3) + eslint: 10.11.0 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + "@typescript-eslint/visitor-keys@8.70.1": + dependencies: + "@typescript-eslint/types": 8.70.1 + eslint-visitor-keys: 5.0.1 + + acorn-jsx@5.3.2(acorn@8.18.0): + dependencies: + acorn: 8.18.0 + + acorn@8.18.0: {} + + ajv@6.15.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ansi-escapes@4.3.2: + dependencies: + type-fest: 0.21.3 + + ansi-regex@5.0.1: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@5.2.0: {} + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.2 + + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + + babel-jest@29.7.0(@babel/core@7.29.7): + dependencies: + "@babel/core": 7.29.7 + "@jest/transform": 29.7.0 + "@types/babel__core": 7.20.5 + babel-plugin-istanbul: 6.1.1 + babel-preset-jest: 29.6.3(@babel/core@7.29.7) + chalk: 4.1.2 + graceful-fs: 4.2.11 + slash: 3.0.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-istanbul@6.1.1: + dependencies: + "@babel/helper-plugin-utils": 7.29.7 + "@istanbuljs/load-nyc-config": 1.1.0 + "@istanbuljs/schema": 0.1.6 + istanbul-lib-instrument: 5.2.1 + test-exclude: 6.0.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-jest-hoist@29.6.3: + dependencies: + "@babel/template": 7.29.7 + "@babel/types": 7.29.8 + "@types/babel__core": 7.20.5 + "@types/babel__traverse": 7.28.0 + + babel-preset-current-node-syntax@1.2.0(@babel/core@7.29.7): + dependencies: + "@babel/core": 7.29.7 + "@babel/plugin-syntax-async-generators": 7.8.4(@babel/core@7.29.7) + "@babel/plugin-syntax-bigint": 7.8.3(@babel/core@7.29.7) + "@babel/plugin-syntax-class-properties": 7.12.13(@babel/core@7.29.7) + "@babel/plugin-syntax-class-static-block": 7.14.5(@babel/core@7.29.7) + "@babel/plugin-syntax-import-attributes": 7.29.7(@babel/core@7.29.7) + "@babel/plugin-syntax-import-meta": 7.10.4(@babel/core@7.29.7) + "@babel/plugin-syntax-json-strings": 7.8.3(@babel/core@7.29.7) + "@babel/plugin-syntax-logical-assignment-operators": 7.10.4(@babel/core@7.29.7) + "@babel/plugin-syntax-nullish-coalescing-operator": 7.8.3(@babel/core@7.29.7) + "@babel/plugin-syntax-numeric-separator": 7.10.4(@babel/core@7.29.7) + "@babel/plugin-syntax-object-rest-spread": 7.8.3(@babel/core@7.29.7) + "@babel/plugin-syntax-optional-catch-binding": 7.8.3(@babel/core@7.29.7) + "@babel/plugin-syntax-optional-chaining": 7.8.3(@babel/core@7.29.7) + "@babel/plugin-syntax-private-property-in-object": 7.14.5(@babel/core@7.29.7) + "@babel/plugin-syntax-top-level-await": 7.14.5(@babel/core@7.29.7) + + babel-preset-jest@29.6.3(@babel/core@7.29.7): + dependencies: + "@babel/core": 7.29.7 + babel-plugin-jest-hoist: 29.6.3 + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.7) + + balanced-match@1.0.2: {} + + balanced-match@4.0.4: {} + + baseline-browser-mapping@2.11.25: {} + + brace-expansion@1.1.21: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@5.0.12: + dependencies: + balanced-match: 4.0.4 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browserslist@4.29.0: + dependencies: + baseline-browser-mapping: 2.11.25 + caniuse-lite: 1.0.30001810 + electron-to-chromium: 1.5.433 + node-releases: 2.0.56 + update-browserslist-db: 1.3.3(browserslist@4.29.0) + + bser@2.1.1: + dependencies: + node-int64: 0.4.0 + + buffer-from@1.1.2: {} + + cacheable@2.5.0: + dependencies: + "@cacheable/memory": 2.2.0 + "@cacheable/utils": 2.5.0 + hookified: 1.15.1 + keyv: 5.6.0 + qified: 0.10.1 + + callsites@3.1.0: {} + + camelcase@5.3.1: {} + + camelcase@6.3.0: {} + + caniuse-lite@1.0.30001810: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + char-regex@1.0.2: {} + + ci-info@3.9.0: {} + + cjs-module-lexer@1.4.3: {} + + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + co@4.6.0: {} + + collect-v8-coverage@1.0.3: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + concat-map@0.0.1: {} + + convert-source-map@2.0.0: {} + + create-jest@29.7.0(@types/node@26.6.2): + dependencies: + "@jest/types": 29.6.3 + chalk: 4.1.2 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-config: 29.7.0(@types/node@26.6.2) + jest-util: 29.7.0 + prompts: 2.4.2 + transitivePeerDependencies: + - "@types/node" + - babel-plugin-macros + - supports-color + - ts-node + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + csstype@3.2.3: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + dedent@1.7.2: {} + + deep-is@0.1.4: {} + + deepmerge@4.3.1: {} + + detect-newline@3.1.0: {} + + diff-sequences@29.6.3: {} + + electron-to-chromium@1.5.433: {} + + emittery@0.13.1: {} + + emoji-regex@8.0.0: {} + + error-ex@1.3.4: + dependencies: + is-arrayish: 0.2.1 + + es-errors@1.3.0: {} + + esbuild@0.25.12: + optionalDependencies: + "@esbuild/aix-ppc64": 0.25.12 + "@esbuild/android-arm": 0.25.12 + "@esbuild/android-arm64": 0.25.12 + "@esbuild/android-x64": 0.25.12 + "@esbuild/darwin-arm64": 0.25.12 + "@esbuild/darwin-x64": 0.25.12 + "@esbuild/freebsd-arm64": 0.25.12 + "@esbuild/freebsd-x64": 0.25.12 + "@esbuild/linux-arm": 0.25.12 + "@esbuild/linux-arm64": 0.25.12 + "@esbuild/linux-ia32": 0.25.12 + "@esbuild/linux-loong64": 0.25.12 + "@esbuild/linux-mips64el": 0.25.12 + "@esbuild/linux-ppc64": 0.25.12 + "@esbuild/linux-riscv64": 0.25.12 + "@esbuild/linux-s390x": 0.25.12 + "@esbuild/linux-x64": 0.25.12 + "@esbuild/netbsd-arm64": 0.25.12 + "@esbuild/netbsd-x64": 0.25.12 + "@esbuild/openbsd-arm64": 0.25.12 + "@esbuild/openbsd-x64": 0.25.12 + "@esbuild/openharmony-arm64": 0.25.12 + "@esbuild/sunos-x64": 0.25.12 + "@esbuild/win32-arm64": 0.25.12 + "@esbuild/win32-ia32": 0.25.12 + "@esbuild/win32-x64": 0.25.12 + + escalade@3.2.0: {} + + escape-string-regexp@2.0.0: {} + + escape-string-regexp@4.0.0: {} + + eslint-scope@9.1.2: + dependencies: + "@types/esrecurse": 4.3.1 + "@types/estree": 1.0.9 + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@5.0.1: {} + + eslint@10.11.0: + dependencies: + "@eslint-community/eslint-utils": 4.10.1(eslint@10.11.0) + "@eslint-community/regexpp": 4.12.2 + "@eslint/config-array": 0.23.5 + "@eslint/config-helpers": 0.7.0 + "@eslint/core": 1.2.1 + "@eslint/plugin-kit": 0.7.3 + "@humanfs/node": 0.16.8 + "@humanwhocodes/module-importer": 1.0.1 + "@humanwhocodes/retry": 0.4.3 + "@types/estree": 1.0.9 + ajv: 6.15.0 + cross-spawn: 7.0.6 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint-scope: 9.1.2 + eslint-visitor-keys: 5.0.1 + espree: 11.2.0 + esquery: 1.7.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 11.1.5 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + minimatch: 10.2.6 + natural-compare: 1.4.0 + optionator: 0.9.4 + transitivePeerDependencies: + - supports-color + + espree@11.2.0: + dependencies: + acorn: 8.18.0 + acorn-jsx: 5.3.2(acorn@8.18.0) + eslint-visitor-keys: 5.0.1 + + esprima@4.0.1: {} + + esquery@1.7.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + esutils@2.0.3: {} + + execa@5.1.1: + dependencies: + cross-spawn: 7.0.6 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + + exit@0.1.2: {} + + expect@29.7.0: + dependencies: + "@jest/expect-utils": 29.7.0 + jest-get-type: 29.6.3 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + + fast-deep-equal@3.1.3: {} + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fb-watchman@2.0.2: + dependencies: + bser: 2.1.1 + + fdir@6.5.0(picomatch@4.0.7): + optionalDependencies: + picomatch: 4.0.7 + + file-entry-cache@11.1.5: + dependencies: + flat-cache: 6.1.23 + + 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@6.1.23: + dependencies: + cacheable: 2.5.0 + flatted: 3.4.4 + hookified: 1.15.1 + + flatted@3.4.4: {} + + fs.realpath@1.0.0: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + gensync@1.0.0-beta.2: {} + + get-caller-file@2.0.5: {} + + get-package-type@0.1.0: {} + + get-stream@6.0.1: {} + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.5 + once: 1.4.0 + path-is-absolute: 1.0.1 + + graceful-fs@4.2.11: {} + + has-flag@4.0.0: {} + + hashery@1.5.1: + dependencies: + hookified: 1.15.1 + + hasown@2.0.4: + dependencies: + function-bind: 1.1.2 + + hookified@1.15.1: {} + + hookified@2.2.0: {} + + html-escaper@2.0.2: {} + + human-signals@2.1.0: {} + + ignore@5.3.2: {} + + ignore@7.0.9: {} + + import-local@3.2.0: + dependencies: + pkg-dir: 4.2.0 + resolve-cwd: 3.0.0 + + imurmurhash@0.1.4: {} + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + + is-arrayish@0.2.1: {} + + is-core-module@2.17.0: + dependencies: + hasown: 2.0.4 + + is-extglob@2.1.1: {} + + is-fullwidth-code-point@3.0.0: {} + + is-generator-fn@2.1.0: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-number@7.0.0: {} + + is-stream@2.0.1: {} + + isexe@2.0.0: {} + + istanbul-lib-coverage@3.2.2: {} + + istanbul-lib-instrument@5.2.1: + dependencies: + "@babel/core": 7.29.7 + "@babel/parser": 7.29.9 + "@istanbuljs/schema": 0.1.6 + istanbul-lib-coverage: 3.2.2 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + istanbul-lib-instrument@6.0.3: + dependencies: + "@babel/core": 7.29.7 + "@babel/parser": 7.29.9 + "@istanbuljs/schema": 0.1.6 + istanbul-lib-coverage: 3.2.2 + semver: 7.8.5 + transitivePeerDependencies: + - supports-color + + istanbul-lib-report@3.0.1: + dependencies: + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 + supports-color: 7.2.0 + + istanbul-lib-source-maps@4.0.1: + dependencies: + debug: 4.4.3 + istanbul-lib-coverage: 3.2.2 + source-map: 0.6.1 + transitivePeerDependencies: + - supports-color + + istanbul-reports@3.2.0: + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + + jest-changed-files@29.7.0: + dependencies: + execa: 5.1.1 + jest-util: 29.7.0 + p-limit: 3.1.0 + + jest-circus@29.7.0: + dependencies: + "@jest/environment": 29.7.0 + "@jest/expect": 29.7.0 + "@jest/test-result": 29.7.0 + "@jest/types": 29.6.3 + "@types/node": 26.6.2 + chalk: 4.1.2 + co: 4.6.0 + dedent: 1.7.2 + is-generator-fn: 2.1.0 + jest-each: 29.7.0 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + p-limit: 3.1.0 + pretty-format: 29.7.0 + pure-rand: 6.1.0 + slash: 3.0.0 + stack-utils: 2.0.6 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-cli@29.7.0(@types/node@26.6.2): + dependencies: + "@jest/core": 29.7.0 + "@jest/test-result": 29.7.0 + "@jest/types": 29.6.3 + chalk: 4.1.2 + create-jest: 29.7.0(@types/node@26.6.2) + exit: 0.1.2 + import-local: 3.2.0 + jest-config: 29.7.0(@types/node@26.6.2) + jest-util: 29.7.0 + jest-validate: 29.7.0 + yargs: 17.7.3 + transitivePeerDependencies: + - "@types/node" + - babel-plugin-macros + - supports-color + - ts-node + + jest-config@29.7.0(@types/node@26.6.2): + dependencies: + "@babel/core": 7.29.7 + "@jest/test-sequencer": 29.7.0 + "@jest/types": 29.6.3 + babel-jest: 29.7.0(@babel/core@7.29.7) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0 + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.8 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + "@types/node": 26.6.2 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-diff@29.7.0: + dependencies: + chalk: 4.1.2 + diff-sequences: 29.6.3 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + + jest-docblock@29.7.0: + dependencies: + detect-newline: 3.1.0 + + jest-each@29.7.0: + dependencies: + "@jest/types": 29.6.3 + chalk: 4.1.2 + jest-get-type: 29.6.3 + jest-util: 29.7.0 + pretty-format: 29.7.0 + + jest-environment-node@29.7.0: + dependencies: + "@jest/environment": 29.7.0 + "@jest/fake-timers": 29.7.0 + "@jest/types": 29.6.3 + "@types/node": 26.6.2 + jest-mock: 29.7.0 + jest-util: 29.7.0 + + jest-get-type@29.6.3: {} + + jest-haste-map@29.7.0: + dependencies: + "@jest/types": 29.6.3 + "@types/graceful-fs": 4.1.9 + "@types/node": 26.6.2 + anymatch: 3.1.3 + fb-watchman: 2.0.2 + graceful-fs: 4.2.11 + jest-regex-util: 29.6.3 + jest-util: 29.7.0 + jest-worker: 29.7.0 + micromatch: 4.0.8 + walker: 1.0.8 + optionalDependencies: + fsevents: 2.3.3 + + jest-leak-detector@29.7.0: + dependencies: + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + + jest-matcher-utils@29.7.0: + dependencies: + chalk: 4.1.2 + jest-diff: 29.7.0 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + + jest-message-util@29.7.0: + dependencies: + "@babel/code-frame": 7.29.7 + "@jest/types": 29.6.3 + "@types/stack-utils": 2.0.3 + chalk: 4.1.2 + graceful-fs: 4.2.11 + micromatch: 4.0.8 + pretty-format: 29.7.0 + slash: 3.0.0 + stack-utils: 2.0.6 + + jest-mock@29.7.0: + dependencies: + "@jest/types": 29.6.3 + "@types/node": 26.6.2 + jest-util: 29.7.0 + + jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): + optionalDependencies: + jest-resolve: 29.7.0 + + jest-regex-util@29.6.3: {} + + jest-resolve-dependencies@29.7.0: + dependencies: + jest-regex-util: 29.6.3 + jest-snapshot: 29.7.0 + transitivePeerDependencies: + - supports-color + + jest-resolve@29.7.0: + dependencies: + chalk: 4.1.2 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-pnp-resolver: 1.2.3(jest-resolve@29.7.0) + jest-util: 29.7.0 + jest-validate: 29.7.0 + resolve: 1.22.12 + resolve.exports: 2.0.3 + slash: 3.0.0 + + jest-runner@29.7.0: + dependencies: + "@jest/console": 29.7.0 + "@jest/environment": 29.7.0 + "@jest/test-result": 29.7.0 + "@jest/transform": 29.7.0 + "@jest/types": 29.6.3 + "@types/node": 26.6.2 + chalk: 4.1.2 + emittery: 0.13.1 + graceful-fs: 4.2.11 + jest-docblock: 29.7.0 + jest-environment-node: 29.7.0 + jest-haste-map: 29.7.0 + jest-leak-detector: 29.7.0 + jest-message-util: 29.7.0 + jest-resolve: 29.7.0 + jest-runtime: 29.7.0 + jest-util: 29.7.0 + jest-watcher: 29.7.0 + jest-worker: 29.7.0 + p-limit: 3.1.0 + source-map-support: 0.5.13 + transitivePeerDependencies: + - supports-color + + jest-runtime@29.7.0: + dependencies: + "@jest/environment": 29.7.0 + "@jest/fake-timers": 29.7.0 + "@jest/globals": 29.7.0 + "@jest/source-map": 29.6.3 + "@jest/test-result": 29.7.0 + "@jest/transform": 29.7.0 + "@jest/types": 29.6.3 + "@types/node": 26.6.2 + chalk: 4.1.2 + cjs-module-lexer: 1.4.3 + collect-v8-coverage: 1.0.3 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-mock: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + slash: 3.0.0 + strip-bom: 4.0.0 + transitivePeerDependencies: + - supports-color + + jest-snapshot@29.7.0: + dependencies: + "@babel/core": 7.29.7 + "@babel/generator": 7.29.8 + "@babel/plugin-syntax-jsx": 7.29.7(@babel/core@7.29.7) + "@babel/plugin-syntax-typescript": 7.29.7(@babel/core@7.29.7) + "@babel/types": 7.29.8 + "@jest/expect-utils": 29.7.0 + "@jest/transform": 29.7.0 + "@jest/types": 29.6.3 + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.7) + chalk: 4.1.2 + expect: 29.7.0 + graceful-fs: 4.2.11 + jest-diff: 29.7.0 + jest-get-type: 29.6.3 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + natural-compare: 1.4.0 + pretty-format: 29.7.0 + semver: 7.8.5 + transitivePeerDependencies: + - supports-color + + jest-util@29.7.0: + dependencies: + "@jest/types": 29.6.3 + "@types/node": 26.6.2 + chalk: 4.1.2 + ci-info: 3.9.0 + graceful-fs: 4.2.11 + picomatch: 2.3.2 + + jest-validate@29.7.0: + dependencies: + "@jest/types": 29.6.3 + camelcase: 6.3.0 + chalk: 4.1.2 + jest-get-type: 29.6.3 + leven: 3.1.0 + pretty-format: 29.7.0 + + jest-watcher@29.7.0: + dependencies: + "@jest/test-result": 29.7.0 + "@jest/types": 29.6.3 + "@types/node": 26.6.2 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + emittery: 0.13.1 + jest-util: 29.7.0 + string-length: 4.0.2 + + jest-worker@29.7.0: + dependencies: + "@types/node": 26.6.2 + jest-util: 29.7.0 + merge-stream: 2.0.0 + supports-color: 8.1.1 + + jest@29.7.0(@types/node@26.6.2): + dependencies: + "@jest/core": 29.7.0 + "@jest/types": 29.6.3 + import-local: 3.2.0 + jest-cli: 29.7.0(@types/node@26.6.2) + transitivePeerDependencies: + - "@types/node" + - babel-plugin-macros + - supports-color + - ts-node + + js-tokens@4.0.0: {} + + js-yaml@3.15.2: + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + + jsesc@3.1.0: {} + + json-parse-even-better-errors@2.3.1: {} + + json-schema-traverse@0.4.1: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json5@2.2.3: {} + + keyv@5.6.0: + dependencies: + "@keyv/serialize": 1.1.1 + + kleur@3.0.3: {} + + leven@3.1.0: {} + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + lines-and-columns@1.2.4: {} + + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + make-dir@4.0.0: + dependencies: + semver: 7.8.5 + + makeerror@1.0.12: + dependencies: + tmpl: 1.0.5 + + merge-stream@2.0.0: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.2 + + mimic-fn@2.1.0: {} + + minimatch@10.2.6: + dependencies: + brace-expansion: 5.0.12 + + minimatch@3.1.5: + dependencies: + brace-expansion: 1.1.21 + + ms@2.1.3: {} + + nanoid@3.3.19: {} + + natural-compare@1.4.0: {} + + node-int64@0.4.0: {} + + node-releases@2.0.56: {} + + normalize-path@3.0.0: {} + + npm-run-path@4.0.1: + dependencies: + path-key: 3.1.1 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + onetime@5.1.2: + dependencies: + mimic-fn: 2.1.0 + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + 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-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: {} + + parse-json@5.2.0: + dependencies: + "@babel/code-frame": 7.29.7 + error-ex: 1.3.4 + 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-parse@1.0.7: {} + + picocolors@1.1.1: {} + + picomatch@2.3.2: {} + + picomatch@4.0.7: {} + + pirates@4.0.7: {} + + pkg-dir@4.2.0: + dependencies: + find-up: 4.1.0 + + playwright-core@1.63.0: {} + + playwright@1.63.0: + dependencies: + playwright-core: 1.63.0 + + postcss@8.5.28: + dependencies: + nanoid: 3.3.19 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prelude-ls@1.2.1: {} + + prettier@3.9.8: {} + + pretty-format@29.7.0: + dependencies: + "@jest/schemas": 29.6.3 + ansi-styles: 5.2.0 + react-is: 18.3.1 + + prompts@2.4.2: + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + + punycode@2.3.1: {} + + pure-rand@6.1.0: {} + + qified@0.10.1: + dependencies: + hookified: 2.2.0 + + react-dom@19.3.0(react@19.3.0): + dependencies: + react: 19.3.0 + scheduler: 0.28.0 + + react-is@18.3.1: {} + + react@19.3.0: {} + + require-directory@2.1.1: {} + + resolve-cwd@3.0.0: + dependencies: + resolve-from: 5.0.0 + + resolve-from@5.0.0: {} + + resolve.exports@2.0.3: {} + + resolve@1.22.12: + dependencies: + es-errors: 1.3.0 + is-core-module: 2.17.0 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + rollup@4.63.4: + dependencies: + "@types/estree": 1.0.9 + optionalDependencies: + "@napi-rs/lzma-linux-x64-gnu": 1.5.1 + "@rollup/rollup-android-arm-eabi": 4.63.4 + "@rollup/rollup-android-arm64": 4.63.4 + "@rollup/rollup-darwin-arm64": 4.63.4 + "@rollup/rollup-darwin-x64": 4.63.4 + "@rollup/rollup-freebsd-arm64": 4.63.4 + "@rollup/rollup-freebsd-x64": 4.63.4 + "@rollup/rollup-linux-arm-gnueabihf": 4.63.4 + "@rollup/rollup-linux-arm-musleabihf": 4.63.4 + "@rollup/rollup-linux-arm64-gnu": 4.63.4 + "@rollup/rollup-linux-arm64-musl": 4.63.4 + "@rollup/rollup-linux-loong64-gnu": 4.63.4 + "@rollup/rollup-linux-loong64-musl": 4.63.4 + "@rollup/rollup-linux-ppc64-gnu": 4.63.4 + "@rollup/rollup-linux-ppc64-musl": 4.63.4 + "@rollup/rollup-linux-riscv64-gnu": 4.63.4 + "@rollup/rollup-linux-riscv64-musl": 4.63.4 + "@rollup/rollup-linux-s390x-gnu": 4.63.4 + "@rollup/rollup-linux-x64-gnu": 4.63.4 + "@rollup/rollup-linux-x64-musl": 4.63.4 + "@rollup/rollup-openbsd-x64": 4.63.4 + "@rollup/rollup-openharmony-arm64": 4.63.4 + "@rollup/rollup-win32-arm64-msvc": 4.63.4 + "@rollup/rollup-win32-ia32-msvc": 4.63.4 + "@rollup/rollup-win32-x64-gnu": 4.63.4 + "@rollup/rollup-win32-x64-msvc": 4.63.4 + fsevents: 2.3.3 + + scheduler@0.28.0: {} + + semver@6.3.1: {} + + semver@7.8.5: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + signal-exit@3.0.7: {} + + sisteransi@1.0.5: {} + + slash@3.0.0: {} + + source-map-js@1.2.1: {} + + source-map-support@0.5.13: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.6.1: {} + + sprintf-js@1.0.3: {} + + stack-utils@2.0.6: + dependencies: + escape-string-regexp: 2.0.0 + + string-length@4.0.2: + dependencies: + char-regex: 1.0.2 + strip-ansi: 6.0.1 + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-bom@4.0.0: {} + + strip-final-newline@2.0.0: {} + + strip-json-comments@3.1.1: {} + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + test-exclude@6.0.0: + dependencies: + "@istanbuljs/schema": 0.1.6 + glob: 7.2.3 + minimatch: 3.1.5 + + tinyglobby@0.2.17: + dependencies: + fdir: 6.5.0(picomatch@4.0.7) + picomatch: 4.0.7 + + tmpl@1.0.5: {} + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + ts-api-utils@2.5.0(typescript@5.9.3): + dependencies: + typescript: 5.9.3 + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + type-detect@4.0.8: {} + + type-fest@0.21.3: {} + + typescript-eslint@8.70.1(eslint@10.11.0)(typescript@5.9.3): + dependencies: + "@typescript-eslint/eslint-plugin": 8.70.1(@typescript-eslint/parser@8.70.1(eslint@10.11.0)(typescript@5.9.3))(eslint@10.11.0)(typescript@5.9.3) + "@typescript-eslint/parser": 8.70.1(eslint@10.11.0)(typescript@5.9.3) + "@typescript-eslint/typescript-estree": 8.70.1(typescript@5.9.3) + "@typescript-eslint/utils": 8.70.1(eslint@10.11.0)(typescript@5.9.3) + eslint: 10.11.0 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + typescript@5.9.3: {} + + undici-types@8.9.0: {} + + update-browserslist-db@1.3.3(browserslist@4.29.0): + dependencies: + browserslist: 4.29.0 + escalade: 3.2.0 + picocolors: 1.1.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + v8-to-istanbul@9.3.0: + dependencies: + "@jridgewell/trace-mapping": 0.3.31 + "@types/istanbul-lib-coverage": 2.0.6 + convert-source-map: 2.0.0 + + vite@6.4.3(@types/node@26.6.2): + dependencies: + esbuild: 0.25.12 + fdir: 6.5.0(picomatch@4.0.7) + picomatch: 4.0.7 + postcss: 8.5.28 + rollup: 4.63.4 + tinyglobby: 0.2.17 + optionalDependencies: + "@types/node": 26.6.2 + fsevents: 2.3.3 + + walker@1.0.8: + dependencies: + makeerror: 1.0.12 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + word-wrap@1.2.5: {} + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrappy@1.0.2: {} + + write-file-atomic@4.0.2: + dependencies: + imurmurhash: 0.1.4 + signal-exit: 3.0.7 + + y18n@5.0.8: {} + + yallist@3.1.1: {} + + yargs-parser@21.1.1: {} + + yargs@17.7.3: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + + yocto-queue@0.1.0: {} diff --git a/web/tests/e2e/.gitkeep b/web/tests/e2e/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/web/tests/infrastructure/toolchain.test.cjs b/web/tests/infrastructure/toolchain.test.cjs new file mode 100644 index 0000000..3d44d78 --- /dev/null +++ b/web/tests/infrastructure/toolchain.test.cjs @@ -0,0 +1,5 @@ +const packageMetadata = require("../../package.json"); + +test("web tooling metadata is available", () => { + expect(packageMetadata.name).toBe("medcheck-web"); +}); diff --git a/web/tests/infrastructure/toolchain.ts b/web/tests/infrastructure/toolchain.ts new file mode 100644 index 0000000..47da146 --- /dev/null +++ b/web/tests/infrastructure/toolchain.ts @@ -0,0 +1,2 @@ +// TypeScript configuration probe; application code belongs in a later change. +export {}; diff --git a/web/tsconfig.json b/web/tsconfig.json new file mode 100644 index 0000000..02088a2 --- /dev/null +++ b/web/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "target": "ES2023", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "strict": true, + "noEmit": true, + "skipLibCheck": true + }, + "files": ["tests/infrastructure/toolchain.ts"] +} From be3a7d4ba06a66510220c955b1f393287746760e Mon Sep 17 00:00:00 2001 From: jonathoncontact Date: Mon, 21 Sep 2026 14:31:54 -0700 Subject: [PATCH 3/3] Tech stack - added pr-checks.yml lines 16-18 --- .github/workflows/pr-checks.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml index 1307046..f70fba6 100644 --- a/.github/workflows/pr-checks.yml +++ b/.github/workflows/pr-checks.yml @@ -13,6 +13,9 @@ jobs: steps: - uses: actions/checkout@v4 - uses: gitleaks/gitleaks-action@v2 + //changed here because github told me... + env: + GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }} backend: name: Backend tooling