diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 00000000..ef82ecf2 Binary files /dev/null and b/.DS_Store differ diff --git a/.env.default b/.env.default index 415b0b7e..8c0250b3 100644 --- a/.env.default +++ b/.env.default @@ -1,2 +1,3 @@ AUTH_TOKEN= -TIFF_PATH= \ No newline at end of file +TIFF_PATH= +GRID_TILES_PATH= \ No newline at end of file diff --git a/.github/workflows/cicd.yml b/.github/workflows/cicd.yml index 5bdd584f..fd3bfd10 100644 --- a/.github/workflows/cicd.yml +++ b/.github/workflows/cicd.yml @@ -3,8 +3,8 @@ name: CI / CD on: push: paths: - - 'api/**' - - '.github/workflows/cicd.yml' + - "api/**" + - ".github/workflows/cicd.yml" workflow_dispatch: jobs: @@ -13,17 +13,17 @@ jobs: runs-on: ubuntu-latest steps: - - name: Check out the repository - uses: actions/checkout@v2 + - name: Check out the repository + uses: actions/checkout@v2 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 - - name: Build and run tests - run: docker-compose up --build --exit-code-from test test + - name: Build and run tests + run: docker compose up --build --exit-code-from test test - - name: Clean up - run: docker-compose down + - name: Clean up + run: docker compose down deploy: name: Deploy @@ -31,18 +31,17 @@ jobs: needs: build-and-test if: github.ref == 'refs/heads/develop' steps: - - - name: Deploy to EC2 - uses: appleboy/ssh-action@master - with: - host: ${{ secrets.HOST }} - username: ${{ secrets.USERNAME }} - key: ${{ secrets.SSH_KEY }} - script: | - cd amazonia-360 - git pull --rebase - sudo docker-compose down - sudo docker-compose up -d api --build + - name: Deploy to EC2 + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.DEV_HOST }} + username: ${{ secrets.USERNAME }} + key: ${{ secrets.SSH_KEY }} + script: | + cd amazonia-360 + git pull --rebase + sudo docker compose down + sudo docker compose up -d api --build health-check: name: Health Check @@ -53,8 +52,6 @@ jobs: - name: URL Health Check uses: Jtalk/url-health-check-action@v4 with: - url: ${{ secrets.HEALTHCHECK }} + url: ${{ secrets.DEV_HEALTHCHECK }} retries: 5 wait: 10 - - diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9d983358..06290094 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -16,8 +16,7 @@ repos: - id: ruff-format types_or: [ python, pyi, jupyter ] - # check for private keys and passwords! - - repo: https://github.com/gitleaks/gitleaks - rev: v8.17.0 + - repo: https://github.com/kynan/nbstripout + rev: 0.7.1 hooks: - - id: gitleaks-docker + - id: nbstripout diff --git a/README.md b/README.md index 2c87bffd..73461bd6 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,3 @@ # amazonia-360 -Amazonia 360 + +Amazonia 360+ diff --git a/api/Dockerfile b/api/Dockerfile index 31bd2524..b95b4b07 100644 --- a/api/Dockerfile +++ b/api/Dockerfile @@ -1,6 +1,13 @@ FROM python:3.11-slim as base LABEL maintainer="hello@vizzuality.com" +# Requirement of fiona and gdal. +RUN set -eux; \ + apt-get update; \ + apt-get install -y --no-install-recommends libexpat1; \ + rm -rf /var/lib/apt/lists/* + + FROM base as production ENV NAME api ENV APP_HOME /opt/$NAME diff --git a/api/README.md b/api/README.md index 95fd55e2..d7aa03c6 100644 --- a/api/README.md +++ b/api/README.md @@ -1,8 +1,9 @@ -# Amazonia360 API +# Amazonia360+ API ## Python setup ### Production + Use the `requirements.txt` file to install the required packages. ```bash @@ -17,7 +18,6 @@ First create a virtual environment with virtualenv or uv. Then install the dependencies with the following command: - ```bash pip-sync requirements.txt requirements-dev.txt ``` @@ -30,4 +30,4 @@ uv pip sync requirements.txt requirements-dev.txt To add a new production dependency, add it to the `requirements.in` file and run `uv pip compile requirements.in -o requirements.txt` (or `pip-compile requirements.in -o requirements.txt`). -To add a new development dependency repeat the same process with the `requirements-dev.in` and `requirement-dev.txt` file. +To add a new development dependency repeat the same process with the `requirements-dev.in` and `requirement-dev.txt` file. diff --git a/api/app/auth/auth.py b/api/app/auth/auth.py index ff05d547..b3d5ec88 100644 --- a/api/app/auth/auth.py +++ b/api/app/auth/auth.py @@ -1,44 +1,15 @@ -"""Auth middleware for the API.""" +"""Auth dependency for the API.""" -from fastapi import HTTPException -from fastapi.security import HTTPBearer -from starlette.middleware.base import BaseHTTPMiddleware -from starlette.requests import Request -from starlette.responses import Response +from fastapi import Depends, HTTPException +from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer from starlette.status import HTTP_401_UNAUTHORIZED from app.config.config import get_settings -security = HTTPBearer() +security = HTTPBearer(auto_error=False) -def verify_token(request: Request): +def verify_token(credentials: HTTPAuthorizationCredentials = Depends(security)): """Validate API key.""" - auth_token = get_settings().auth_token - auth_header = request.headers.get('Authorization') - if not auth_header: + if credentials is None or credentials.credentials != get_settings().auth_token: raise HTTPException(status_code=HTTP_401_UNAUTHORIZED, detail="Unauthorized") - - try: - scheme, token = auth_header.split() - if scheme.lower() != 'bearer' or token != auth_token: - raise HTTPException(status_code=HTTP_401_UNAUTHORIZED, detail="Unauthorized") - except ValueError: - raise HTTPException(status_code=HTTP_401_UNAUTHORIZED, detail="Invalid authorization header") # noqa: B904 - - return token - - -class AuthMiddleware(BaseHTTPMiddleware): - """Generic auth middleware.""" - - async def dispatch(self, request: Request, call_next): # noqa: D102 - if request.url.path == "/docs" or request.url.path == "/openapi.json" or request.url.path == "/health": - return await call_next(request) - request_token = request.headers.get("Authorization") - if request_token and request_token.startswith("Bearer "): - request_token = request_token.split("Bearer ")[1] - if request_token == get_settings().auth_token: - return await call_next(request) - else: - return Response(content="Unauthorized", status_code=401) diff --git a/api/app/config/config.py b/api/app/config/config.py index a4038276..c57f6501 100644 --- a/api/app/config/config.py +++ b/api/app/config/config.py @@ -10,6 +10,8 @@ class Settings(BaseSettings): auth_token: str tiff_path: str + grid_tiles_path: str + tile_to_cell_resolution_diff: int = 5 @lru_cache diff --git a/api/app/main.py b/api/app/main.py index e351f865..9154b09c 100644 --- a/api/app/main.py +++ b/api/app/main.py @@ -9,6 +9,7 @@ from app.auth.auth import verify_token from app.config.config import get_settings +from app.routers.grid import grid_router from app.routers.zonal_stats import ZonalTilerFactory @@ -25,13 +26,15 @@ def path_params(raster_filename: Annotated[str, Query(description="Raster filena app = FastAPI(title="Amazonia360 API", default_response_class=ORJSONResponse) app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"]) -routes = ZonalTilerFactory(path_dependency=path_params) -app.include_router(routes.router, dependencies=[Depends(verify_token)]) +tiler_routes = ZonalTilerFactory(path_dependency=path_params) + +app.include_router(tiler_routes.router, tags=["Raster"], dependencies=[Depends(verify_token)]) +app.include_router(grid_router, prefix="/grid", tags=["Grid"], dependencies=[Depends(verify_token)]) add_exception_handlers(app, DEFAULT_STATUS_CODES) -@app.get("/tifs", dependencies=[Depends(verify_token)]) +@app.get("/tifs", tags=["Raster"], dependencies=[Depends(verify_token)]) async def list_files(): """List all available tif files.""" tiff_path = get_settings().tiff_path diff --git a/api/app/models/grid.py b/api/app/models/grid.py new file mode 100644 index 00000000..17ce102d --- /dev/null +++ b/api/app/models/grid.py @@ -0,0 +1,147 @@ +# ruff: noqa: D101 + +from enum import Enum +from typing import Annotated, Literal + +from fastapi import Query +from pydantic import BaseModel, ConfigDict, Field +from pydantic_extra_types.color import Color +from sqlalchemy.sql import column, desc, nullslast, select, table + + +class LegendTypes(str, Enum): + continuous = "continuous" + discrete = "discrete" + categorical = "categorical" + + +class LevelStats(BaseModel): + level: int = Field( + ge=0, + le=15, + description="Stats for this level. AKA Overview or zoom level in other applications", + ) + min: int | float | None = Field(..., description="null value represents -infinity") + max: int | float | None = Field(..., description="null value represents infinity") + + +class NumericalLegend(BaseModel): + legend_type: Literal["discrete"] | Literal["continuous"] + colormap_name: str | None = Field("viridis", description="suggestion of color map to use") + stats: list[LevelStats] + + +class CategoricalLegendEntry(BaseModel): + model_config = ConfigDict(json_encoders={Color: lambda c: c.as_hex()}) + value: int | str + color: Color + label: str = Field(description="human readable label") + + +class CategoricalLegend(BaseModel): + legend_type: Literal["categorical"] + entries: list[CategoricalLegendEntry] + + +class DatasetMeta(BaseModel): + var_name: str = Field(description="Column name.") + var_dtype: str = Field(description="Column dtype.") + label: str = Field(description="Human readable name.") + nodata: str | None = Field(default=None, description="Nodata value used in grid") + description: str = Field(description="Human readable indicator description.") + unit: str | None = Field(description="Unit of the measurement") + lineage: list[str] | None = Field(default=None, description="Source data used to compute this dataset.") + legend: CategoricalLegend | NumericalLegend = Field(discriminator="legend_type") + + +class H3GridInfo(BaseModel): + level: int = Field(ge=0, le=15) + h3_cells_resolution: int = Field(ge=0, le=15) + h3_cells_count: int + + +class MultiDatasetMeta(BaseModel): + datasets: list[DatasetMeta] = Field(description="Variables represented in this dataset.") + h3_grid_info: list[H3GridInfo] = Field(description="H3 related information.") + + +# =============================================== +# TABLE FILTERING +# =============================================== + + +class NumericalOperators(str, Enum): + eq = "eq" + gt = "gt" + lt = "lt" + gte = "gte" + lte = "lte" + not_eq = "not_eq" + + +class CategoricalOperators(str, Enum): + in_ = "in" + not_in = "not_in" + + +class CategoricalFilter(BaseModel): + filter_type: Literal["categorical"] + column_name: str = Field(description="Name of the column to which the filter will apply.") + operation: CategoricalOperators + value: list[int] = Field(description="Value to compare with.") + + +class NumericalFilter(BaseModel): + filter_type: Literal["numerical"] + column_name: str = Field(description="Name of the column to which the filter will apply.") + operation: NumericalOperators = Field(description="Operation to use in compare.") + value: float = Field(description="Value to compare with.") + + +class TableFilters(BaseModel): + filters: list[Annotated[CategoricalFilter | NumericalFilter, Field(discriminator="filter_type")]] + limit: int = Field(Query(10, lt=1000, description="Number of records.")) + order_by: Annotated[ + list[str], + Field( + Query(..., description="Prepend '-' to column name to make it descending"), + ), + ] + + def to_sql_query(self, table_name: str) -> str: + """Compile model to sql query""" + op_to_python_dunder = { + "eq": "__eq__", + "gt": "__gt__", + "lt": "__lt__", + "gte": "__ge__", + "lte": "__le__", + "not_eq": "__ne__", + "in": "in_", + } + filters_to_apply = [] + for _filter in self.filters: + if _filter is None: + continue + col = column(_filter.column_name) + param = getattr(col, op_to_python_dunder.get(_filter.operation, _filter.operation))(_filter.value) + filters_to_apply.append(param) + query = ( + select("*") + .select_from(table(table_name)) + .where(*filters_to_apply) + .limit(self.limit) + .order_by( + *[nullslast(desc(column(col[1:]))) if col.startswith("-") else column(col) for col in self.order_by] + ) + ) + return str(query.compile(compile_kwargs={"literal_binds": True})) + + +class TableResultColumn(BaseModel): + column: Annotated[str, Field(title="column", description="Column name")] + values: Annotated[list, Field(description="Check dataset metadata for type info")] + + +class TableResults(BaseModel): + table: list[TableResultColumn] diff --git a/api/app/models/exact_extract.py b/api/app/models/zonal_stats.py similarity index 100% rename from api/app/models/exact_extract.py rename to api/app/models/zonal_stats.py diff --git a/api/app/routers/grid.py b/api/app/routers/grid.py new file mode 100644 index 00000000..4ced36de --- /dev/null +++ b/api/app/routers/grid.py @@ -0,0 +1,180 @@ +import io +import logging +import os +import pathlib +from functools import lru_cache +from typing import Annotated + +import h3 +import h3ronpy.polars # noqa: F401 +import polars as pl +import pyarrow as pa +import shapely +from fastapi import APIRouter, Depends, HTTPException, Path, Query +from fastapi.params import Body +from fastapi.responses import Response +from geojson_pydantic import Feature +from h3 import H3CellError +from h3ronpy.polars import cells_to_string +from h3ronpy.polars.vector import geometry_to_cells +from pydantic import ValidationError + +from app.config.config import get_settings +from app.models.grid import MultiDatasetMeta, TableFilters, TableResults + +log = logging.getLogger("uvicorn.error") # Show the logs in the uvicorn runner logs + +grid_router = APIRouter() + +tile_exception_responses = { + 400: {"description": "Column does not exist or tile_index is not valid h3 index."}, + 404: {"description": "Tile does not exist or is empty"}, +} + + +class ArrowIPCResponse(Response): # noqa: D101 + media_type = "application/octet-stream" + + +def get_tile(tile_index: str, columns: list[str]) -> tuple[pl.LazyFrame, int]: + """Get the tile from filesystem filtered by column and the resolution of the tile index""" + try: + z = h3.api.basic_str.h3_get_resolution(tile_index) + except (H3CellError, ValueError): + raise HTTPException(status_code=400, detail="Tile index is not a valid H3 cell") from None + tile_path = os.path.join(get_settings().grid_tiles_path, f"{z}/{tile_index}.arrow") + if not os.path.exists(tile_path): + raise HTTPException(status_code=404, detail=f"Tile {tile_path} not found") + tile = pl.scan_ipc(tile_path).select(["cell", *columns]) + return tile, z + + +@lru_cache +def cells_in_geojson(geometry: str, cell_resolution: int) -> pl.LazyFrame: + """Return the cells that fill the polygon area in the geojson + + Geometry must be a shapely geometry, a wkt or wkb so the lru cache + can hash the parameter. + """ + cells = cells_to_string(geometry_to_cells(geometry, cell_resolution)) + return pl.LazyFrame({"cell": cells}) + + +def polars_to_string_ipc(df: pl.DataFrame) -> bytes: + """Cast cell column of polars dataframe to arrow type `string` and return the ipc bytes.""" + # For performance reasons all the strings in polars are treated as `large_string`, + # a custom string type. As of today, the frontend library @loadrs.gl/arrow only supports + # `string` type so we need to downcast with pyarrow + table: pa.Table = df.to_arrow() + + schema = table.schema + schema = schema.set(schema.get_field_index("cell"), pa.field("cell", pa.string())) + table = table.cast(schema) + sink = io.BytesIO() + with pa.ipc.new_file(sink, table.schema) as writer: + writer.write_table(table) + return sink.getvalue() + +@grid_router.get( + "/tile/{tile_index}", + summary="Get a grid tile", + response_class=ArrowIPCResponse, + response_description="Arrow IPC table", + responses=tile_exception_responses, +) +def grid_tile( + tile_index: Annotated[str, Path(description="The `h3` index of the tile")], + columns: list[str] = Query( + [], description="Colum/s to include in the tile. If empty, it returns only cell indexes." + ), +) -> ArrowIPCResponse: + """Get a tile of h3 cells with specified data columns""" + tile, _ = get_tile(tile_index, columns) + try: + tile = tile.collect() + # we don't know if the column requested are correct until we call .collect() + except pl.exceptions.ColumnNotFoundError: + raise HTTPException(status_code=400, detail="One or more of the specified columns is not valid") from None + return ArrowIPCResponse(polars_to_string_ipc(tile)) + + +@grid_router.post( + "/tile/{tile_index}", + summary="Get a grid tile with cells contained inside the GeoJSON", + response_class=ArrowIPCResponse, + response_description="Arrow IPC table", + responses=tile_exception_responses, +) +def grid_tile_in_area( + tile_index: Annotated[str, Path(description="The `h3` index of the tile")], + geojson: Annotated[Feature, Body(description="GeoJSON feature used to filter the cells.")], + columns: list[str] = Query( + [], description="Colum/s to include in the tile. If empty, it returns only cell indexes." + ), +) -> ArrowIPCResponse: + """Get a tile of h3 cells that are inside the polygon""" + tile, tile_index_res = get_tile(tile_index, columns) + cell_res = tile_index_res + get_settings().tile_to_cell_resolution_diff + geom = shapely.from_geojson(geojson.model_dump_json()) + cells = cells_in_geojson(geom, cell_res) + try: + tile = tile.join(cells, on="cell").collect() + # we don't know if the column requested are correct until we call .collect() + except pl.exceptions.ColumnNotFoundError: + raise HTTPException(status_code=400, detail="One or more of the specified columns is not valid") from None + if tile.is_empty(): + raise HTTPException(status_code=404, detail="No data in region") + return ArrowIPCResponse(polars_to_string_ipc(tile)) + + +@grid_router.get( + "/meta", + summary="Dataset metadata", +) +async def grid_dataset_metadata() -> MultiDatasetMeta: + """Get the grid dataset metadata""" + file = os.path.join(get_settings().grid_tiles_path, "meta.json") + with open(file) as f: + raw = f.read() + try: + meta = MultiDatasetMeta.model_validate_json(raw) + except ValidationError as e: + # validation error is our fault because meta file is internal. We don't want to show internal error details + # so raise controlled 500 + log.exception(e) + raise HTTPException(status_code=500, detail="Metadata file is malformed. Please contact developer.") from None + return meta + + +@grid_router.post("/table") +def read_table( + level: Annotated[int, Query(..., description="Tile level at which the query will be computed")], + filters: TableFilters = Depends(), + geojson: Feature | None = None, +) -> TableResults: + """Query tile dataset and return table data""" + files_path = pathlib.Path(get_settings().grid_tiles_path) / str(level) + if not files_path.exists(): + raise HTTPException(404, detail=f"Level {level} does not exist") from None + + lf = pl.scan_ipc(list(files_path.glob("*.arrow"))) + + if geojson is not None: + cell_res = level + get_settings().tile_to_cell_resolution_diff + geom = shapely.from_geojson(geojson.model_dump_json()) + cells = cells_in_geojson(geom, cell_res) + lf = lf.join(cells, on="cell") + + query = filters.to_sql_query("frame") + log.debug(query) + + try: + res = pl.SQLContext(frame=lf).execute(query).collect() + except pl.exceptions.ColumnNotFoundError as e: # bad column in order by clause + log.exception(e) + raise HTTPException(status_code=400, detail="One or more of the specified columns is not valid") from None + except pl.exceptions.ComputeError as e: # raised if wrong type in compare. + log.exception(e) + raise HTTPException(status_code=422, detail=str(e)) from None + + return TableResults(table=[{"column": k, "values": v} for k, v in res.to_dict(as_series=False).items()]) diff --git a/api/app/routers/zonal_stats.py b/api/app/routers/zonal_stats.py index 0f9911c5..1e7f080f 100644 --- a/api/app/routers/zonal_stats.py +++ b/api/app/routers/zonal_stats.py @@ -1,5 +1,5 @@ """Minimal COG tiler.""" -import os + from typing import Annotated, List, Union import rasterio @@ -8,8 +8,7 @@ from geojson_pydantic import Feature, FeatureCollection from titiler.core.factory import TilerFactory -from app.config.config import get_settings -from app.models.exact_extract import StatsFeatures, StatsOps +from app.models.zonal_stats import StatsFeatures, StatsOps class ZonalTilerFactory(TilerFactory): @@ -65,8 +64,6 @@ def exact_zonal_stats( features = [geojson.model_dump()] with rasterio.Env(**env): - tiff_path = get_settings().tiff_path - src_path = os.path.join(tiff_path, src_path) with rasterio.open(src_path, **reader_params) as src_dst: statistics = [op.value for op in statistics] # extract the values from the Enum stats = exact_extract(src_dst, features, ops=statistics) diff --git a/api/pyproject.toml b/api/pyproject.toml index 9f929ad5..034ba548 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -1,7 +1,7 @@ [tool.ruff] line-length = 120 extend-include = ["*.ipynb"] -src = ["app"] +src = ["."] [tool.ruff.lint] select = [ @@ -24,3 +24,6 @@ extend-immutable-calls = ["fastapi.Depends", "fastapi.params.Depends", "fastapi. [tool.ruff.lint.per-file-ignores] "**/{tests}/*" = ["D103"] # Missing docstring in public function + +[tool.mypy] +disable_error_code = ["import-untyped", "attr-defined"] diff --git a/api/requirements.in b/api/requirements.in index 397e3edf..2d6a81c2 100644 --- a/api/requirements.in +++ b/api/requirements.in @@ -4,3 +4,8 @@ orjson pydantic_settings titiler.core uvicorn +h3 +pydantic-extra-types +polars +sqlalchemy +h3ronpy \ No newline at end of file diff --git a/api/requirements.txt b/api/requirements.txt index f5389ba6..471937ae 100644 --- a/api/requirements.txt +++ b/api/requirements.txt @@ -2,20 +2,20 @@ # uv pip compile requirements.in -o requirements.txt affine==2.4.0 # via rasterio -annotated-types==0.6.0 +annotated-types==0.7.0 # via pydantic -anyio==4.3.0 +anyio==4.4.0 # via # httpx # starlette -attrs==23.2.0 +attrs==24.2.0 # via # morecantile # rasterio # rio-tiler -cachetools==5.3.3 +cachetools==5.5.0 # via rio-tiler -certifi==2024.2.2 +certifi==2024.8.30 # via # httpcore # httpx @@ -31,74 +31,97 @@ click-plugins==1.1.1 # via rasterio cligj==0.7.2 # via rasterio -color-operations==0.1.3 +color-operations==0.1.5 # via rio-tiler -exactextract==0.2.0.dev0 -fastapi==0.110.1 - # via titiler-core -geojson-pydantic==1.0.2 +exactextract==0.2.0 + # via -r requirements.in +fastapi==0.114.1 + # via + # -r requirements.in + # titiler-core +geojson-pydantic==1.1.1 # via titiler-core +greenlet==3.1.0 + # via sqlalchemy h11==0.14.0 # via # httpcore # uvicorn +h3==3.7.7 + # via -r requirements.in +h3ronpy==0.21.0 + # via -r requirements.in httpcore==1.0.5 # via httpx -httpx==0.27.0 +httpx==0.27.2 # via rio-tiler -idna==3.6 +idna==3.8 # via # anyio # httpx -jinja2==3.1.3 +jinja2==3.1.4 # via titiler-core markupsafe==2.1.5 # via jinja2 -morecantile==5.3.0 +morecantile==5.4.2 # via # rio-tiler # titiler-core -numexpr==2.10.0 +numexpr==2.10.1 # via rio-tiler numpy==1.26.4 # via # color-operations + # h3ronpy # numexpr + # pyarrow # rasterio # rio-tiler + # shapely # snuggs # titiler-core -orjson==3.10.0 -pydantic==2.6.4 +orjson==3.10.7 + # via -r requirements.in +polars==1.7.0 + # via -r requirements.in +pyarrow==17.0.0 + # via h3ronpy +pydantic==2.9.1 # via # fastapi # geojson-pydantic # morecantile + # pydantic-extra-types # pydantic-settings # rio-tiler # titiler-core -pydantic-core==2.16.3 +pydantic-core==2.23.3 # via pydantic -pydantic-settings==2.2.1 -pyparsing==3.1.2 +pydantic-extra-types==2.9.0 + # via -r requirements.in +pydantic-settings==2.5.2 + # via -r requirements.in +pyparsing==3.1.4 # via snuggs pyproj==3.6.1 # via morecantile -pystac==1.10.0 +pystac==1.10.1 # via rio-tiler python-dateutil==2.9.0.post0 # via pystac python-dotenv==1.0.1 # via pydantic-settings -rasterio==1.3.9 +rasterio==1.3.11 # via # rio-tiler # titiler-core -rio-tiler==6.4.5 +rio-tiler==6.7.0 # via titiler-core -setuptools==69.2.0 +setuptools==74.1.2 # via rasterio -simplejson==3.19.2 +shapely==2.0.6 + # via h3ronpy +simplejson==3.19.3 # via titiler-core six==1.16.0 # via python-dateutil @@ -108,13 +131,18 @@ sniffio==1.3.1 # httpx snuggs==1.4.7 # via rasterio -starlette==0.37.2 +sqlalchemy==2.0.34 + # via -r requirements.in +starlette==0.38.5 # via fastapi -titiler-core==0.18.0 -typing-extensions==4.11.0 +titiler-core==0.18.6 + # via -r requirements.in +typing-extensions==4.12.2 # via # fastapi # pydantic # pydantic-core + # sqlalchemy # titiler-core -uvicorn==0.29.0 +uvicorn==0.30.6 + # via -r requirements.in diff --git a/api/tests/benchmark_grid_post.lua b/api/tests/benchmark_grid_post.lua new file mode 100644 index 00000000..ea2083cf --- /dev/null +++ b/api/tests/benchmark_grid_post.lua @@ -0,0 +1,147 @@ +-- command: +-- wrk -c 100 -t 10 -d 10s -s benchmark_grid_post.lua 'http://localhost:8000/grid/tile/815f7ffffffffff?columns=AMIN' + +local geojsons = { + [[ + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + [ + [ + -61.113268179996055, + 8.666717320892204 + ], + [ + -61.113268179996055, + 8.505177617822142 + ], + [ + -60.86538798013957, + 8.505177617822142 + ], + [ + -60.86538798013957, + 8.666717320892204 + ], + [ + -61.113268179996055, + 8.666717320892204 + ] + ] + ], + "type": "Polygon" + } + } + ]], + [[ + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + [ + [ + -66.98965634041855, + -2.552105344245007 + ], + [ + -66.98965634041855, + -6.931424712822178 + ], + [ + -60.673596725229004, + -6.931424712822178 + ], + [ + -60.673596725229004, + -2.552105344245007 + ], + [ + -66.98965634041855, + -2.552105344245007 + ] + ] + ], + "type": "Polygon" + } + } + ]], + [[ + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + [ + [ + -59.40141593993765, + -0.8180702598489091 + ], + [ + -59.40141593993765, + -3.8038880006152453 + ], + [ + -56.08276971246181, + -3.8038880006152453 + ], + [ + -56.08276971246181, + -0.8180702598489091 + ], + [ + -59.40141593993765, + -0.8180702598489091 + ] + ] + ], + "type": "Polygon" + } + } + ]], + [[ + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + [ + [ + -68.36016539573357, + -3.4797077655746023 + ], + [ + -68.36016539573357, + -10.328634044400019 + ], + [ + -60.34168576692953, + -10.328634044400019 + ], + [ + -60.34168576692953, + -3.4797077655746023 + ], + [ + -68.36016539573357, + -3.4797077655746023 + ] + ] + ], + "type": "Polygon" + } + } + ]] +} + + +request = function() + wrk.method = "POST" + wrk.body = geojsons[math.random(1, #geojsons)] + wrk.headers["Content-Type"] = "application/json" + wrk.headers["accept"] = "application/json" + wrk.headers["Authorization"] = "Bearer 1234" + return wrk.format() +end diff --git a/api/tests/benchmark_table_post.lua b/api/tests/benchmark_table_post.lua new file mode 100644 index 00000000..c71ab840 --- /dev/null +++ b/api/tests/benchmark_table_post.lua @@ -0,0 +1,28 @@ +-- example HTTP POST script which demonstrates setting the +-- HTTP method, body, and adding a header +-- command: +-- wrk -c 100 -t 10 -d 10s -s benchmark_post.lua 'http://localhost:8000/grid/table?level=4&limit=10&order_by=-population' + + +wrk.method = "POST" +wrk.body = [[ +[ + { + "filter_type": "categorical", + "column_name": "fire", + "operation": "in", + "value": [ + 1,2,3 + ] + }, + { + "filter_type": "numerical", + "column_name": "population", + "operation": "gt", + "value": 10000 + } +] +]] +wrk.headers["Content-Type"] = "application/json" +wrk.headers["accept"] = "application/json" +wrk.headers["Authorization"] = "Bearer 1234" diff --git a/api/tests/conftest.py b/api/tests/conftest.py new file mode 100644 index 00000000..8910dd20 --- /dev/null +++ b/api/tests/conftest.py @@ -0,0 +1,144 @@ +import json +import os +from pathlib import Path + +import numpy as np +import polars as pl +import pytest +import rasterio + +from app.config.config import get_settings + +TEST_ROOT = Path(__file__).resolve().parent + +# Testing settings env variables +os.environ["AUTH_TOKEN"] = "secret" +os.environ["TIFF_PATH"] = str(TEST_ROOT / "data") +os.environ["GRID_TILES_PATH"] = str(TEST_ROOT / "data" / "grid") + +FILES = ["raster.tif", "raster2.tif", "raster3.tif"] +HEADERS = {"Authorization": f"Bearer {get_settings().auth_token}"} + + +@pytest.fixture() +def geojson() -> str: + """This geojson contains the cell 895f4261e03ffff in `grid_dataset`""" + s = json.dumps( + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + [ + [-61.11, 8.66], + [-61.11, 8.50], + [-60.86, 8.50], + [-60.86, 8.66], + [-61.11, 8.66], + ] + ], + "type": "Polygon", + }, + } + ) + return s + + +@pytest.fixture() +def grid_dataset(setup_data_folder) -> str: + """Create an empty binary file to be used as grid dataset stub + for a level 0 tile. like: + data + └── grid + ├── 0 + │ └── 84395c9ffffffff.arrow + └── meta.json + """ + level = "4" + h3_index = "84395c9ffffffff" + + grid_dataset_path = Path(get_settings().grid_tiles_path) + level_path = grid_dataset_path / level + level_path.mkdir(parents=True) + tile_path = level_path / f"{h3_index}.arrow" + + df = pl.DataFrame( + { + "cell": [ + "895f4261e03ffff", + "865f00007ffffff", + "865f0000fffffff", + "865f00017ffffff", + "865f0001fffffff", + ], + "landcover": [1, 4, 3, 3, 4], + "population": [100, 200, 1, 900, 900], + } + ) + with open(grid_dataset_path / "meta.json", "w") as f: + f.write("{}") + + with open(tile_path, "wb") as f: + df.write_ipc(f) + + yield h3_index + + tile_path.unlink() + level_path.rmdir() + (grid_dataset_path / "meta.json").unlink() + grid_dataset_path.rmdir() + + +@pytest.fixture() +def setup_data_folder(): + os.mkdir(get_settings().tiff_path) + + yield + + os.rmdir(get_settings().tiff_path) + + +@pytest.fixture() +def tif_file(setup_data_folder): + """Create a test raster file. + + [[0, 1, 0], + [1, 9, 1], + [0, 1, 0]] + + The raster is a 3x3 grid with the upper left corner at 0E, 10N and 1 degree pixel size. + The bbox is BoundingBox(left=0.0, bottom=7.0, right=3.0, top=10.0) + """ + data = np.array([[0, 1, 0], [1, 9, 1], [0, 1, 0]]) + transform = rasterio.transform.from_origin(0, 10, 1, 1) + with rasterio.open( + f"{get_settings().tiff_path}/raster.tif", + "w", + driver="GTiff", + width=data.shape[1], + height=data.shape[0], + count=1, + dtype="uint8", + crs="+proj=latlong", + transform=transform, + ) as dst: + dst.write(data, 1) + + yield + + os.remove(f"{get_settings().tiff_path}/raster.tif") + + +@pytest.fixture() +def setup_empty_files(setup_data_folder): + test_tiff_path = get_settings().tiff_path + + for file in FILES: + # Create empty files writing nothing + with open(f"{test_tiff_path}/{file}", "w") as f: + f.write("") + + yield + + for file in FILES: + os.remove(f"{test_tiff_path}/{file}") diff --git a/api/tests/test_grid.py b/api/tests/test_grid.py new file mode 100644 index 00000000..b75c254c --- /dev/null +++ b/api/tests/test_grid.py @@ -0,0 +1,286 @@ +import json + +import polars as pl + +from app.models.grid import TableFilters +from tests.conftest import HEADERS +from tests.utils import test_client + + +def test_grid_tile(grid_dataset): + response = test_client.get( + f"/grid/tile/{grid_dataset}", params={"columns": ["landcover", "population"]}, headers=HEADERS + ) + + assert response.status_code == 200 + assert pl.read_ipc(response.read()).to_dict(as_series=False) == { + "cell": [ + "895f4261e03ffff", + "865f00007ffffff", + "865f0000fffffff", + "865f00017ffffff", + "865f0001fffffff", + ], + "landcover": [1, 4, 3, 3, 4], + "population": [100, 200, 1, 900, 900], + } + + +def test_grid_tile_empty_column_param(grid_dataset): + response = test_client.get(f"/grid/tile/{grid_dataset}", headers=HEADERS) + + assert response.status_code == 200 + assert pl.read_ipc(response.read()).to_dict(as_series=False) == { + "cell": [ + "895f4261e03ffff", + "865f00007ffffff", + "865f0000fffffff", + "865f00017ffffff", + "865f0001fffffff", + ], + } + + +def test_grid_tile_wrong_column(grid_dataset): + response = test_client.get(f"/grid/tile/{grid_dataset}", params={"columns": ["NOEXIST"]}, headers=HEADERS) + assert response.status_code == 400 + assert response.json() == {"detail": "One or more of the specified columns is not valid"} + + +def test_grid_tile_404(grid_dataset): + response = test_client.get("/grid/tile/8439181ffffffff", headers=HEADERS) + + assert response.status_code == 404 + + +def test_grid_tile_bad_index(grid_dataset): + response = test_client.get("/grid/tile/123", headers=HEADERS) + + assert response.status_code == 400 + assert response.json() == {"detail": "Tile index is not a valid H3 cell"} + + +def test_grid_metadata_fails_gracefully(grid_dataset): + res = test_client.get("/grid/meta", headers=HEADERS) + + assert res.status_code == 500 + assert res.json() == {"detail": "Metadata file is malformed. Please contact developer."} + + +def test_table_filter_numerical_eq_to_sql(): + tf = TableFilters.model_validate( + { + "filters": [{"filter_type": "numerical", "column_name": "foo", "operation": "eq", "value": 10}], + "limit": 10, + "order_by": ["baz"], + } + ) + query = tf.to_sql_query("table") + assert query.replace("\n", "") == 'SELECT * FROM "table" WHERE foo = 10.0 ORDER BY baz LIMIT 10' + + +def test_table_filter_numerical_gt_to_sql(): + tf = TableFilters.model_validate( + { + "filters": [{"filter_type": "numerical", "column_name": "foo", "operation": "gt", "value": 10}], + "limit": 10, + "order_by": ["baz"], + } + ) + query = tf.to_sql_query("table") + assert query.replace("\n", "") == 'SELECT * FROM "table" WHERE foo > 10.0 ORDER BY baz LIMIT 10' + + +def test_table_filter_numerical_lt_to_sql(): + tf = TableFilters.model_validate( + { + "filters": [{"filter_type": "numerical", "column_name": "foo", "operation": "lt", "value": 10}], + "limit": 10, + "order_by": ["baz"], + } + ) + query = tf.to_sql_query("table") + assert query.replace("\n", "") == 'SELECT * FROM "table" WHERE foo < 10.0 ORDER BY baz LIMIT 10' + + +def test_table_filter_numerical_gte_to_sql(): + tf = TableFilters.model_validate( + { + "filters": [{"filter_type": "numerical", "column_name": "foo", "operation": "gte", "value": 10}], + "limit": 10, + "order_by": ["baz"], + } + ) + query = tf.to_sql_query("table") + assert query.replace("\n", "") == 'SELECT * FROM "table" WHERE foo >= 10.0 ORDER BY baz LIMIT 10' + + +def test_table_filter_numerical_lte_to_sql(): + tf = TableFilters.model_validate( + { + "filters": [{"filter_type": "numerical", "column_name": "foo", "operation": "lte", "value": 10}], + "limit": 10, + "order_by": ["baz"], + } + ) + query = tf.to_sql_query("table") + assert query.replace("\n", "") == 'SELECT * FROM "table" WHERE foo <= 10.0 ORDER BY baz LIMIT 10' + + +def test_table_filter_numerical_not_eq_to_sql(): + tf = TableFilters.model_validate( + { + "filters": [{"filter_type": "numerical", "column_name": "foo", "operation": "not_eq", "value": 10}], + "limit": 10, + "order_by": ["baz"], + } + ) + query = tf.to_sql_query("table") + assert query.replace("\n", "") == 'SELECT * FROM "table" WHERE foo != 10.0 ORDER BY baz LIMIT 10' + + +def test_table_filter_categorical_in_to_sql(): + tf = TableFilters.model_validate( + { + "filters": [{"filter_type": "categorical", "column_name": "foo", "operation": "in", "value": [1, 2, 3]}], + "limit": 10, + "order_by": ["baz"], + } + ) + query = tf.to_sql_query("table") + assert query.replace("\n", "") == 'SELECT * FROM "table" WHERE foo IN (1, 2, 3) ORDER BY baz LIMIT 10' + + +def test_table_filter_categorical_not_in_to_sql(): + tf = TableFilters.model_validate( + { + "filters": [ + {"filter_type": "categorical", "column_name": "foo", "operation": "not_in", "value": [1, 2, 3]} + ], + "limit": 10, + "order_by": ["baz"], + } + ) + query = tf.to_sql_query("table") + assert query.replace("\n", "") == 'SELECT * FROM "table" WHERE (foo NOT IN (1, 2, 3)) ORDER BY baz LIMIT 10' + + +def test_table_filters_order_by_desc(): + tf = TableFilters.model_validate( + { + "filters": [{"filter_type": "numerical", "column_name": "foo", "operation": "gt", "value": 10}], + "limit": 100, + "order_by": ["-baz"], + } + ) + query = tf.to_sql_query("table") + assert query.replace("\n", "") == 'SELECT * FROM "table" WHERE foo > 10.0 ORDER BY baz DESC NULLS LAST LIMIT 100' + + +def test_table_filters_multiple_order_by(): + tf = TableFilters.model_validate( + { + "filters": [{"filter_type": "numerical", "column_name": "foo", "operation": "gt", "value": 10}], + "limit": 100, + "order_by": ["-baz", "foo", "-bar"], + } + ) + query = tf.to_sql_query("table") + assert ( + query.replace("\n", "") + == 'SELECT * FROM "table" WHERE foo > 10.0 ORDER BY baz DESC NULLS LAST, foo, bar DESC NULLS LAST LIMIT 100' + ) + + +def test_table_filters_multiple_filters(): + tf = TableFilters.model_validate( + { + "filters": [ + {"filter_type": "numerical", "column_name": "foo", "operation": "eq", "value": 10}, + {"filter_type": "categorical", "column_name": "bar", "operation": "in", "value": [1, 2, 3]}, + ], + "limit": 100, + "order_by": ["-baz", "foo"], + } + ) + query = tf.to_sql_query("table") + assert ( + query.replace("\n", "") + == 'SELECT * FROM "table" WHERE foo = 10.0 AND bar IN (1, 2, 3) ORDER BY baz DESC NULLS LAST, foo LIMIT 100' + ) + + +def test_grid_table(grid_dataset): + body = { + "filters": [ + {"filter_type": "numerical", "column_name": "population", "operation": "lte", "value": 200}, + {"filter_type": "numerical", "column_name": "population", "operation": "gt", "value": 1}, + ] + } + + response = test_client.post("/grid/table?level=4&order_by=-population", headers=HEADERS, content=json.dumps(body)) + assert response.status_code == 200 + assert json.loads(response.read()) == { + "table": [ + {"column": "cell", "values": ["865f00007ffffff", "895f4261e03ffff"]}, + {"column": "landcover", "values": [4, 1]}, + {"column": "population", "values": [200, 100]}, + ] + } + + +def test_grid_table_geojson(grid_dataset, geojson): + body = { + "filters": [ + {"filter_type": "numerical", "column_name": "population", "operation": "lte", "value": 200}, + {"filter_type": "numerical", "column_name": "population", "operation": "gt", "value": 1}, + ], + "geojson": json.loads(geojson), + } + response = test_client.post("/grid/table?level=4&order_by=-population", headers=HEADERS, content=json.dumps(body)) + assert response.status_code == 200 + assert json.loads(response.read()) == { + "table": [ + {"column": "cell", "values": ["895f4261e03ffff"]}, + {"column": "landcover", "values": [1]}, + {"column": "population", "values": [100]}, + ] + } + + +def test_grid_tile_post_geojson(grid_dataset, geojson): + response = test_client.post( + f"/grid/tile/{grid_dataset}", + params={"columns": ["landcover", "population"]}, + headers=HEADERS, + content=geojson, + ) + assert response.status_code == 200 + assert pl.read_ipc(response.read()).to_dict(as_series=False) == { + "cell": ["895f4261e03ffff"], + "landcover": [1], + "population": [100], + } + + +def test_grid_tile_post_geojson_404(grid_dataset, geojson): + response = test_client.post( + "/grid/tile/8439181ffffffff", + params={"columns": ["landcover", "population"]}, + headers=HEADERS, + content=geojson, + ) + + assert response.status_code == 404 + + +def test_grid_tile_post_wrong_column(grid_dataset, geojson): + response = test_client.post( + f"/grid/tile/{grid_dataset}", + params={"columns": ["I DO NOT EXIST"]}, + headers=HEADERS, + content=geojson, + ) + + assert response.status_code == 400 + assert response.json() == {"detail": "One or more of the specified columns is not valid"} diff --git a/api/tests/test_main.py b/api/tests/test_main.py index b349ca36..301be158 100644 --- a/api/tests/test_main.py +++ b/api/tests/test_main.py @@ -1,95 +1,10 @@ -import os - -import numpy as np -import pytest -import rasterio -from app.config.config import get_settings +from fastapi.routing import APIRoute +from tests.conftest import FILES, HEADERS from tests.utils import test_client -TOKEN = get_settings().auth_token -FILES = ["raster.tif", "raster2.tif", "raster3.tif"] -GEOJSON = { - "type": "FeatureCollection", - "features": [ - { - "type": "Feature", - "properties": {}, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [3.0, 7.0], - [3.0, 10.0], - [0.0, 10.0], - [0.0, 7.0], - [3.0, 7.0], - ], - ], - }, - } - ], -} - -HEADERS = {"Authorization": f"Bearer {TOKEN}"} - - -@pytest.fixture() -def setup_data_folder(): - os.mkdir(get_settings().tiff_path) - - yield - - os.rmdir(get_settings().tiff_path) - - -@pytest.fixture() -def tif_file(setup_data_folder): - """Create a test raster file. - - [[0, 1, 0], - [1, 9, 1], - [0, 1, 0]] - - The raster is a 3x3 grid with the upper left corner at 0E, 10N and 1 degree pixel size. - The bbox is BoundingBox(left=0.0, bottom=7.0, right=3.0, top=10.0) - """ - data = np.array([[0, 1, 0], [1, 9, 1], [0, 1, 0]]) - transform = rasterio.transform.from_origin(0, 10, 1, 1) - with rasterio.open( - f"{get_settings().tiff_path}/raster.tif", - "w", - driver="GTiff", - width=data.shape[1], - height=data.shape[0], - count=1, - dtype="uint8", - crs="+proj=latlong", - transform=transform, - ) as dst: - dst.write(data, 1) - - yield - - os.remove(f"{get_settings().tiff_path}/raster.tif") - - -@pytest.fixture() -def setup_empty_files(setup_data_folder): - test_tiff_path = get_settings().tiff_path - - for file in FILES: - # Create empty files writing nothing - with open(f"{test_tiff_path}/{file}", "w") as f: - f.write("") - - yield - - for file in FILES: - os.remove(f"{test_tiff_path}/{file}") - - -def test_no_token(): + +def test_no_token_is_unauthorized(): response = test_client.get("/tifs") response2 = test_client.post("/exact_zonal_stats") assert response.status_code == 401 @@ -98,6 +13,12 @@ def test_no_token(): assert response2.json() == {"detail": "Unauthorized"} +def test_wrong_token_is_unauthorized(): + response = test_client.get("/tifs", headers={"Authorization": "Bearer BAD-TOKKI-123"}) + assert response.status_code == 401 + assert response.json() == {"detail": "Unauthorized"} + + def test_health_is_public(): response = test_client.get("/health") assert response.status_code == 200 @@ -105,15 +26,9 @@ def test_health_is_public(): def test_options_request_is_allowed_with_correct_headers(): - headers = { - "Access-Control-Request-Method": "GET", - "Origin": "http://example.com" - } - response = test_client.options( - "/tifs", - headers=headers - ) - response2 = test_client.options('/exact_zonal_stats', headers=headers) + headers = {"Access-Control-Request-Method": "GET", "Origin": "http://example.com"} + response = test_client.options("/tifs", headers=headers) + response2 = test_client.options("/exact_zonal_stats", headers=headers) assert response.status_code == 200 assert response2.status_code == 200 assert "DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT" in response.headers["Access-Control-Allow-Methods"] @@ -137,54 +52,12 @@ def test_list_files(setup_empty_files): assert response.json() == {"files": FILES} -def test_wrong_file_name_raises_404(setup_data_folder): - response = test_client.post( - "/exact_zonal_stats", headers=HEADERS, params={"raster_filename": "wrong.tif"}, json=GEOJSON - ) - assert response.status_code == 404 - assert response.json() == {"detail": "Raster file wrong.tif does not exist."} - - -def test_no_geojson_raises_422(tif_file): - response = test_client.post("/exact_zonal_stats", headers=HEADERS, params={"raster_filename": "raster.tif"}) - assert response.status_code == 422 - assert response.json() == { - "detail": [ - { - "input": None, - "loc": ["body"], - "msg": "Field required", - "type": "missing", - "url": "https://errors.pydantic.dev/2.6/v/missing", - } - ] - } - - -def test_default_zonal_stats(tif_file): - response = test_client.post( - "/exact_zonal_stats", headers=HEADERS, params={"raster_filename": "raster.tif"}, json=GEOJSON - ) - assert response.status_code == 200 - assert response.json() == {"features": [{"properties": {"max": 9.0, "min": 0.0}, "type": "Feature"}]} - - -def test_custom_zonal_stats(tif_file): - response = test_client.post( - "/exact_zonal_stats", - headers=HEADERS, - params={"raster_filename": "raster.tif", "statistics": ["count"]}, - json=GEOJSON, - ) - assert response.status_code == 200 - assert response.json() == {"features": [{"properties": {"count": 9}, "type": "Feature"}]} +def test_all_api_routes_require_token(): + api_routes = {r.path: r.methods for r in test_client.app.routes if isinstance(r, APIRoute)} + # public endpoints that do not need auth: + del api_routes["/health"] -def test_nonexistent_statistic_raises_422(tif_file): - response = test_client.post( - "/exact_zonal_stats", - headers=HEADERS, - params={"raster_filename": "raster.tif", "statistics": ["nonexistent"]}, - json=GEOJSON, - ) - assert response.status_code == 422 + for route, method in api_routes.items(): + res = test_client.request(method.pop(), route) + assert res.status_code == 401 diff --git a/api/tests/test_zonal_stats.py b/api/tests/test_zonal_stats.py new file mode 100644 index 00000000..ef3078b1 --- /dev/null +++ b/api/tests/test_zonal_stats.py @@ -0,0 +1,76 @@ +from tests.conftest import HEADERS +from tests.utils import test_client + +GEOJSON = { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [3.0, 7.0], + [3.0, 10.0], + [0.0, 10.0], + [0.0, 7.0], + [3.0, 7.0], + ], + ], + }, + } + ], +} + + +def test_wrong_file_name_raises_404(setup_data_folder): + response = test_client.post( + "/exact_zonal_stats", headers=HEADERS, params={"raster_filename": "wrong.tif"}, json=GEOJSON + ) + assert response.status_code == 404 + assert response.json() == {"detail": "Raster file wrong.tif does not exist."} + + +def test_no_geojson_raises_422(tif_file): + response = test_client.post("/exact_zonal_stats", headers=HEADERS, params={"raster_filename": "raster.tif"}) + assert response.status_code == 422 + assert response.json() == { + "detail": [ + { + "input": None, + "loc": ["body"], + "msg": "Field required", + "type": "missing", + } + ] + } + + +def test_default_zonal_stats(tif_file): + response = test_client.post( + "/exact_zonal_stats", headers=HEADERS, params={"raster_filename": "raster.tif"}, json=GEOJSON + ) + assert response.status_code == 200 + assert response.json() == {"features": [{"properties": {"max": 9.0, "min": 0.0}, "type": "Feature"}]} + + +def test_custom_zonal_stats(tif_file): + response = test_client.post( + "/exact_zonal_stats", + headers=HEADERS, + params={"raster_filename": "raster.tif", "statistics": ["count"]}, + json=GEOJSON, + ) + assert response.status_code == 200 + assert response.json() == {"features": [{"properties": {"count": 9}, "type": "Feature"}]} + + +def test_nonexistent_statistic_raises_422(tif_file): + response = test_client.post( + "/exact_zonal_stats", + headers=HEADERS, + params={"raster_filename": "raster.tif", "statistics": ["nonexistent"]}, + json=GEOJSON, + ) + assert response.status_code == 422 diff --git a/api/tests/utils.py b/api/tests/utils.py index 31d21aff..8aa7242e 100644 --- a/api/tests/utils.py +++ b/api/tests/utils.py @@ -1,4 +1,5 @@ -from app.main import app from fastapi.testclient import TestClient +from app.main import app + test_client = TestClient(app) diff --git a/client/.env.test b/client/.env.test new file mode 100644 index 00000000..aec06ee0 --- /dev/null +++ b/client/.env.test @@ -0,0 +1,11 @@ +NEXT_PUBLIC_URL=http://localhost:$PORT +NEXT_PUBLIC_API_URL=https://api.amazonia360.dev-vizzuality.com/ +NEXT_PUBLIC_ARCGIS_API_KEY="" +NEXT_PUBLIC_API_KEY="" + +ARCGIS_CLIENT_ID="" +ARCGIS_CLIENT_SECRET="" + +BASIC_AUTH_USER=amazonia360 +BASIC_AUTH_PASSWORD=amazonia360 +# BASIC_AUTH_PASSWORD=Amazonia360$MVP/2024 diff --git a/client/.husky/pre-commit b/client/.husky/pre-commit index f13f6bc5..0cc5217a 100755 --- a/client/.husky/pre-commit +++ b/client/.husky/pre-commit @@ -3,7 +3,7 @@ # Client linting and type checking # cd ./client && pnpm types && pnpm lint --fix && pnpm check-types && git add src/types/generated/ -cd ./client && pnpm lint --fix && pnpm check-types +cd ./client && pnpm lint --fix && pnpm check-types && pnpm test # CMS config sync # cd .. && cd ./cms && pnpm config-sync export -y && git add config/sync \ No newline at end of file diff --git a/client/jest.config.ts b/client/jest.config.ts new file mode 100644 index 00000000..93f84e8a --- /dev/null +++ b/client/jest.config.ts @@ -0,0 +1,215 @@ +/** + * For a detailed explanation regarding each configuration property, visit: + * https://jestjs.io/docs/configuration + */ + +import nextJest from "next/jest.js"; + +import type { Config } from "jest"; + +const createJestConfig = nextJest({ + dir: "./", +}); + +const config: Config = { + // All imported modules in your tests should be mocked automatically + // automock: false, + + // Stop running tests after `n` failures + // bail: 0, + + // The directory where Jest should store its cached dependency information + // cacheDirectory: "/private/var/folders/qf/6j4jk_1956x50x2x438d5bxm0000gn/T/jest_dx", + + // Automatically clear mock calls, instances, contexts and results before every test + clearMocks: true, + + // Indicates whether the coverage information should be collected while executing the test + collectCoverage: true, + + // An array of glob patterns indicating a set of files for which coverage information should be collected + // collectCoverageFrom: undefined, + + // The directory where Jest should output its coverage files + coverageDirectory: "coverage", + + // An array of regexp pattern strings used to skip coverage collection + // coveragePathIgnorePatterns: [ + // "/node_modules/" + // ], + + // Indicates which provider should be used to instrument code for coverage + // coverageProvider: "babel", + + // A list of reporter names that Jest uses when writing coverage reports + // coverageReporters: [ + // "json", + // "text", + // "lcov", + // "clover" + // ], + + // An object that configures minimum threshold enforcement for coverage results + // coverageThreshold: undefined, + + // A path to a custom dependency extractor + // dependencyExtractor: undefined, + + // Make calling deprecated APIs throw helpful error messages + // errorOnDeprecated: false, + + // The default configuration for fake timers + // fakeTimers: { + // "enableGlobally": false + // }, + + // Force coverage collection from ignored files using an array of glob patterns + // forceCoverageMatch: [], + + // A path to a module which exports an async function that is triggered once before all test suites + // globalSetup: undefined, + + // A path to a module which exports an async function that is triggered once after all test suites + // globalTeardown: undefined, + + // A set of global variables that need to be available in all test environments + // globals: {}, + + // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. + // maxWorkers: "50%", + + // An array of directory names to be searched recursively up from the requiring module's location + // moduleDirectories: [ + // "node_modules" + // ], + + // An array of file extensions your modules use + // moduleFileExtensions: [ + // "js", + // "mjs", + // "cjs", + // "jsx", + // "ts", + // "tsx", + // "json", + // "node" + // ], + + // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module + moduleNameMapper: { + "^@/(.*)$": "/src/$1", + }, + + // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader + // modulePathIgnorePatterns: [], + + // Activates notifications for test results + // notify: false, + + // An enum that specifies notification mode. Requires { notify: true } + // notifyMode: "failure-change", + + // A preset that is used as a base for Jest's configuration + preset: "ts-jest", + + // Run tests from one or more projects + // projects: undefined, + + // Use this configuration option to add custom reporters to Jest + // reporters: undefined, + + // Automatically reset mock state before every test + // resetMocks: false, + + // Reset the module registry before running each individual test + // resetModules: false, + + // A path to a custom resolver + // resolver: undefined, + + // Automatically restore mock state and implementation before every test + // restoreMocks: false, + + // The root directory that Jest should scan for tests and modules within + // rootDir: undefined, + + // A list of paths to directories that Jest should use to search for files in + // roots: [ + // "" + // ], + + // Allows you to use a custom runner instead of Jest's default test runner + // runner: "jest-runner", + + // The paths to modules that run some code to configure or set up the testing environment before each test + // setupFiles: [], + + // A list of paths to modules that run some code to configure or set up the testing framework before each test + setupFilesAfterEnv: ["/src/jest.setup.ts"], + + // The number of seconds after which a test is considered as slow and reported as such in the results. + // slowTestThreshold: 5, + + // A list of paths to snapshot serializer modules Jest should use for snapshot testing + // snapshotSerializers: [], + + // The test environment that will be used for testing + testEnvironment: "jsdom", + + // Options that will be passed to the testEnvironment + // testEnvironmentOptions: {}, + + // Adds a location field to test results + // testLocationInResults: false, + + // The glob patterns Jest uses to detect test files + // testMatch: [ + // "**/__tests__/**/*.[jt]s?(x)", + // "**/?(*.)+(spec|test).[tj]s?(x)" + // ], + + // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped + // testPathIgnorePatterns: [ + // "/node_modules/" + // ], + + // The regexp pattern or array of patterns that Jest uses to detect test files + // testRegex: [], + + // This option allows the use of a custom results processor + // testResultsProcessor: undefined, + + // This option allows use of a custom test runner + // testRunner: "jest-circus/runner", + + // A map from regular expressions to paths to transformers + transform: { + // '^.+\\.[tj]sx?$' to process js/ts with `ts-jest` + // '^.+\\.m?[tj]sx?$' to process js/ts/mjs/mts with `ts-jest` + "^.+\\.m?[tj]sx?$": [ + "ts-jest", + { + // ts-jest configuration goes here + }, + ], + }, + + // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation + transformIgnorePatterns: [ + "node_modules/(?!@arcgis|@esri|@stencil|query-string)", + ], + + // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them + // unmockedModulePathPatterns: undefined, + + // Indicates whether each individual test should be reported during the run + // verbose: undefined, + + // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode + // watchPathIgnorePatterns: [], + + // Whether to use watchman for file crawling + // watchman: true, +}; + +export default createJestConfig(config); diff --git a/client/package.json b/client/package.json index afa4f56f..2f152cd1 100644 --- a/client/package.json +++ b/client/package.json @@ -9,7 +9,9 @@ "lint": "next lint", "check-types": "tsc", "types": "orval --config ./orval.config.ts", - "prepare": "cd .. && husky install client/.husky" + "prepare": "cd .. && husky install client/.husky", + "test": "jest", + "test:watch": "jest --watch" }, "dependencies": { "@arcgis/core": "^4.28.10", @@ -64,7 +66,10 @@ "zod": "^3.22.4" }, "devDependencies": { + "@testing-library/jest-dom": "^6.4.5", + "@testing-library/react": "^15.0.7", "@types/chroma-js": "^2.4.4", + "@types/jest": "^29.5.12", "@types/node": "^20", "@types/pluralize": "^0.0.33", "@types/react": "^18", @@ -78,12 +83,16 @@ "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.1.3", "husky": "^8.0.3", + "jest": "^29.7.0", + "jest-environment-jsdom": "^29.7.0", "orval": "^6.26.0", "postcss": "^8", "prettier": "^3.2.4", "prettier-plugin-tailwindcss": "^0.5.11", "tailwindcss": "^3.3.0", + "ts-jest": "^29.1.2", + "ts-node": "^10.9.2", "typescript": "^5" }, - "packageManager": "pnpm@9.1.1+sha256.9551e803dcb7a1839fdf5416153a844060c7bce013218ce823410532504ac10b" + "packageManager": "pnpm@9.4.0+sha256.b6fd0bfda555e7e584ad7e56b30c68b01d5a04f9ee93989f4b93ca8473c49c74" } diff --git a/client/pnpm-lock.yaml b/client/pnpm-lock.yaml index 03a91bda..637ed14e 100644 --- a/client/pnpm-lock.yaml +++ b/client/pnpm-lock.yaml @@ -13,58 +13,58 @@ importers: version: 4.28.10 '@radix-ui/react-alert-dialog': specifier: ^1.0.5 - version: 1.0.5(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + version: 1.0.5(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-checkbox': specifier: ^1.0.4 - version: 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + version: 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-collapsible': specifier: ^1.0.3 - version: 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + version: 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-dialog': specifier: ^1.0.5 - version: 1.0.5(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + version: 1.0.5(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-icons': specifier: ^1.3.0 version: 1.3.0(react@18.2.0) '@radix-ui/react-label': specifier: ^2.0.2 - version: 2.0.2(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + version: 2.0.2(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-popover': specifier: ^1.0.7 - version: 1.0.7(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + version: 1.0.7(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-radio-group': specifier: ^1.1.3 - version: 1.1.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + version: 1.1.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-scroll-area': specifier: ^1.0.5 - version: 1.0.5(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + version: 1.0.5(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-select': specifier: ^2.0.0 - version: 2.0.0(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + version: 2.0.0(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-slot': specifier: ^1.0.2 version: 1.0.2(@types/react@18.2.48)(react@18.2.0) '@radix-ui/react-tabs': specifier: 1.0.4 - version: 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + version: 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-tooltip': specifier: ^1.0.7 - version: 1.0.7(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + version: 1.0.7(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@t3-oss/env-nextjs': specifier: ^0.7.3 version: 0.7.3(typescript@5.3.3)(zod@3.22.4) '@tailwindcss/typography': specifier: ^0.5.13 - version: 0.5.13(tailwindcss@3.4.1) + version: 0.5.13(tailwindcss@3.4.1(ts-node@10.9.2(@types/node@20.11.5)(typescript@5.3.3))) '@tanstack/react-query': specifier: ^5.28.9 version: 5.28.9(react@18.2.0) '@tanstack/react-table': specifier: ^8.15.3 - version: 8.15.3(react-dom@18.2.0)(react@18.2.0) + version: 8.15.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@visx/annotation': specifier: ^3.3.0 - version: 3.3.0(react-dom@18.2.0)(react@18.2.0) + version: 3.3.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@visx/event': specifier: 3.3.0 version: 3.3.0 @@ -88,7 +88,7 @@ importers: version: 3.5.0(react@18.2.0) '@visx/tooltip': specifier: 3.3.0 - version: 3.3.0(react-dom@18.2.0)(react@18.2.0) + version: 3.3.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@visx/vendor': specifier: ^3.5.0 version: 3.5.0 @@ -106,7 +106,7 @@ importers: version: 2.1.0 cmdk: specifier: ^0.2.1 - version: 0.2.1(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + version: 0.2.1(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) html-react-parser: specifier: ^5.1.10 version: 5.1.10(@types/react@18.2.48)(react@18.2.0) @@ -118,10 +118,10 @@ importers: version: 0.371.0(react@18.2.0) next: specifier: 14.1.0 - version: 14.1.0(react-dom@18.2.0)(react@18.2.0) + version: 14.1.0(@babel/core@7.24.5)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) nuqs: specifier: ^1.17.0 - version: 1.17.0(next@14.1.0) + version: 1.17.0(next@14.1.0(@babel/core@7.24.5)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)) pluralize: specifier: ^8.0.0 version: 8.0.0 @@ -145,13 +145,13 @@ importers: version: 1.6.0(react@18.2.0) rooks: specifier: ^7.14.1 - version: 7.14.1(react-dom@18.2.0)(react@18.2.0) + version: 7.14.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) tailwind-merge: specifier: ^2.2.0 version: 2.2.0 tailwindcss-animate: specifier: ^1.0.7 - version: 1.0.7(tailwindcss@3.4.1) + version: 1.0.7(tailwindcss@3.4.1(ts-node@10.9.2(@types/node@20.11.5)(typescript@5.3.3))) ts-deepmerge: specifier: ^7.0.0 version: 7.0.0 @@ -159,9 +159,18 @@ importers: specifier: ^3.22.4 version: 3.22.4 devDependencies: + '@testing-library/jest-dom': + specifier: ^6.4.5 + version: 6.4.5(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.11.5)(ts-node@10.9.2(@types/node@20.11.5)(typescript@5.3.3))) + '@testing-library/react': + specifier: ^15.0.7 + version: 15.0.7(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@types/chroma-js': specifier: ^2.4.4 version: 2.4.4 + '@types/jest': + specifier: ^29.5.12 + version: 29.5.12 '@types/node': specifier: ^20 version: 20.11.5 @@ -179,7 +188,7 @@ importers: version: 1.4.5 '@typescript-eslint/eslint-plugin': specifier: ^6.19.0 - version: 6.19.0(@typescript-eslint/parser@6.19.0)(eslint@8.56.0)(typescript@5.3.3) + version: 6.19.0(@typescript-eslint/parser@6.19.0(eslint@8.56.0)(typescript@5.3.3))(eslint@8.56.0)(typescript@5.3.3) '@typescript-eslint/parser': specifier: ^6.19.0 version: 6.19.0(eslint@8.56.0)(typescript@5.3.3) @@ -197,10 +206,16 @@ importers: version: 9.1.0(eslint@8.56.0) eslint-plugin-prettier: specifier: ^5.1.3 - version: 5.1.3(eslint-config-prettier@9.1.0)(eslint@8.56.0)(prettier@3.2.4) + version: 5.1.3(eslint-config-prettier@9.1.0(eslint@8.56.0))(eslint@8.56.0)(prettier@3.2.4) husky: specifier: ^8.0.3 version: 8.0.3 + jest: + specifier: ^29.7.0 + version: 29.7.0(@types/node@20.11.5)(ts-node@10.9.2(@types/node@20.11.5)(typescript@5.3.3)) + jest-environment-jsdom: + specifier: ^29.7.0 + version: 29.7.0 orval: specifier: ^6.26.0 version: 6.26.0(openapi-types@12.1.3)(typescript@5.3.3) @@ -215,7 +230,13 @@ importers: version: 0.5.11(prettier@3.2.4) tailwindcss: specifier: ^3.3.0 - version: 3.4.1 + version: 3.4.1(ts-node@10.9.2(@types/node@20.11.5)(typescript@5.3.3)) + ts-jest: + specifier: ^29.1.2 + version: 29.1.2(@babel/core@7.24.5)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.5))(jest@29.7.0(@types/node@20.11.5)(ts-node@10.9.2(@types/node@20.11.5)(typescript@5.3.3)))(typescript@5.3.3) + ts-node: + specifier: ^10.9.2 + version: 10.9.2(@types/node@20.11.5)(typescript@5.3.3) typescript: specifier: ^5 version: 5.3.3 @@ -226,10 +247,17 @@ packages: resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} engines: {node: '>=0.10.0'} + '@adobe/css-tools@4.3.3': + resolution: {integrity: sha512-rE0Pygv0sEZ4vBWHlAgJLGDU7Pm8xoO6p3wsEceb7GYAjScrOHpEo8KK/eVkAcnSM+slAEtXjA2JpdjLp4fJQQ==} + '@alloc/quick-lru@5.2.0': resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + '@apidevtools/json-schema-ref-parser@9.0.6': resolution: {integrity: sha512-M3YgsLjI0lZxvrpeGVk9Ap032W6TPQkH6pRAZz81Ac3WUNF79VQooAFnp8umjvVzUmD93NkogxEwbSce7qMsUg==} @@ -251,6 +279,158 @@ packages: '@asyncapi/specs@4.3.1': resolution: {integrity: sha512-EfexhJu/lwF8OdQDm28NKLJHFkx0Gb6O+rcezhZYLPIoNYKXJMh2J1vFGpwmfAcTTh+ffK44Oc2Hs1Q4sLBp+A==} + '@babel/code-frame@7.24.2': + resolution: {integrity: sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.24.4': + resolution: {integrity: sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.24.5': + resolution: {integrity: sha512-tVQRucExLQ02Boi4vdPp49svNGcfL2GhdTCT9aldhXgCJVAI21EtRfBettiuLUwce/7r6bFdgs6JFkcdTiFttA==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.24.5': + resolution: {integrity: sha512-x32i4hEXvr+iI0NEoEfDKzlemF8AmtOP8CcrRaEcpzysWuoEb1KknpcvMsHKPONoKZiDuItklgWhB18xEhr9PA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.23.6': + resolution: {integrity: sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-environment-visitor@7.22.20': + resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-function-name@7.23.0': + resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-hoist-variables@7.22.5': + resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.24.3': + resolution: {integrity: sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.24.5': + resolution: {integrity: sha512-9GxeY8c2d2mdQUP1Dye0ks3VDyIMS98kt/llQ2nUId8IsWqTF0l1LkSX0/uP7l7MCDrzXS009Hyhe2gzTiGW8A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-plugin-utils@7.24.5': + resolution: {integrity: sha512-xjNLDopRzW2o6ba0gKbkZq5YWEBaK3PCyTOY1K2P/O07LGMhMqlMXPxwN4S5/RhWuCobT8z0jrlKGlYmeR1OhQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-simple-access@7.24.5': + resolution: {integrity: sha512-uH3Hmf5q5n7n8mz7arjUlDOCbttY/DW4DYhE6FUsjKJ/oYC1kQQUvwEQWxRwUpX9qQKRXeqLwWxrqilMrf32sQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-split-export-declaration@7.24.5': + resolution: {integrity: sha512-5CHncttXohrHk8GWOFCcCl4oRD9fKosWlIRgWm4ql9VYioKm52Mk2xsmoohvm7f3JoiLSM5ZgJuRaf5QZZYd3Q==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.24.1': + resolution: {integrity: sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.24.5': + resolution: {integrity: sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.23.5': + resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.24.5': + resolution: {integrity: sha512-CiQmBMMpMQHwM5m01YnrM6imUG1ebgYJ+fAIW4FZe6m4qHTPaRHti+R8cggAwkdz4oXhtO4/K9JWlh+8hIfR2Q==} + engines: {node: '>=6.9.0'} + + '@babel/highlight@7.24.5': + resolution: {integrity: sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.24.5': + resolution: {integrity: sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==} + 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-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.24.1': + resolution: {integrity: sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==} + 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-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.24.1': + resolution: {integrity: sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/runtime@7.23.8': resolution: {integrity: sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw==} engines: {node: '>=6.9.0'} @@ -259,6 +439,25 @@ packages: resolution: {integrity: sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==} engines: {node: '>=6.9.0'} + '@babel/template@7.24.0': + resolution: {integrity: sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.24.5': + resolution: {integrity: sha512-7aaBLeDQ4zYcUFDUD41lJc1fG8+5IU9DaNSJAgal866FGvmD5EbWQgnEC6kO1gGLsX0esNkfnJSndbTXA3r7UA==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.24.5': + resolution: {integrity: sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ==} + engines: {node: '>=6.9.0'} + + '@bcoe/v8-coverage@0.2.3': + resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + + '@cspotcode/source-map-support@0.8.1': + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + '@esbuild/aix-ppc64@0.19.12': resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==} engines: {node: '>=12'} @@ -471,10 +670,88 @@ packages: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} + '@istanbuljs/load-nyc-config@1.1.0': + resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} + engines: {node: '>=8'} + + '@istanbuljs/schema@0.1.3': + resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + 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.3': resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} engines: {node: '>=6.0.0'} + '@jridgewell/gen-mapping@0.3.5': + resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} + engines: {node: '>=6.0.0'} + '@jridgewell/resolve-uri@3.1.1': resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} engines: {node: '>=6.0.0'} @@ -483,12 +760,22 @@ packages: resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} engines: {node: '>=6.0.0'} + '@jridgewell/set-array@1.2.1': + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} + '@jridgewell/sourcemap-codec@1.4.15': resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} '@jridgewell/trace-mapping@0.3.21': resolution: {integrity: sha512-SRfKmRe1KvYnxjEMtxEr+J4HIeMX5YBg/qhRHpxEIGjhX1rshcHlnFUE9K0GazhVKWM7B+nARSkV8LuvJdJ5/g==} + '@jridgewell/trace-mapping@0.3.25': + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + + '@jridgewell/trace-mapping@0.3.9': + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + '@jsdevtools/ono@7.1.3': resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==} @@ -1102,6 +1389,15 @@ packages: '@rushstack/eslint-patch@1.7.2': resolution: {integrity: sha512-RbhOOTCNoCrbfkRyoXODZp75MlpiHMgbE5MEBZAnnnLyQNgrigEj4p0lzsMDyc1zVsJDLrivB58tgg3emX0eEA==} + '@sinclair/typebox@0.27.8': + resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + + '@sinonjs/commons@3.0.1': + resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} + + '@sinonjs/fake-timers@10.3.0': + resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} + '@stencil/core@2.22.3': resolution: {integrity: sha512-kmVA0M/HojwsfkeHsifvHVIYe4l5tin7J5+DLgtl8h6WWfiMClND5K3ifCXXI2ETDNKiEk21p6jql3Fx9o2rng==} engines: {node: '>=12.10.0', npm: '>=6.0.0'} @@ -1229,10 +1525,77 @@ packages: resolution: {integrity: sha512-wOgV0HfEvuMOv8RlqdR9MdNNqq0uyvQtP39QOvGlggHvIObOE4exS+D5LGO8LZ3LUXxId2IlUKcHDHaGujWhUg==} engines: {node: '>=12'} + '@testing-library/dom@10.1.0': + resolution: {integrity: sha512-wdsYKy5zupPyLCW2Je5DLHSxSfbIp6h80WoHOQc+RPtmPGA52O9x5MJEkv92Sjonpq+poOAtUKhh1kBGAXBrNA==} + engines: {node: '>=18'} + + '@testing-library/jest-dom@6.4.5': + resolution: {integrity: sha512-AguB9yvTXmCnySBP1lWjfNNUwpbElsaQ567lt2VdGqAdHtpieLgjmcVyv1q7PMIvLbgpDdkWV5Ydv3FEejyp2A==} + engines: {node: '>=14', npm: '>=6', yarn: '>=1'} + peerDependencies: + '@jest/globals': '>= 28' + '@types/bun': latest + '@types/jest': '>= 28' + jest: '>= 28' + vitest: '>= 0.32' + peerDependenciesMeta: + '@jest/globals': + optional: true + '@types/bun': + optional: true + '@types/jest': + optional: true + jest: + optional: true + vitest: + optional: true + + '@testing-library/react@15.0.7': + resolution: {integrity: sha512-cg0RvEdD1TIhhkm1IeYMQxrzy0MtUNfa3minv4MjbgcYzJAZ7yD0i0lwoPOTPr+INtiXFezt2o8xMSnyHhEn2Q==} + engines: {node: '>=18'} + peerDependencies: + '@types/react': ^18.0.0 + react: ^18.0.0 + react-dom: ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + '@tootallnate/once@2.0.0': + resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} + engines: {node: '>= 10'} + '@trysound/sax@0.2.0': resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} engines: {node: '>=10.13.0'} + '@tsconfig/node10@1.0.11': + resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} + + '@tsconfig/node12@1.0.11': + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + + '@tsconfig/node14@1.0.3': + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + + '@tsconfig/node16@1.0.4': + resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + + '@types/aria-query@5.0.4': + resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.6.8': + resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.20.5': + resolution: {integrity: sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==} + '@types/chroma-js@2.4.4': resolution: {integrity: sha512-/DTccpHTaKomqussrn+ciEvfW4k6NAHzNzs/sts1TCqg333qNxOhy8TNIoQCmbGG3Tl8KdEhkGAssb1n3mTXiQ==} @@ -1287,6 +1650,24 @@ packages: '@types/geojson@7946.0.14': resolution: {integrity: sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==} + '@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.12': + resolution: {integrity: sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==} + + '@types/jsdom@20.0.1': + resolution: {integrity: sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==} + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -1320,9 +1701,21 @@ packages: '@types/semver@7.5.6': resolution: {integrity: sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==} + '@types/stack-utils@2.0.3': + resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + + '@types/tough-cookie@4.0.5': + resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} + '@types/urijs@1.19.25': resolution: {integrity: sha512-XOfUup9r3Y06nFAZh3WvO0rBU4OtlfPB/vgxpjg+NRdGU6CN6djdc6OEiH+PcqHCY6eFLo9Ista73uarf4gnBg==} + '@types/yargs-parser@21.0.3': + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} + + '@types/yargs@17.0.32': + resolution: {integrity: sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==} + '@typescript-eslint/eslint-plugin@6.19.0': resolution: {integrity: sha512-DUCUkQNklCQYnrBSSikjVChdc84/vMPDQSgJTHBZ64G9bA9w0Crc0rd2diujKbTdp6w2J47qkeHQLoi0rpLCdg==} engines: {node: ^16.0.0 || >=18.0.0} @@ -1455,20 +1848,35 @@ packages: resolution: {integrity: sha512-SWAK+hLYKRHswhakNUirPYrdsflSFOxykUckfbWDcPvP8tjLuV5EWyd3GHV0hVaJLDps40jJnv8yQVDbWnQDfg==} engines: {bun: '>=0.7.0', deno: '>=1.0.0', node: '>=16.5.0'} + abab@2.0.6: + resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} + deprecated: Use your platform's native atob() and btoa() methods instead + abort-controller@3.0.0: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} engines: {node: '>=6.5'} + acorn-globals@7.0.1: + resolution: {integrity: sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==} + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + acorn-walk@8.3.2: + resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==} + engines: {node: '>=0.4.0'} + acorn@8.11.3: resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} engines: {node: '>=0.4.0'} hasBin: true + agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + ajv-draft-04@1.0.0: resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==} peerDependencies: @@ -1500,6 +1908,10 @@ packages: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} + 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'} @@ -1508,10 +1920,18 @@ packages: resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} engines: {node: '>=12'} + ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + ansi-styles@6.2.1: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} engines: {node: '>=12'} @@ -1523,6 +1943,9 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} + arg@4.1.3: + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + arg@5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} @@ -1608,6 +2031,31 @@ packages: axobject-query@3.2.1: resolution: {integrity: sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==} + 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.0.1: + resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} + peerDependencies: + '@babel/core': ^7.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@0.4.2: resolution: {integrity: sha512-STw03mQKnGUYtoNjmowo4F2cRmIIxYEGiMsjjwla/u5P1lxadj/05WkNaFjNiKTgJkj8KiXbgAiRTmcQRwQNtg==} @@ -1636,6 +2084,16 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + bs-logger@0.2.6: + resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} + engines: {node: '>= 6'} + + 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==} + busboy@1.6.0: resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} engines: {node: '>=10.16.0'} @@ -1659,16 +2117,36 @@ packages: resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} 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.30001579: resolution: {integrity: sha512-u5AUVkixruKHJjw/pj9wISlcMpgFWzSrczLZbrqBSxukQixmg0SJ5sZTpvaFvxU0HoQKd4yoyAogyrAz9pzJnA==} caniuse-lite@1.0.30001589: resolution: {integrity: sha512-vNQWS6kI+q6sBlHbh71IIeC+sRwK2N3EDySc/updIGhIee2x5z00J4c1242/5/d6EpEMdOnk/m+6tuk4/tcsqg==} + chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + + chalk@3.0.0: + resolution: {integrity: sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==} + engines: {node: '>=8'} + 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'} + chokidar@3.5.3: resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} engines: {node: '>= 8.10.0'} @@ -1676,6 +2154,13 @@ packages: chroma-js@2.4.2: resolution: {integrity: sha512-U9eDw6+wt7V8z5NncY2jJfZa+hUH8XEj8FQHgFJTrUFnJfXYf4Ml4adI2vXZOjqRDpFWtYVWypDfZwnJ+HIR4A==} + ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + + cjs-module-lexer@1.3.1: + resolution: {integrity: sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q==} + class-variance-authority@0.7.0: resolution: {integrity: sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==} @@ -1703,10 +2188,23 @@ packages: react: ^18.0.0 react-dom: ^18.0.0 + co@4.6.0: + resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} + engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + + collect-v8-coverage@1.0.2: + resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} + + color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} + color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} @@ -1741,6 +2239,17 @@ packages: 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 + + create-require@1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + cross-spawn@7.0.3: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} @@ -1760,6 +2269,9 @@ packages: resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} engines: {node: '>= 6'} + css.escape@1.5.1: + resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==} + cssesc@3.0.0: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} engines: {node: '>=4'} @@ -1772,6 +2284,16 @@ packages: resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + cssom@0.3.8: + resolution: {integrity: sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==} + + cssom@0.5.0: + resolution: {integrity: sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==} + + cssstyle@2.3.0: + resolution: {integrity: sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==} + engines: {node: '>=8'} + csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} @@ -1823,6 +2345,10 @@ packages: damerau-levenshtein@1.0.8: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} + data-urls@3.0.2: + resolution: {integrity: sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==} + engines: {node: '>=12'} + data-view-buffer@1.0.1: resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==} engines: {node: '>= 0.4'} @@ -1858,13 +2384,28 @@ packages: supports-color: optional: true + decimal.js@10.4.3: + resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==} + decode-uri-component@0.4.1: resolution: {integrity: sha512-+8VxcR21HhTy8nOt6jf20w0c9CADrw1O8d+VZ/YzzCt4bJ3uBjw+D1q2osAB8RnpwwaeYBxy0HyKQxD5JBMuuQ==} engines: {node: '>=14.16'} + dedent@1.5.3: + resolution: {integrity: sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==} + 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'} + define-data-property@1.1.4: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} @@ -1888,12 +2429,24 @@ packages: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} + detect-newline@3.1.0: + resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} + engines: {node: '>=8'} + detect-node-es@1.1.0: resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} didyoumean@1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + diff-sequences@29.6.3: + resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + diff@4.0.2: + resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + engines: {node: '>=0.3.1'} + dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} @@ -1909,12 +2462,23 @@ packages: resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} engines: {node: '>=6.0.0'} + dom-accessibility-api@0.5.16: + resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} + + dom-accessibility-api@0.6.3: + resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==} + dom-serializer@2.0.0: resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} domelementtype@2.3.0: resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + domexception@4.0.0: + resolution: {integrity: sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==} + engines: {node: '>=12'} + deprecated: Use your platform's native DOMException instead + domhandler@5.0.3: resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} engines: {node: '>= 4'} @@ -1928,6 +2492,10 @@ packages: electron-to-chromium@1.4.637: resolution: {integrity: sha512-G7j3UCOukFtxVO1vWrPQUoDk3kL70mtvjc/DC/k2o7lE0wAdq+Vwp1ipagOow+BH0uVztFysLWbkM/RTIrbK3w==} + 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==} @@ -1946,6 +2514,9 @@ packages: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} + error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + es-abstract@1.22.4: resolution: {integrity: sha512-vZYJlk2u6qHYxBOTjAeg7qUxHdNfih64Uu2J8QqWgXZ2cri0ZpJAkzDUK/q593+mvKwlxyaxr6F1Q+3LKoQRgg==} engines: {node: '>= 0.4'} @@ -2000,10 +2571,23 @@ packages: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} engines: {node: '>=6'} + escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + + 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'} + escodegen@2.1.0: + resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} + engines: {node: '>=6.0'} + hasBin: true + eslint-config-next@14.1.0: resolution: {integrity: sha512-SBX2ed7DoRFXC6CQSLc/SbLY9Ut6HxNB2wPTcoIWjUMd7aF7O/SIE7111L8FdZ9TXsNV4pulUDnfthpyPtbFUg==} peerDependencies: @@ -2138,6 +2722,14 @@ packages: 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==} @@ -2163,6 +2755,9 @@ packages: fastq@1.16.0: resolution: {integrity: sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==} + fb-watchman@2.0.2: + resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + file-entry-cache@6.0.1: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} @@ -2175,6 +2770,10 @@ packages: resolution: {integrity: sha512-qWeTREPoT7I0bifpPUXtxkZJ1XJzxWtfoWWkdVGqa+eCr3SHW/Ocp89o8vLvbUuQnadybJpjOKu4V+RwO6sGng==} engines: {node: '>=14.16'} + 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'} @@ -2234,6 +2833,10 @@ packages: functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} @@ -2246,6 +2849,10 @@ packages: resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} engines: {node: '>=6'} + 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'} @@ -2273,6 +2880,10 @@ packages: glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + globals@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + globals@13.24.0: resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} engines: {node: '>=8'} @@ -2297,6 +2908,10 @@ packages: has-bigints@1.0.2: resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} + has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} @@ -2331,6 +2946,13 @@ packages: html-dom-parser@5.0.8: resolution: {integrity: sha512-vuWiX9EXgu8CJ5m9EP5c7bvBmNSuQVnrY8tl0z0ZX96Uth1IPlYH/8W8VZ/hBajFf18EN+j2pukbCNd01HEd1w==} + html-encoding-sniffer@3.0.0: + resolution: {integrity: sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==} + engines: {node: '>=12'} + + html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + html-react-parser@5.1.10: resolution: {integrity: sha512-gV22PvLij4wdEdtrZbGVC7Zy2OVWnQ0bYhX63S196ZRSx4+K0TuutCreHSXr+saUia8KeKB+2TYziVfijpH4Tw==} peerDependencies: @@ -2343,9 +2965,17 @@ packages: htmlparser2@9.1.0: resolution: {integrity: sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==} + http-proxy-agent@5.0.0: + resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} + engines: {node: '>= 6'} + http2-client@1.3.5: resolution: {integrity: sha512-EC2utToWl4RKfs5zd36Mxq7nzHHBuomZboI0yYL6Y0RmBgT7Sgkq4rQ0ezFTYoIsSs7Tm9SJe+o2FcAg6GBhGA==} + https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + human-signals@2.1.0: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} @@ -2355,6 +2985,10 @@ packages: engines: {node: '>=14'} hasBin: true + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + ignore@5.3.0: resolution: {integrity: sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==} engines: {node: '>= 4'} @@ -2366,10 +3000,19 @@ packages: resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} engines: {node: '>=6'} + import-local@3.1.0: + resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==} + engines: {node: '>=8'} + hasBin: true + imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} + indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} @@ -2394,6 +3037,9 @@ packages: resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} engines: {node: '>= 0.4'} + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + is-arrayish@0.3.2: resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} @@ -2438,6 +3084,10 @@ packages: 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-generator-function@1.0.10: resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} engines: {node: '>= 0.4'} @@ -2465,6 +3115,9 @@ packages: resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} engines: {node: '>=8'} + is-potential-custom-element-name@1.0.1: + resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + is-regex@1.1.4: resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} engines: {node: '>= 0.4'} @@ -2507,6 +3160,30 @@ packages: 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.2: + resolution: {integrity: sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw==} + 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.1.7: + resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==} + engines: {node: '>=8'} + iterator.prototype@1.1.2: resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==} @@ -2514,6 +3191,144 @@ packages: resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} engines: {node: '>=14'} + 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-jsdom@29.7.0: + resolution: {integrity: sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + canvas: ^2.5.0 + peerDependenciesMeta: + canvas: + optional: true + + 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 + jiti@1.21.0: resolution: {integrity: sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==} hasBin: true @@ -2541,13 +3356,30 @@ packages: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true + jsdom@20.0.3: + resolution: {integrity: sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==} + engines: {node: '>=14'} + peerDependencies: + canvas: ^2.5.0 + peerDependenciesMeta: + canvas: + optional: true + jsep@1.3.8: resolution: {integrity: sha512-qofGylTGgYj9gZFsHuyWAN4jr35eJ66qJCK4eKDnldohuUoQFbU3iZn2zjvEbd9wOAhP9Wx5DsAAduTyE1PSWQ==} engines: {node: '>= 10.16.0'} + jsesc@2.5.2: + resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} + engines: {node: '>=4'} + hasBin: true + json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} @@ -2561,6 +3393,11 @@ packages: resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} hasBin: true + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + jsonc-parser@2.2.1: resolution: {integrity: sha512-o6/yDBYccGvTz1+QFevz6l6OBZ2+fMVu2JZ9CIhzsYRX4mjaK5IyX9eldUdCmga16zlgQxyrj5pt9kzuj2C02w==} @@ -2586,6 +3423,10 @@ packages: keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + language-subtag-registry@0.3.22: resolution: {integrity: sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==} @@ -2612,6 +3453,10 @@ packages: 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'} @@ -2634,6 +3479,9 @@ packages: lodash.isplainobject@4.0.6: resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + lodash.memoize@4.1.2: + resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} + lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} @@ -2673,6 +3521,9 @@ packages: resolution: {integrity: sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==} engines: {node: 14 || >=16.14} + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + lru-cache@6.0.0: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} @@ -2686,6 +3537,20 @@ packages: resolution: {integrity: sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==} engines: {node: '>=12'} + lz-string@1.5.0: + resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} + hasBin: true + + make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + + make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + + makeerror@1.0.12: + resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + math-expression-evaluator@1.4.0: resolution: {integrity: sha512-4vRUvPyxdO8cWULGTh9dZWL2tZK6LDBvj+OGHBER7poH9Qdt7kXEoj20wiz4lQUbUXQZFjPbe5mVDo9nutizCw==} @@ -2718,6 +3583,10 @@ packages: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} + min-indent@1.0.1: + resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} + engines: {node: '>=4'} + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -2788,6 +3657,9 @@ packages: encoding: optional: true + node-int64@0.4.0: + resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} + node-readfiles@0.2.0: resolution: {integrity: sha512-SU00ZarexNlE4Rjdm83vglt5Y9yiQ+XI1XpflWlb7q7UTN1JUItm69xMeiQCTxtTfnzt+83T8Cx+vI2ED++VDA==} @@ -2814,6 +3686,9 @@ packages: peerDependencies: next: '>=13.4 <14.0.2 || ^14.0.3' + nwsapi@2.2.10: + resolution: {integrity: sha512-QK0sRs7MKv0tKe1+5uZIQk/C8XGza4DAnztJG8iD+TpJIORARrCxczA738awHrZoHeTjSSoHqao2teO0dC/gFQ==} + oas-kit-common@1.0.8: resolution: {integrity: sha512-pJTS2+T0oGIwgjGpw7sIRU8RQMcUoKCDWFLdBqKB2BNmGpbBMH2sdqAaOXUg8OzonZHU0L7vfJu1mJFEiYDWOQ==} @@ -2888,18 +3763,37 @@ packages: resolution: {integrity: sha512-pgUNgXYSjnLz6uF1LOoeoIlI39mwq//ktx1FDUoRJ+ZspouLTKM4GSNmoMjEdn6T/CvPmkKQffTGo5rIUYPcmA==} hasBin: true + 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'} + parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + + parse5@7.1.2: + resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -2941,6 +3835,10 @@ packages: resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} engines: {node: '>= 6'} + pkg-dir@4.2.0: + resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} + engines: {node: '>=8'} + pluralize@8.0.0: resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} engines: {node: '>=4'} @@ -3064,20 +3962,41 @@ packages: engines: {node: '>=14'} hasBin: true + pretty-format@27.5.1: + resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + 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'} + prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + psl@1.9.0: + resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + pure-rand@6.1.0: + resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + query-string@9.0.0: resolution: {integrity: sha512-4EWwcRGsO2H+yzq6ddHcVqkCQ2EFUSfDMEjF8ryp8ReymyZhIuaFRGLomeOQLkrzacMHoyky2HW0Qe30UbzkKw==} engines: {node: '>=18'} + querystringify@2.2.0: + resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} + queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -3097,6 +4016,12 @@ packages: react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + react-is@17.0.2: + resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + react-property@2.0.2: resolution: {integrity: sha512-+PbtI3VuDV0l6CleQMsx2gtK0JZbZKbpdu5ynr+lbsuvtmgbNcS3VM0tuY2QjFNOcWxvXeHjDpy42RO+4U2rug==} @@ -3168,6 +4093,10 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} + redent@3.0.0: + resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} + engines: {node: '>=8'} + reduce-css-calc@1.3.0: resolution: {integrity: sha512-0dVfwYVOlf/LBA2ec4OwQ6p3X9mYxn/wOl2xTcLwjnPYrkgEfPx3VI4eGCH3rQLlPISG5v9I9bkZosKsNRTRKA==} @@ -3196,13 +4125,28 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} + requires-port@1.0.0: + resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} + + resolve-cwd@3.0.0: + resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} + engines: {node: '>=8'} + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + resolve.exports@2.0.2: + resolution: {integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==} + engines: {node: '>=10'} + resolve@1.22.8: resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true @@ -3247,6 +4191,13 @@ packages: safe-stable-stringify@1.1.1: resolution: {integrity: sha512-ERq4hUjKDbJfE4+XtZLFPCDi8Vb1JqaxAPTxWFLBx8XcAlf9Bda/ZJdVezs/NAfsMQScyIlUMx+Yeu7P7rx5jw==} + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + saxes@6.0.0: + resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} + engines: {node: '>=v12.22.7'} + scheduler@0.23.0: resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==} @@ -3311,6 +4262,9 @@ packages: simple-swizzle@0.2.2: resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} @@ -3325,6 +4279,13 @@ packages: resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} 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'} + split-on-first@3.0.0: resolution: {integrity: sha512-qxQJTx2ryR0Dw0ITYyekNQWpz6f8dGd7vffGNflQQ3Iqj9NJ6qiZ7ELpZsJ/QBhIVAiDfXdag3+Gp8RvWa62AA==} engines: {node: '>=12'} @@ -3332,6 +4293,10 @@ packages: sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + streamsearch@1.1.0: resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} engines: {node: '>=10.0.0'} @@ -3340,6 +4305,10 @@ packages: resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} engines: {node: '>=0.6.19'} + 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'} @@ -3384,10 +4353,18 @@ packages: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} + 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-indent@3.0.0: + resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} + engines: {node: '>=8'} + strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -3416,10 +4393,18 @@ packages: engines: {node: '>=16 || 14 >=14.17'} hasBin: true + supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} + 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'} @@ -3436,6 +4421,9 @@ packages: resolution: {integrity: sha512-upi/0ZGkYgEcLeGieoz8gT74oWHA0E7JivX7aN9mAf+Tc7BQoRBvnIGHoPDw+f9TXTW4s6kGYCZJtauP6OYp7g==} hasBin: true + symbol-tree@3.2.4: + resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + synckit@0.8.8: resolution: {integrity: sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==} engines: {node: ^14.18.0 || >=16.0.0} @@ -3460,6 +4448,10 @@ packages: resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} engines: {node: '>=6'} + test-exclude@6.0.0: + resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} + engines: {node: '>=8'} + text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} @@ -3474,13 +4466,28 @@ packages: resolution: {integrity: sha512-t7E/9sPfCU0m0ZbS7Cqw52D6CB/UyeaiIBmyJCokI1SyOyOgA/ESiQ/fbreeFaUG9QSenGlZSSk/7rEbkipbOA==} hasBin: true + tmpl@1.0.5: + resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} + + to-fast-properties@2.0.0: + resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} + engines: {node: '>=4'} + to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + tough-cookie@4.1.4: + resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==} + engines: {node: '>=6'} + tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + tr46@3.0.0: + resolution: {integrity: sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==} + engines: {node: '>=12'} + ts-api-utils@1.0.3: resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==} engines: {node: '>=16.13.0'} @@ -3494,6 +4501,41 @@ packages: ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + ts-jest@29.1.2: + resolution: {integrity: sha512-br6GJoH/WUX4pu7FbZXuWGKGNDuU7b8Uj77g/Sp7puZV6EXzuByl6JrECvm0MzVzSTkSHWTihsXt+5XYER5b+g==} + engines: {node: ^16.10.0 || ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@babel/core': '>=7.0.0-beta.0 <8' + '@jest/types': ^29.0.0 + babel-jest: ^29.0.0 + esbuild: '*' + jest: ^29.0.0 + typescript: '>=4.3 <6' + peerDependenciesMeta: + '@babel/core': + optional: true + '@jest/types': + optional: true + babel-jest: + optional: true + esbuild: + optional: true + + ts-node@10.9.2: + resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + tsconfck@2.1.2: resolution: {integrity: sha512-ghqN1b0puy3MhhviwO2kGF8SeMDNhEbnKxjK7h6+fvY9JAxqvXi8y5NAHSQv687OVboS2uZIByzGd45/YxrRHg==} engines: {node: ^14.13.1 || ^16 || >=18} @@ -3517,10 +4559,18 @@ packages: 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.20.2: resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} engines: {node: '>=10'} + type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + typed-array-buffer@1.0.2: resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} engines: {node: '>= 0.4'} @@ -3552,6 +4602,10 @@ packages: undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + universalify@0.2.0: + resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} + engines: {node: '>= 4.0.0'} + universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} @@ -3568,6 +4622,9 @@ packages: urijs@1.19.11: resolution: {integrity: sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==} + url-parse@1.5.10: + resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} + use-callback-ref@1.3.1: resolution: {integrity: sha512-Lg4Vx1XZQauB42Hw3kK7JM6yjVjgFmFC5/Ab797s79aARomD2nEErc4mCgM8EZrARLmmbWpi5DGCadmK50DcAQ==} engines: {node: '>=10'} @@ -3600,13 +4657,43 @@ packages: resolution: {integrity: sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==} engines: {node: '>= 4'} + v8-compile-cache-lib@3.0.1: + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + + v8-to-istanbul@9.2.0: + resolution: {integrity: sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==} + engines: {node: '>=10.12.0'} + validator@13.11.0: resolution: {integrity: sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==} engines: {node: '>= 0.10'} + w3c-xmlserializer@4.0.0: + resolution: {integrity: sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==} + engines: {node: '>=14'} + + walker@1.0.8: + resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} + webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + webidl-conversions@7.0.0: + resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} + engines: {node: '>=12'} + + whatwg-encoding@2.0.0: + resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==} + engines: {node: '>=12'} + + whatwg-mimetype@3.0.0: + resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} + engines: {node: '>=12'} + + whatwg-url@11.0.0: + resolution: {integrity: sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==} + engines: {node: '>=12'} + whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} @@ -3647,6 +4734,29 @@ packages: 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} + + ws@8.17.0: + resolution: {integrity: sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + xml-name-validator@4.0.0: + resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} + engines: {node: '>=12'} + + xmlchars@2.2.0: + resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + xss@1.0.13: resolution: {integrity: sha512-clu7dxTm1e8Mo5fz3n/oW3UCXBfV89xZ72jM8yzo1vR/pIS0w3sgB3XV2H8Vm6zfGnHL0FzvLJPJEBhd86/z4Q==} engines: {node: '>= 0.10.0'} @@ -3656,6 +4766,9 @@ packages: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} @@ -3675,6 +4788,10 @@ packages: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} + yn@3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -3686,8 +4803,15 @@ snapshots: '@aashutoshrathi/word-wrap@1.2.6': {} + '@adobe/css-tools@4.3.3': {} + '@alloc/quick-lru@5.2.0': {} + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + '@apidevtools/json-schema-ref-parser@9.0.6': dependencies: '@jsdevtools/ono': 7.1.3 @@ -3724,55 +4848,259 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 - '@babel/runtime@7.23.8': + '@babel/code-frame@7.24.2': dependencies: - regenerator-runtime: 0.14.1 + '@babel/highlight': 7.24.5 + picocolors: 1.0.0 - '@babel/runtime@7.23.9': - dependencies: - regenerator-runtime: 0.14.1 + '@babel/compat-data@7.24.4': {} + + '@babel/core@7.24.5': + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.24.2 + '@babel/generator': 7.24.5 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-module-transforms': 7.24.5(@babel/core@7.24.5) + '@babel/helpers': 7.24.5 + '@babel/parser': 7.24.5 + '@babel/template': 7.24.0 + '@babel/traverse': 7.24.5 + '@babel/types': 7.24.5 + convert-source-map: 2.0.0 + debug: 4.3.4 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color - '@esbuild/aix-ppc64@0.19.12': - optional: true + '@babel/generator@7.24.5': + dependencies: + '@babel/types': 7.24.5 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 2.5.2 - '@esbuild/android-arm64@0.19.12': - optional: true + '@babel/helper-compilation-targets@7.23.6': + dependencies: + '@babel/compat-data': 7.24.4 + '@babel/helper-validator-option': 7.23.5 + browserslist: 4.22.2 + lru-cache: 5.1.1 + semver: 6.3.1 - '@esbuild/android-arm@0.19.12': - optional: true + '@babel/helper-environment-visitor@7.22.20': {} - '@esbuild/android-x64@0.19.12': - optional: true + '@babel/helper-function-name@7.23.0': + dependencies: + '@babel/template': 7.24.0 + '@babel/types': 7.24.5 - '@esbuild/darwin-arm64@0.19.12': - optional: true + '@babel/helper-hoist-variables@7.22.5': + dependencies: + '@babel/types': 7.24.5 - '@esbuild/darwin-x64@0.19.12': - optional: true + '@babel/helper-module-imports@7.24.3': + dependencies: + '@babel/types': 7.24.5 - '@esbuild/freebsd-arm64@0.19.12': - optional: true + '@babel/helper-module-transforms@7.24.5(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-module-imports': 7.24.3 + '@babel/helper-simple-access': 7.24.5 + '@babel/helper-split-export-declaration': 7.24.5 + '@babel/helper-validator-identifier': 7.24.5 - '@esbuild/freebsd-x64@0.19.12': - optional: true + '@babel/helper-plugin-utils@7.24.5': {} - '@esbuild/linux-arm64@0.19.12': - optional: true + '@babel/helper-simple-access@7.24.5': + dependencies: + '@babel/types': 7.24.5 - '@esbuild/linux-arm@0.19.12': - optional: true + '@babel/helper-split-export-declaration@7.24.5': + dependencies: + '@babel/types': 7.24.5 - '@esbuild/linux-ia32@0.19.12': - optional: true + '@babel/helper-string-parser@7.24.1': {} - '@esbuild/linux-loong64@0.19.12': - optional: true + '@babel/helper-validator-identifier@7.24.5': {} - '@esbuild/linux-mips64el@0.19.12': - optional: true + '@babel/helper-validator-option@7.23.5': {} - '@esbuild/linux-ppc64@0.19.12': - optional: true + '@babel/helpers@7.24.5': + dependencies: + '@babel/template': 7.24.0 + '@babel/traverse': 7.24.5 + '@babel/types': 7.24.5 + transitivePeerDependencies: + - supports-color + + '@babel/highlight@7.24.5': + dependencies: + '@babel/helper-validator-identifier': 7.24.5 + chalk: 2.4.2 + js-tokens: 4.0.0 + picocolors: 1.0.0 + + '@babel/parser@7.24.5': + dependencies: + '@babel/types': 7.24.5 + + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-syntax-jsx@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-syntax-typescript@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/runtime@7.23.8': + dependencies: + regenerator-runtime: 0.14.1 + + '@babel/runtime@7.23.9': + dependencies: + regenerator-runtime: 0.14.1 + + '@babel/template@7.24.0': + dependencies: + '@babel/code-frame': 7.24.2 + '@babel/parser': 7.24.5 + '@babel/types': 7.24.5 + + '@babel/traverse@7.24.5': + dependencies: + '@babel/code-frame': 7.24.2 + '@babel/generator': 7.24.5 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-split-export-declaration': 7.24.5 + '@babel/parser': 7.24.5 + '@babel/types': 7.24.5 + debug: 4.3.4 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.24.5': + dependencies: + '@babel/helper-string-parser': 7.24.1 + '@babel/helper-validator-identifier': 7.24.5 + to-fast-properties: 2.0.0 + + '@bcoe/v8-coverage@0.2.3': {} + + '@cspotcode/source-map-support@0.8.1': + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + + '@esbuild/aix-ppc64@0.19.12': + optional: true + + '@esbuild/android-arm64@0.19.12': + optional: true + + '@esbuild/android-arm@0.19.12': + optional: true + + '@esbuild/android-x64@0.19.12': + optional: true + + '@esbuild/darwin-arm64@0.19.12': + optional: true + + '@esbuild/darwin-x64@0.19.12': + optional: true + + '@esbuild/freebsd-arm64@0.19.12': + optional: true + + '@esbuild/freebsd-x64@0.19.12': + optional: true + + '@esbuild/linux-arm64@0.19.12': + optional: true + + '@esbuild/linux-arm@0.19.12': + optional: true + + '@esbuild/linux-ia32@0.19.12': + optional: true + + '@esbuild/linux-loong64@0.19.12': + optional: true + + '@esbuild/linux-mips64el@0.19.12': + optional: true + + '@esbuild/linux-ppc64@0.19.12': + optional: true '@esbuild/linux-riscv64@0.19.12': optional: true @@ -3859,7 +5187,7 @@ snapshots: '@floating-ui/core': 1.5.3 '@floating-ui/utils': 0.2.1 - '@floating-ui/react-dom@2.0.6(react-dom@18.2.0)(react@18.2.0)': + '@floating-ui/react-dom@2.0.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@floating-ui/dom': 1.5.4 react: 18.2.0 @@ -3907,16 +5235,196 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 + '@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.14.1 + resolve-from: 5.0.0 + + '@istanbuljs/schema@0.1.3': {} + + '@jest/console@29.7.0': + dependencies: + '@jest/types': 29.6.3 + '@types/node': 20.11.5 + chalk: 4.1.2 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + slash: 3.0.0 + + '@jest/core@29.7.0(ts-node@10.9.2(@types/node@20.11.5)(typescript@5.3.3))': + 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': 20.11.5 + 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@20.11.5)(ts-node@10.9.2(@types/node@20.11.5)(typescript@5.3.3)) + 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.5 + 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': 20.11.5 + 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': 20.11.5 + 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.21 + '@types/node': 20.11.5 + chalk: 4.1.2 + collect-v8-coverage: 1.0.2 + exit: 0.1.2 + glob: 7.2.3 + graceful-fs: 4.2.11 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-instrument: 6.0.2 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 4.0.1 + istanbul-reports: 3.1.7 + 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.2.0 + transitivePeerDependencies: + - supports-color + + '@jest/schemas@29.6.3': + dependencies: + '@sinclair/typebox': 0.27.8 + + '@jest/source-map@29.6.3': + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + 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.2 + + '@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.24.5 + '@jest/types': 29.6.3 + '@jridgewell/trace-mapping': 0.3.21 + 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.5 + pirates: 4.0.6 + 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': 20.11.5 + '@types/yargs': 17.0.32 + chalk: 4.1.2 + '@jridgewell/gen-mapping@0.3.3': dependencies: '@jridgewell/set-array': 1.1.2 '@jridgewell/sourcemap-codec': 1.4.15 '@jridgewell/trace-mapping': 0.3.21 + '@jridgewell/gen-mapping@0.3.5': + dependencies: + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/resolve-uri@3.1.1': {} '@jridgewell/set-array@1.1.2': {} + '@jridgewell/set-array@1.2.1': {} + '@jridgewell/sourcemap-codec@1.4.15': {} '@jridgewell/trace-mapping@0.3.21': @@ -3924,6 +5432,16 @@ snapshots: '@jridgewell/resolve-uri': 3.1.1 '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/trace-mapping@0.3.25': + dependencies: + '@jridgewell/resolve-uri': 3.1.1 + '@jridgewell/sourcemap-codec': 1.4.15 + + '@jridgewell/trace-mapping@0.3.9': + dependencies: + '@jridgewell/resolve-uri': 3.1.1 + '@jridgewell/sourcemap-codec': 1.4.15 + '@jsdevtools/ono@7.1.3': {} '@jsep-plugin/regex@1.0.3(jsep@1.3.8)': @@ -4088,72 +5606,77 @@ snapshots: dependencies: '@babel/runtime': 7.23.9 - '@radix-ui/react-alert-dialog@1.0.5(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-alert-dialog@1.0.5(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.9 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.48)(react@18.2.0) '@radix-ui/react-context': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@radix-ui/react-dialog': 1.0.5(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-dialog': 1.0.5(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-slot': 1.0.2(@types/react@18.2.48)(react@18.2.0) - '@types/react': 18.2.48 - '@types/react-dom': 18.2.18 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.48 + '@types/react-dom': 18.2.18 - '@radix-ui/react-arrow@1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-arrow@1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.9 - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@types/react': 18.2.48 - '@types/react-dom': 18.2.18 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.48 + '@types/react-dom': 18.2.18 - '@radix-ui/react-checkbox@1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-checkbox@1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.48)(react@18.2.0) '@radix-ui/react-context': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.48)(react@18.2.0) '@radix-ui/react-use-previous': 1.0.1(@types/react@18.2.48)(react@18.2.0) '@radix-ui/react-use-size': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@types/react': 18.2.48 - '@types/react-dom': 18.2.18 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.48 + '@types/react-dom': 18.2.18 - '@radix-ui/react-collapsible@1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-collapsible@1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.9 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.48)(react@18.2.0) '@radix-ui/react-context': 1.0.1(@types/react@18.2.48)(react@18.2.0) '@radix-ui/react-id': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.48)(react@18.2.0) '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@types/react': 18.2.48 - '@types/react-dom': 18.2.18 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.48 + '@types/react-dom': 18.2.18 - '@radix-ui/react-collection@1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-collection@1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.48)(react@18.2.0) '@radix-ui/react-context': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-slot': 1.0.2(@types/react@18.2.48)(react@18.2.0) - '@types/react': 18.2.48 - '@types/react-dom': 18.2.18 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.48 + '@types/react-dom': 18.2.18 '@radix-ui/react-compose-refs@1.0.0(react@18.2.0)': dependencies: @@ -4163,8 +5686,9 @@ snapshots: '@radix-ui/react-compose-refs@1.0.1(@types/react@18.2.48)(react@18.2.0)': dependencies: '@babel/runtime': 7.23.9 - '@types/react': 18.2.48 react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.48 '@radix-ui/react-context@1.0.0(react@18.2.0)': dependencies: @@ -4174,22 +5698,23 @@ snapshots: '@radix-ui/react-context@1.0.1(@types/react@18.2.48)(react@18.2.0)': dependencies: '@babel/runtime': 7.23.9 - '@types/react': 18.2.48 react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.48 - '@radix-ui/react-dialog@1.0.0(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-dialog@1.0.0(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.9 '@radix-ui/primitive': 1.0.0 '@radix-ui/react-compose-refs': 1.0.0(react@18.2.0) '@radix-ui/react-context': 1.0.0(react@18.2.0) - '@radix-ui/react-dismissable-layer': 1.0.0(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-dismissable-layer': 1.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-focus-guards': 1.0.0(react@18.2.0) - '@radix-ui/react-focus-scope': 1.0.0(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-focus-scope': 1.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-id': 1.0.0(react@18.2.0) - '@radix-ui/react-portal': 1.0.0(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-presence': 1.0.0(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.0(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-portal': 1.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-presence': 1.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-primitive': 1.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-slot': 1.0.0(react@18.2.0) '@radix-ui/react-use-controllable-state': 1.0.0(react@18.2.0) aria-hidden: 1.2.3 @@ -4199,57 +5724,60 @@ snapshots: transitivePeerDependencies: - '@types/react' - '@radix-ui/react-dialog@1.0.5(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-dialog@1.0.5(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.48)(react@18.2.0) '@radix-ui/react-context': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@radix-ui/react-dismissable-layer': 1.0.5(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-dismissable-layer': 1.0.5(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-focus-guards': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@radix-ui/react-focus-scope': 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-focus-scope': 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-id': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@radix-ui/react-portal': 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-portal': 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-slot': 1.0.2(@types/react@18.2.48)(react@18.2.0) '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@types/react': 18.2.48 - '@types/react-dom': 18.2.18 aria-hidden: 1.2.3 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) react-remove-scroll: 2.5.5(@types/react@18.2.48)(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.48 + '@types/react-dom': 18.2.18 '@radix-ui/react-direction@1.0.1(@types/react@18.2.48)(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 - '@types/react': 18.2.48 react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.48 - '@radix-ui/react-dismissable-layer@1.0.0(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-dismissable-layer@1.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.9 '@radix-ui/primitive': 1.0.0 '@radix-ui/react-compose-refs': 1.0.0(react@18.2.0) - '@radix-ui/react-primitive': 1.0.0(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-use-callback-ref': 1.0.0(react@18.2.0) '@radix-ui/react-use-escape-keydown': 1.0.0(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@radix-ui/react-dismissable-layer@1.0.5(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-dismissable-layer@1.0.5(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.48)(react@18.2.0) '@radix-ui/react-use-escape-keydown': 1.0.3(@types/react@18.2.48)(react@18.2.0) - '@types/react': 18.2.48 - '@types/react-dom': 18.2.18 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.48 + '@types/react-dom': 18.2.18 '@radix-ui/react-focus-guards@1.0.0(react@18.2.0)': dependencies: @@ -4259,28 +5787,30 @@ snapshots: '@radix-ui/react-focus-guards@1.0.1(@types/react@18.2.48)(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 - '@types/react': 18.2.48 react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.48 - '@radix-ui/react-focus-scope@1.0.0(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-focus-scope@1.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.9 '@radix-ui/react-compose-refs': 1.0.0(react@18.2.0) - '@radix-ui/react-primitive': 1.0.0(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-use-callback-ref': 1.0.0(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@radix-ui/react-focus-scope@1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-focus-scope@1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@types/react': 18.2.48 - '@types/react-dom': 18.2.18 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.48 + '@types/react-dom': 18.2.18 '@radix-ui/react-icons@1.3.0(react@18.2.0)': dependencies: @@ -4296,76 +5826,81 @@ snapshots: dependencies: '@babel/runtime': 7.23.9 '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@types/react': 18.2.48 react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.48 - '@radix-ui/react-label@2.0.2(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-label@2.0.2(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@types/react': 18.2.48 - '@types/react-dom': 18.2.18 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.48 + '@types/react-dom': 18.2.18 - '@radix-ui/react-popover@1.0.7(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-popover@1.0.7(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.48)(react@18.2.0) '@radix-ui/react-context': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@radix-ui/react-dismissable-layer': 1.0.5(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-dismissable-layer': 1.0.5(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-focus-guards': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@radix-ui/react-focus-scope': 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-focus-scope': 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-id': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@radix-ui/react-popper': 1.1.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-portal': 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-popper': 1.1.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-portal': 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-slot': 1.0.2(@types/react@18.2.48)(react@18.2.0) '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@types/react': 18.2.48 - '@types/react-dom': 18.2.18 aria-hidden: 1.2.3 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) react-remove-scroll: 2.5.5(@types/react@18.2.48)(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.48 + '@types/react-dom': 18.2.18 - '@radix-ui/react-popper@1.1.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-popper@1.1.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 - '@floating-ui/react-dom': 2.0.6(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-arrow': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@floating-ui/react-dom': 2.0.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-arrow': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.48)(react@18.2.0) '@radix-ui/react-context': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.48)(react@18.2.0) '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.48)(react@18.2.0) '@radix-ui/react-use-rect': 1.0.1(@types/react@18.2.48)(react@18.2.0) '@radix-ui/react-use-size': 1.0.1(@types/react@18.2.48)(react@18.2.0) '@radix-ui/rect': 1.0.1 - '@types/react': 18.2.48 - '@types/react-dom': 18.2.18 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.48 + '@types/react-dom': 18.2.18 - '@radix-ui/react-portal@1.0.0(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-portal@1.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.9 - '@radix-ui/react-primitive': 1.0.0(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@radix-ui/react-portal@1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-portal@1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@types/react': 18.2.48 - '@types/react-dom': 18.2.18 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.48 + '@types/react-dom': 18.2.18 - '@radix-ui/react-presence@1.0.0(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-presence@1.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.9 '@radix-ui/react-compose-refs': 1.0.0(react@18.2.0) @@ -4373,68 +5908,72 @@ snapshots: react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@radix-ui/react-presence@1.0.1(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-presence@1.0.1(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.9 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.48)(react@18.2.0) '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@types/react': 18.2.48 - '@types/react-dom': 18.2.18 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.48 + '@types/react-dom': 18.2.18 - '@radix-ui/react-primitive@1.0.0(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-primitive@1.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.9 '@radix-ui/react-slot': 1.0.0(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@radix-ui/react-primitive@1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-primitive@1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.9 '@radix-ui/react-slot': 1.0.2(@types/react@18.2.48)(react@18.2.0) - '@types/react': 18.2.48 - '@types/react-dom': 18.2.18 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.48 + '@types/react-dom': 18.2.18 - '@radix-ui/react-radio-group@1.1.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-radio-group@1.1.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.48)(react@18.2.0) '@radix-ui/react-context': 1.0.1(@types/react@18.2.48)(react@18.2.0) '@radix-ui/react-direction': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-roving-focus': 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-roving-focus': 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.48)(react@18.2.0) '@radix-ui/react-use-previous': 1.0.1(@types/react@18.2.48)(react@18.2.0) '@radix-ui/react-use-size': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@types/react': 18.2.48 - '@types/react-dom': 18.2.18 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.48 + '@types/react-dom': 18.2.18 - '@radix-ui/react-roving-focus@1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-roving-focus@1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-collection': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-collection': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.48)(react@18.2.0) '@radix-ui/react-context': 1.0.1(@types/react@18.2.48)(react@18.2.0) '@radix-ui/react-direction': 1.0.1(@types/react@18.2.48)(react@18.2.0) '@radix-ui/react-id': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.48)(react@18.2.0) '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@types/react': 18.2.48 - '@types/react-dom': 18.2.18 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.48 + '@types/react-dom': 18.2.18 - '@radix-ui/react-scroll-area@1.0.5(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-scroll-area@1.0.5(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 '@radix-ui/number': 1.0.1 @@ -4442,43 +5981,45 @@ snapshots: '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.48)(react@18.2.0) '@radix-ui/react-context': 1.0.1(@types/react@18.2.48)(react@18.2.0) '@radix-ui/react-direction': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.48)(react@18.2.0) '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@types/react': 18.2.48 - '@types/react-dom': 18.2.18 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.48 + '@types/react-dom': 18.2.18 - '@radix-ui/react-select@2.0.0(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-select@2.0.0(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 '@radix-ui/number': 1.0.1 '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-collection': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-collection': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.48)(react@18.2.0) '@radix-ui/react-context': 1.0.1(@types/react@18.2.48)(react@18.2.0) '@radix-ui/react-direction': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@radix-ui/react-dismissable-layer': 1.0.5(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-dismissable-layer': 1.0.5(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-focus-guards': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@radix-ui/react-focus-scope': 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-focus-scope': 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-id': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@radix-ui/react-popper': 1.1.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-portal': 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-popper': 1.1.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-portal': 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-slot': 1.0.2(@types/react@18.2.48)(react@18.2.0) '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.48)(react@18.2.0) '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.48)(react@18.2.0) '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.48)(react@18.2.0) '@radix-ui/react-use-previous': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@radix-ui/react-visually-hidden': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@types/react': 18.2.48 - '@types/react-dom': 18.2.18 + '@radix-ui/react-visually-hidden': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) aria-hidden: 1.2.3 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) react-remove-scroll: 2.5.5(@types/react@18.2.48)(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.48 + '@types/react-dom': 18.2.18 '@radix-ui/react-slot@1.0.0(react@18.2.0)': dependencies: @@ -4490,44 +6031,47 @@ snapshots: dependencies: '@babel/runtime': 7.23.8 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@types/react': 18.2.48 react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.48 - '@radix-ui/react-tabs@1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-tabs@1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.9 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-context': 1.0.1(@types/react@18.2.48)(react@18.2.0) '@radix-ui/react-direction': 1.0.1(@types/react@18.2.48)(react@18.2.0) '@radix-ui/react-id': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-roving-focus': 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-roving-focus': 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@types/react': 18.2.48 - '@types/react-dom': 18.2.18 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.48 + '@types/react-dom': 18.2.18 - '@radix-ui/react-tooltip@1.0.7(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-tooltip@1.0.7(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.48)(react@18.2.0) '@radix-ui/react-context': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@radix-ui/react-dismissable-layer': 1.0.5(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-dismissable-layer': 1.0.5(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-id': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@radix-ui/react-popper': 1.1.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-portal': 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-popper': 1.1.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-portal': 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-slot': 1.0.2(@types/react@18.2.48)(react@18.2.0) '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@radix-ui/react-visually-hidden': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@types/react': 18.2.48 - '@types/react-dom': 18.2.18 + '@radix-ui/react-visually-hidden': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.48 + '@types/react-dom': 18.2.18 '@radix-ui/react-use-callback-ref@1.0.0(react@18.2.0)': dependencies: @@ -4537,8 +6081,9 @@ snapshots: '@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.2.48)(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 - '@types/react': 18.2.48 react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.48 '@radix-ui/react-use-controllable-state@1.0.0(react@18.2.0)': dependencies: @@ -4550,8 +6095,9 @@ snapshots: dependencies: '@babel/runtime': 7.23.9 '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@types/react': 18.2.48 react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.48 '@radix-ui/react-use-escape-keydown@1.0.0(react@18.2.0)': dependencies: @@ -4563,8 +6109,9 @@ snapshots: dependencies: '@babel/runtime': 7.23.9 '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@types/react': 18.2.48 react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.48 '@radix-ui/react-use-layout-effect@1.0.0(react@18.2.0)': dependencies: @@ -4574,37 +6121,42 @@ snapshots: '@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.2.48)(react@18.2.0)': dependencies: '@babel/runtime': 7.23.9 - '@types/react': 18.2.48 react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.48 '@radix-ui/react-use-previous@1.0.1(@types/react@18.2.48)(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 - '@types/react': 18.2.48 react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.48 '@radix-ui/react-use-rect@1.0.1(@types/react@18.2.48)(react@18.2.0)': dependencies: '@babel/runtime': 7.23.9 '@radix-ui/rect': 1.0.1 - '@types/react': 18.2.48 react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.48 '@radix-ui/react-use-size@1.0.1(@types/react@18.2.48)(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@types/react': 18.2.48 react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.48 - '@radix-ui/react-visually-hidden@1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-visually-hidden@1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@types/react': 18.2.48 - '@types/react-dom': 18.2.18 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.48 + '@types/react-dom': 18.2.18 '@radix-ui/rect@1.0.1': dependencies: @@ -4612,6 +6164,16 @@ snapshots: '@rushstack/eslint-patch@1.7.2': {} + '@sinclair/typebox@0.27.8': {} + + '@sinonjs/commons@3.0.1': + dependencies: + type-detect: 4.0.8 + + '@sinonjs/fake-timers@10.3.0': + dependencies: + '@sinonjs/commons': 3.0.1 + '@stencil/core@2.22.3': {} '@stoplight/better-ajv-errors@1.0.3(ajv@8.12.0)': @@ -4787,22 +6349,24 @@ snapshots: '@t3-oss/env-core@0.7.3(typescript@5.3.3)(zod@3.22.4)': dependencies: - typescript: 5.3.3 zod: 3.22.4 + optionalDependencies: + typescript: 5.3.3 '@t3-oss/env-nextjs@0.7.3(typescript@5.3.3)(zod@3.22.4)': dependencies: '@t3-oss/env-core': 0.7.3(typescript@5.3.3)(zod@3.22.4) - typescript: 5.3.3 zod: 3.22.4 + optionalDependencies: + typescript: 5.3.3 - '@tailwindcss/typography@0.5.13(tailwindcss@3.4.1)': + '@tailwindcss/typography@0.5.13(tailwindcss@3.4.1(ts-node@10.9.2(@types/node@20.11.5)(typescript@5.3.3)))': dependencies: lodash.castarray: 4.4.0 lodash.isplainobject: 4.0.6 lodash.merge: 4.6.2 postcss-selector-parser: 6.0.10 - tailwindcss: 3.4.1 + tailwindcss: 3.4.1(ts-node@10.9.2(@types/node@20.11.5)(typescript@5.3.3)) '@tanstack/query-core@5.28.9': {} @@ -4811,7 +6375,7 @@ snapshots: '@tanstack/query-core': 5.28.9 react: 18.2.0 - '@tanstack/react-table@8.15.3(react-dom@18.2.0)(react@18.2.0)': + '@tanstack/react-table@8.15.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@tanstack/table-core': 8.15.3 react: 18.2.0 @@ -4819,8 +6383,77 @@ snapshots: '@tanstack/table-core@8.15.3': {} + '@testing-library/dom@10.1.0': + dependencies: + '@babel/code-frame': 7.24.2 + '@babel/runtime': 7.23.9 + '@types/aria-query': 5.0.4 + aria-query: 5.3.0 + chalk: 4.1.2 + dom-accessibility-api: 0.5.16 + lz-string: 1.5.0 + pretty-format: 27.5.1 + + '@testing-library/jest-dom@6.4.5(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.11.5)(ts-node@10.9.2(@types/node@20.11.5)(typescript@5.3.3)))': + dependencies: + '@adobe/css-tools': 4.3.3 + '@babel/runtime': 7.23.9 + aria-query: 5.3.0 + chalk: 3.0.0 + css.escape: 1.5.1 + dom-accessibility-api: 0.6.3 + lodash: 4.17.21 + redent: 3.0.0 + optionalDependencies: + '@jest/globals': 29.7.0 + '@types/jest': 29.5.12 + jest: 29.7.0(@types/node@20.11.5)(ts-node@10.9.2(@types/node@20.11.5)(typescript@5.3.3)) + + '@testing-library/react@15.0.7(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + dependencies: + '@babel/runtime': 7.23.9 + '@testing-library/dom': 10.1.0 + '@types/react-dom': 18.2.18 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.48 + + '@tootallnate/once@2.0.0': {} + '@trysound/sax@0.2.0': {} + '@tsconfig/node10@1.0.11': {} + + '@tsconfig/node12@1.0.11': {} + + '@tsconfig/node14@1.0.3': {} + + '@tsconfig/node16@1.0.4': {} + + '@types/aria-query@5.0.4': {} + + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.24.5 + '@babel/types': 7.24.5 + '@types/babel__generator': 7.6.8 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.20.5 + + '@types/babel__generator@7.6.8': + dependencies: + '@babel/types': 7.24.5 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.24.5 + '@babel/types': 7.24.5 + + '@types/babel__traverse@7.20.5': + dependencies: + '@babel/types': 7.24.5 + '@types/chroma-js@2.4.4': {} '@types/color-convert@2.0.3': @@ -4871,6 +6504,31 @@ snapshots: '@types/geojson@7946.0.14': {} + '@types/graceful-fs@4.1.9': + dependencies: + '@types/node': 20.11.5 + + '@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.12': + dependencies: + expect: 29.7.0 + pretty-format: 29.7.0 + + '@types/jsdom@20.0.1': + dependencies: + '@types/node': 20.11.5 + '@types/tough-cookie': 4.0.5 + parse5: 7.1.2 + '@types/json-schema@7.0.15': {} '@types/json5@0.0.29': {} @@ -4903,9 +6561,19 @@ snapshots: '@types/semver@7.5.6': {} + '@types/stack-utils@2.0.3': {} + + '@types/tough-cookie@4.0.5': {} + '@types/urijs@1.19.25': {} - '@typescript-eslint/eslint-plugin@6.19.0(@typescript-eslint/parser@6.19.0)(eslint@8.56.0)(typescript@5.3.3)': + '@types/yargs-parser@21.0.3': {} + + '@types/yargs@17.0.32': + dependencies: + '@types/yargs-parser': 21.0.3 + + '@typescript-eslint/eslint-plugin@6.19.0(@typescript-eslint/parser@6.19.0(eslint@8.56.0)(typescript@5.3.3))(eslint@8.56.0)(typescript@5.3.3)': dependencies: '@eslint-community/regexpp': 4.10.0 '@typescript-eslint/parser': 6.19.0(eslint@8.56.0)(typescript@5.3.3) @@ -4920,6 +6588,7 @@ snapshots: natural-compare: 1.4.0 semver: 7.5.4 ts-api-utils: 1.0.3(typescript@5.3.3) + optionalDependencies: typescript: 5.3.3 transitivePeerDependencies: - supports-color @@ -4932,6 +6601,7 @@ snapshots: '@typescript-eslint/visitor-keys': 6.19.0 debug: 4.3.4 eslint: 8.56.0 + optionalDependencies: typescript: 5.3.3 transitivePeerDependencies: - supports-color @@ -4948,6 +6618,7 @@ snapshots: debug: 4.3.4 eslint: 8.56.0 ts-api-utils: 1.0.3(typescript@5.3.3) + optionalDependencies: typescript: 5.3.3 transitivePeerDependencies: - supports-color @@ -4964,6 +6635,7 @@ snapshots: minimatch: 9.0.3 semver: 7.5.4 ts-api-utils: 1.0.3(typescript@5.3.3) + optionalDependencies: typescript: 5.3.3 transitivePeerDependencies: - supports-color @@ -4989,7 +6661,7 @@ snapshots: '@ungap/structured-clone@1.2.0': {} - '@visx/annotation@3.3.0(react-dom@18.2.0)(react@18.2.0)': + '@visx/annotation@3.3.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@types/react': 18.2.48 '@visx/drag': 3.3.0(react@18.2.0) @@ -4998,11 +6670,11 @@ snapshots: classnames: 2.5.1 prop-types: 15.8.1 react: 18.2.0 - react-use-measure: 2.1.1(react-dom@18.2.0)(react@18.2.0) + react-use-measure: 2.1.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) transitivePeerDependencies: - react-dom - '@visx/bounds@3.3.0(react-dom@18.2.0)(react@18.2.0)': + '@visx/bounds@3.3.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@types/react': 18.2.48 '@types/react-dom': 18.2.18 @@ -5094,15 +6766,15 @@ snapshots: react: 18.2.0 reduce-css-calc: 1.3.0 - '@visx/tooltip@3.3.0(react-dom@18.2.0)(react@18.2.0)': + '@visx/tooltip@3.3.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@types/react': 18.2.48 - '@visx/bounds': 3.3.0(react-dom@18.2.0)(react@18.2.0) + '@visx/bounds': 3.3.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 prop-types: 15.8.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - react-use-measure: 2.1.1(react-dom@18.2.0)(react@18.2.0) + react-use-measure: 2.1.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@visx/vendor@3.5.0': dependencies: @@ -5128,18 +6800,33 @@ snapshots: '@zip.js/zip.js@2.7.34': {} + abab@2.0.6: {} + abort-controller@3.0.0: dependencies: event-target-shim: 5.0.1 + acorn-globals@7.0.1: + dependencies: + acorn: 8.11.3 + acorn-walk: 8.3.2 + acorn-jsx@5.3.2(acorn@8.11.3): dependencies: acorn: 8.11.3 + acorn-walk@8.3.2: {} + acorn@8.11.3: {} - ajv-draft-04@1.0.0(ajv@8.12.0): + agent-base@6.0.2: dependencies: + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + + ajv-draft-04@1.0.0(ajv@8.12.0): + optionalDependencies: ajv: 8.12.0 ajv-errors@3.0.0(ajv@8.12.0): @@ -5147,7 +6834,7 @@ snapshots: ajv: 8.12.0 ajv-formats@2.1.1(ajv@8.12.0): - dependencies: + optionalDependencies: ajv: 8.12.0 ajv@6.12.6: @@ -5166,14 +6853,24 @@ snapshots: ansi-colors@4.1.3: {} + ansi-escapes@4.3.2: + dependencies: + type-fest: 0.21.3 + ansi-regex@5.0.1: {} ansi-regex@6.0.1: {} + ansi-styles@3.2.1: + dependencies: + color-convert: 1.9.3 + ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 + ansi-styles@5.2.0: {} + ansi-styles@6.2.1: {} any-promise@1.3.0: {} @@ -5183,6 +6880,8 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.1 + arg@4.1.3: {} + arg@5.0.2: {} argparse@1.0.10: @@ -5285,21 +6984,73 @@ snapshots: available-typed-arrays@1.0.7: dependencies: - possible-typed-array-names: 1.0.0 + possible-typed-array-names: 1.0.0 + + axe-core@4.7.0: {} + + axios@1.6.8: + dependencies: + follow-redirects: 1.15.6 + form-data: 4.0.0 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + + axobject-query@3.2.1: + dependencies: + dequal: 2.0.3 + + babel-jest@29.7.0(@babel/core@7.24.5): + dependencies: + '@babel/core': 7.24.5 + '@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.24.5) + 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.24.5 + '@istanbuljs/load-nyc-config': 1.1.0 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-instrument: 5.2.1 + test-exclude: 6.0.0 + transitivePeerDependencies: + - supports-color - axe-core@4.7.0: {} + babel-plugin-jest-hoist@29.6.3: + dependencies: + '@babel/template': 7.24.0 + '@babel/types': 7.24.5 + '@types/babel__core': 7.20.5 + '@types/babel__traverse': 7.20.5 - axios@1.6.8: + babel-preset-current-node-syntax@1.0.1(@babel/core@7.24.5): dependencies: - follow-redirects: 1.15.6 - form-data: 4.0.0 - proxy-from-env: 1.1.0 - transitivePeerDependencies: - - debug + '@babel/core': 7.24.5 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.5) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.24.5) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.24.5) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.5) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.5) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.5) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.5) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.5) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.5) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.5) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.5) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.5) - axobject-query@3.2.1: + babel-preset-jest@29.6.3(@babel/core@7.24.5): dependencies: - dequal: 2.0.3 + '@babel/core': 7.24.5 + babel-plugin-jest-hoist: 29.6.3 + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.24.5) balanced-match@0.4.2: {} @@ -5329,6 +7080,16 @@ snapshots: node-releases: 2.0.14 update-browserslist-db: 1.0.13(browserslist@4.22.2) + bs-logger@0.2.6: + dependencies: + fast-json-stable-stringify: 2.1.0 + + bser@2.1.1: + dependencies: + node-int64: 0.4.0 + + buffer-from@1.1.2: {} + busboy@1.6.0: dependencies: streamsearch: 1.1.0 @@ -5349,15 +7110,32 @@ snapshots: camelcase-css@2.0.1: {} + camelcase@5.3.1: {} + + camelcase@6.3.0: {} + caniuse-lite@1.0.30001579: {} caniuse-lite@1.0.30001589: {} + chalk@2.4.2: + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + + chalk@3.0.0: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + chalk@4.1.2: dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 + char-regex@1.0.2: {} + chokidar@3.5.3: dependencies: anymatch: 3.1.3 @@ -5372,6 +7150,10 @@ snapshots: chroma-js@2.4.2: {} + ci-info@3.9.0: {} + + cjs-module-lexer@1.3.1: {} + class-variance-authority@0.7.0: dependencies: clsx: 2.0.0 @@ -5390,18 +7172,28 @@ snapshots: clsx@2.1.0: {} - cmdk@0.2.1(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0): + cmdk@0.2.1(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: - '@radix-ui/react-dialog': 1.0.0(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-dialog': 1.0.0(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) transitivePeerDependencies: - '@types/react' + co@4.6.0: {} + + collect-v8-coverage@1.0.2: {} + + color-convert@1.9.3: + dependencies: + color-name: 1.1.3 + color-convert@2.0.1: dependencies: color-name: 1.1.4 + color-name@1.1.3: {} + color-name@1.1.4: {} color-string@1.9.1: @@ -5430,6 +7222,25 @@ snapshots: concat-map@0.0.1: {} + convert-source-map@2.0.0: {} + + create-jest@29.7.0(@types/node@20.11.5)(ts-node@10.9.2(@types/node@20.11.5)(typescript@5.3.3)): + 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@20.11.5)(ts-node@10.9.2(@types/node@20.11.5)(typescript@5.3.3)) + jest-util: 29.7.0 + prompts: 2.4.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + + create-require@1.1.1: {} + cross-spawn@7.0.3: dependencies: path-key: 3.1.1 @@ -5456,6 +7267,8 @@ snapshots: css-what@6.1.0: {} + css.escape@1.5.1: {} + cssesc@3.0.0: {} cssfilter@0.0.10: {} @@ -5464,6 +7277,14 @@ snapshots: dependencies: css-tree: 2.2.1 + cssom@0.3.8: {} + + cssom@0.5.0: {} + + cssstyle@2.3.0: + dependencies: + cssom: 0.3.8 + csstype@3.1.3: {} d3-array@3.2.1: @@ -5512,6 +7333,12 @@ snapshots: damerau-levenshtein@1.0.8: {} + data-urls@3.0.2: + dependencies: + abab: 2.0.6 + whatwg-mimetype: 3.0.0 + whatwg-url: 11.0.0 + data-view-buffer@1.0.1: dependencies: call-bind: 1.0.7 @@ -5542,10 +7369,16 @@ snapshots: dependencies: ms: 2.1.2 + decimal.js@10.4.3: {} + decode-uri-component@0.4.1: {} + dedent@1.5.3: {} + deep-is@0.1.4: {} + deepmerge@4.3.1: {} + define-data-property@1.1.4: dependencies: es-define-property: 1.0.0 @@ -5568,10 +7401,16 @@ snapshots: dequal@2.0.3: {} + detect-newline@3.1.0: {} + detect-node-es@1.1.0: {} didyoumean@1.2.2: {} + diff-sequences@29.6.3: {} + + diff@4.0.2: {} + dir-glob@3.0.1: dependencies: path-type: 4.0.0 @@ -5586,6 +7425,10 @@ snapshots: dependencies: esutils: 2.0.3 + dom-accessibility-api@0.5.16: {} + + dom-accessibility-api@0.6.3: {} + dom-serializer@2.0.0: dependencies: domelementtype: 2.3.0 @@ -5594,6 +7437,10 @@ snapshots: domelementtype@2.3.0: {} + domexception@4.0.0: + dependencies: + webidl-conversions: 7.0.0 + domhandler@5.0.3: dependencies: domelementtype: 2.3.0 @@ -5608,6 +7455,8 @@ snapshots: electron-to-chromium@1.4.637: {} + emittery@0.13.1: {} + emoji-regex@8.0.0: {} emoji-regex@9.2.2: {} @@ -5624,6 +7473,10 @@ snapshots: entities@4.5.0: {} + error-ex@1.3.2: + dependencies: + is-arrayish: 0.2.1 + es-abstract@1.22.4: dependencies: array-buffer-byte-length: 1.0.1 @@ -5804,8 +7657,20 @@ snapshots: escalade@3.1.1: {} + escape-string-regexp@1.0.5: {} + + escape-string-regexp@2.0.0: {} + escape-string-regexp@4.0.0: {} + escodegen@2.1.0: + dependencies: + esprima: 4.0.1 + estraverse: 5.3.0 + esutils: 2.0.3 + optionalDependencies: + source-map: 0.6.1 + eslint-config-next@14.1.0(eslint@8.56.0)(typescript@5.3.3): dependencies: '@next/eslint-plugin-next': 14.1.0 @@ -5813,11 +7678,12 @@ snapshots: '@typescript-eslint/parser': 6.19.0(eslint@8.56.0)(typescript@5.3.3) eslint: 8.56.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.19.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.56.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.19.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.19.0(eslint@8.56.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.56.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.19.0(eslint@8.56.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0) eslint-plugin-jsx-a11y: 6.8.0(eslint@8.56.0) eslint-plugin-react: 7.33.2(eslint@8.56.0) eslint-plugin-react-hooks: 4.6.0(eslint@8.56.0) + optionalDependencies: typescript: 5.3.3 transitivePeerDependencies: - eslint-import-resolver-webpack @@ -5835,13 +7701,13 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.19.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.56.0): + eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.19.0(eslint@8.56.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.56.0): dependencies: debug: 4.3.4 enhanced-resolve: 5.15.0 eslint: 8.56.0 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.19.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.19.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.19.0(eslint@8.56.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.19.0(eslint@8.56.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.56.0))(eslint@8.56.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.19.0(eslint@8.56.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0) fast-glob: 3.3.2 get-tsconfig: 4.7.2 is-core-module: 2.13.1 @@ -5852,19 +7718,19 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.8.0(@typescript-eslint/parser@6.19.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0): + eslint-module-utils@2.8.0(@typescript-eslint/parser@6.19.0(eslint@8.56.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.19.0(eslint@8.56.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.56.0))(eslint@8.56.0): dependencies: - '@typescript-eslint/parser': 6.19.0(eslint@8.56.0)(typescript@5.3.3) debug: 3.2.7 + optionalDependencies: + '@typescript-eslint/parser': 6.19.0(eslint@8.56.0)(typescript@5.3.3) eslint: 8.56.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.19.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.56.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.19.0(eslint@8.56.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.56.0) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.19.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0): + eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.19.0(eslint@8.56.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0): dependencies: - '@typescript-eslint/parser': 6.19.0(eslint@8.56.0)(typescript@5.3.3) array-includes: 3.1.7 array.prototype.findlastindex: 1.2.4 array.prototype.flat: 1.3.2 @@ -5873,7 +7739,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.56.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.19.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.19.0(eslint@8.56.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.19.0(eslint@8.56.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.56.0))(eslint@8.56.0) hasown: 2.0.1 is-core-module: 2.13.1 is-glob: 4.0.3 @@ -5883,6 +7749,8 @@ snapshots: object.values: 1.1.7 semver: 6.3.1 tsconfig-paths: 3.15.0 + optionalDependencies: + '@typescript-eslint/parser': 6.19.0(eslint@8.56.0)(typescript@5.3.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -5908,13 +7776,14 @@ snapshots: object.entries: 1.1.7 object.fromentries: 2.0.7 - eslint-plugin-prettier@5.1.3(eslint-config-prettier@9.1.0)(eslint@8.56.0)(prettier@3.2.4): + eslint-plugin-prettier@5.1.3(eslint-config-prettier@9.1.0(eslint@8.56.0))(eslint@8.56.0)(prettier@3.2.4): dependencies: eslint: 8.56.0 - eslint-config-prettier: 9.1.0(eslint@8.56.0) prettier: 3.2.4 prettier-linter-helpers: 1.0.0 synckit: 0.8.8 + optionalDependencies: + eslint-config-prettier: 9.1.0(eslint@8.56.0) eslint-plugin-react-hooks@4.6.0(eslint@8.56.0): dependencies: @@ -6024,6 +7893,16 @@ snapshots: 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-diff@1.3.0: {} @@ -6048,6 +7927,10 @@ snapshots: dependencies: reusify: 1.0.4 + fb-watchman@2.0.2: + dependencies: + bser: 2.1.1 + file-entry-cache@6.0.1: dependencies: flat-cache: 3.2.0 @@ -6058,6 +7941,11 @@ snapshots: filter-obj@5.1.0: {} + 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 @@ -6116,6 +8004,8 @@ snapshots: functions-have-names@1.2.3: {} + gensync@1.0.0-beta.2: {} + get-caller-file@2.0.5: {} get-intrinsic@1.2.4: @@ -6128,6 +8018,8 @@ snapshots: get-nonce@1.0.1: {} + get-package-type@0.1.0: {} + get-stream@6.0.1: {} get-symbol-description@1.0.2: @@ -6165,6 +8057,8 @@ snapshots: once: 1.4.0 path-is-absolute: 1.0.1 + globals@11.12.0: {} + globals@13.24.0: dependencies: type-fest: 0.20.2 @@ -6192,6 +8086,8 @@ snapshots: has-bigints@1.0.2: {} + has-flag@3.0.0: {} + has-flag@4.0.0: {} has-property-descriptors@1.0.2: @@ -6223,14 +8119,21 @@ snapshots: domhandler: 5.0.3 htmlparser2: 9.1.0 + html-encoding-sniffer@3.0.0: + dependencies: + whatwg-encoding: 2.0.0 + + html-escaper@2.0.2: {} + html-react-parser@5.1.10(@types/react@18.2.48)(react@18.2.0): dependencies: - '@types/react': 18.2.48 domhandler: 5.0.3 html-dom-parser: 5.0.8 react: 18.2.0 react-property: 2.0.2 style-to-js: 1.1.12 + optionalDependencies: + '@types/react': 18.2.48 htmlparser2@9.1.0: dependencies: @@ -6239,12 +8142,31 @@ snapshots: domutils: 3.1.0 entities: 4.5.0 + http-proxy-agent@5.0.0: + dependencies: + '@tootallnate/once': 2.0.0 + agent-base: 6.0.2 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + http2-client@1.3.5: {} + https-proxy-agent@5.0.1: + dependencies: + agent-base: 6.0.2 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + human-signals@2.1.0: {} husky@8.0.3: {} + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + ignore@5.3.0: {} immer@9.0.21: {} @@ -6254,8 +8176,15 @@ snapshots: parent-module: 1.0.1 resolve-from: 4.0.0 + import-local@3.1.0: + dependencies: + pkg-dir: 4.2.0 + resolve-cwd: 3.0.0 + imurmurhash@0.1.4: {} + indent-string@4.0.0: {} + inflight@1.0.6: dependencies: once: 1.4.0 @@ -6282,6 +8211,8 @@ snapshots: call-bind: 1.0.7 get-intrinsic: 1.2.4 + is-arrayish@0.2.1: {} + is-arrayish@0.3.2: {} is-async-function@2.0.0: @@ -6323,84 +8254,453 @@ snapshots: is-fullwidth-code-point@3.0.0: {} + is-generator-fn@2.1.0: {} + is-generator-function@1.0.10: dependencies: has-tostringtag: 1.0.2 - is-glob@4.0.3: + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-map@2.0.2: {} + + is-negative-zero@2.0.3: {} + + is-number-object@1.0.7: + dependencies: + has-tostringtag: 1.0.2 + + is-number@7.0.0: {} + + is-path-inside@3.0.3: {} + + is-potential-custom-element-name@1.0.1: {} + + is-regex@1.1.4: + dependencies: + call-bind: 1.0.7 + has-tostringtag: 1.0.2 + + is-set@2.0.2: {} + + is-shared-array-buffer@1.0.3: + dependencies: + call-bind: 1.0.7 + + is-stream@2.0.1: {} + + is-string@1.0.7: + dependencies: + has-tostringtag: 1.0.2 + + is-symbol@1.0.4: + dependencies: + has-symbols: 1.0.3 + + is-typed-array@1.1.13: + dependencies: + which-typed-array: 1.1.14 + + is-weakmap@2.0.1: {} + + is-weakref@1.0.2: + dependencies: + call-bind: 1.0.7 + + is-weakset@2.0.2: + dependencies: + call-bind: 1.0.7 + get-intrinsic: 1.2.4 + + isarray@2.0.5: {} + + isexe@2.0.0: {} + + istanbul-lib-coverage@3.2.2: {} + + istanbul-lib-instrument@5.2.1: + dependencies: + '@babel/core': 7.24.5 + '@babel/parser': 7.24.5 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.2 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + istanbul-lib-instrument@6.0.2: + dependencies: + '@babel/core': 7.24.5 + '@babel/parser': 7.24.5 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.2 + semver: 7.5.4 + 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.3.4 + istanbul-lib-coverage: 3.2.2 + source-map: 0.6.1 + transitivePeerDependencies: + - supports-color + + istanbul-reports@3.1.7: + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + + iterator.prototype@1.1.2: + dependencies: + define-properties: 1.2.1 + get-intrinsic: 1.2.4 + has-symbols: 1.0.3 + reflect.getprototypeof: 1.0.5 + set-function-name: 2.0.2 + + jackspeak@2.3.6: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + 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': 20.11.5 + chalk: 4.1.2 + co: 4.6.0 + dedent: 1.5.3 + 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@20.11.5)(ts-node@10.9.2(@types/node@20.11.5)(typescript@5.3.3)): + dependencies: + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@20.11.5)(typescript@5.3.3)) + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + chalk: 4.1.2 + create-jest: 29.7.0(@types/node@20.11.5)(ts-node@10.9.2(@types/node@20.11.5)(typescript@5.3.3)) + exit: 0.1.2 + import-local: 3.1.0 + jest-config: 29.7.0(@types/node@20.11.5)(ts-node@10.9.2(@types/node@20.11.5)(typescript@5.3.3)) + jest-util: 29.7.0 + jest-validate: 29.7.0 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + + jest-config@29.7.0(@types/node@20.11.5)(ts-node@10.9.2(@types/node@20.11.5)(typescript@5.3.3)): + dependencies: + '@babel/core': 7.24.5 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.24.5) + 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.5 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 20.11.5 + ts-node: 10.9.2(@types/node@20.11.5)(typescript@5.3.3) + 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-jsdom@29.7.0: + dependencies: + '@jest/environment': 29.7.0 + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/jsdom': 20.0.1 + '@types/node': 20.11.5 + jest-mock: 29.7.0 + jest-util: 29.7.0 + jsdom: 20.0.3 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + jest-environment-node@29.7.0: dependencies: - is-extglob: 2.1.1 + '@jest/environment': 29.7.0 + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.11.5 + jest-mock: 29.7.0 + jest-util: 29.7.0 - is-map@2.0.2: {} + jest-get-type@29.6.3: {} - is-negative-zero@2.0.3: {} + jest-haste-map@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/graceful-fs': 4.1.9 + '@types/node': 20.11.5 + 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.5 + walker: 1.0.8 + optionalDependencies: + fsevents: 2.3.3 - is-number-object@1.0.7: + jest-leak-detector@29.7.0: dependencies: - has-tostringtag: 1.0.2 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 - is-number@7.0.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 - is-path-inside@3.0.3: {} + jest-message-util@29.7.0: + dependencies: + '@babel/code-frame': 7.24.2 + '@jest/types': 29.6.3 + '@types/stack-utils': 2.0.3 + chalk: 4.1.2 + graceful-fs: 4.2.11 + micromatch: 4.0.5 + pretty-format: 29.7.0 + slash: 3.0.0 + stack-utils: 2.0.6 - is-regex@1.1.4: + jest-mock@29.7.0: dependencies: - call-bind: 1.0.7 - has-tostringtag: 1.0.2 + '@jest/types': 29.6.3 + '@types/node': 20.11.5 + jest-util: 29.7.0 - is-set@2.0.2: {} + jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): + optionalDependencies: + jest-resolve: 29.7.0 - is-shared-array-buffer@1.0.3: - dependencies: - call-bind: 1.0.7 + jest-regex-util@29.6.3: {} - is-stream@2.0.1: {} + jest-resolve-dependencies@29.7.0: + dependencies: + jest-regex-util: 29.6.3 + jest-snapshot: 29.7.0 + transitivePeerDependencies: + - supports-color - is-string@1.0.7: + jest-resolve@29.7.0: dependencies: - has-tostringtag: 1.0.2 + 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.8 + resolve.exports: 2.0.2 + slash: 3.0.0 - is-symbol@1.0.4: + jest-runner@29.7.0: dependencies: - has-symbols: 1.0.3 + '@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': 20.11.5 + 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 - is-typed-array@1.1.13: + jest-runtime@29.7.0: dependencies: - which-typed-array: 1.1.14 + '@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': 20.11.5 + chalk: 4.1.2 + cjs-module-lexer: 1.3.1 + collect-v8-coverage: 1.0.2 + 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 - is-weakmap@2.0.1: {} + jest-snapshot@29.7.0: + dependencies: + '@babel/core': 7.24.5 + '@babel/generator': 7.24.5 + '@babel/plugin-syntax-jsx': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-syntax-typescript': 7.24.1(@babel/core@7.24.5) + '@babel/types': 7.24.5 + '@jest/expect-utils': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.24.5) + 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.5.4 + transitivePeerDependencies: + - supports-color - is-weakref@1.0.2: + jest-util@29.7.0: dependencies: - call-bind: 1.0.7 + '@jest/types': 29.6.3 + '@types/node': 20.11.5 + chalk: 4.1.2 + ci-info: 3.9.0 + graceful-fs: 4.2.11 + picomatch: 2.3.1 - is-weakset@2.0.2: + jest-validate@29.7.0: dependencies: - call-bind: 1.0.7 - get-intrinsic: 1.2.4 - - isarray@2.0.5: {} + '@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 - isexe@2.0.0: {} + jest-watcher@29.7.0: + dependencies: + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.11.5 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + emittery: 0.13.1 + jest-util: 29.7.0 + string-length: 4.0.2 - iterator.prototype@1.1.2: + jest-worker@29.7.0: dependencies: - define-properties: 1.2.1 - get-intrinsic: 1.2.4 - has-symbols: 1.0.3 - reflect.getprototypeof: 1.0.5 - set-function-name: 2.0.2 + '@types/node': 20.11.5 + jest-util: 29.7.0 + merge-stream: 2.0.0 + supports-color: 8.1.1 - jackspeak@2.3.6: + jest@29.7.0(@types/node@20.11.5)(ts-node@10.9.2(@types/node@20.11.5)(typescript@5.3.3)): dependencies: - '@isaacs/cliui': 8.0.2 - optionalDependencies: - '@pkgjs/parseargs': 0.11.0 + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@20.11.5)(typescript@5.3.3)) + '@jest/types': 29.6.3 + import-local: 3.1.0 + jest-cli: 29.7.0(@types/node@20.11.5)(ts-node@10.9.2(@types/node@20.11.5)(typescript@5.3.3)) + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node jiti@1.21.0: {} jotai@2.6.2(@types/react@18.2.48)(react@18.2.0): - dependencies: + optionalDependencies: '@types/react': 18.2.48 react: 18.2.0 @@ -6415,10 +8715,47 @@ snapshots: dependencies: argparse: 2.0.1 + jsdom@20.0.3: + dependencies: + abab: 2.0.6 + acorn: 8.11.3 + acorn-globals: 7.0.1 + cssom: 0.5.0 + cssstyle: 2.3.0 + data-urls: 3.0.2 + decimal.js: 10.4.3 + domexception: 4.0.0 + escodegen: 2.1.0 + form-data: 4.0.0 + html-encoding-sniffer: 3.0.0 + http-proxy-agent: 5.0.0 + https-proxy-agent: 5.0.1 + is-potential-custom-element-name: 1.0.1 + nwsapi: 2.2.10 + parse5: 7.1.2 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 4.1.4 + w3c-xmlserializer: 4.0.0 + webidl-conversions: 7.0.0 + whatwg-encoding: 2.0.0 + whatwg-mimetype: 3.0.0 + whatwg-url: 11.0.0 + ws: 8.17.0 + xml-name-validator: 4.0.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + jsep@1.3.8: {} + jsesc@2.5.2: {} + json-buffer@3.0.1: {} + json-parse-even-better-errors@2.3.1: {} + json-schema-traverse@0.4.1: {} json-schema-traverse@1.0.0: {} @@ -6429,6 +8766,8 @@ snapshots: dependencies: minimist: 1.2.8 + json5@2.2.3: {} + jsonc-parser@2.2.1: {} jsonfile@6.1.0: @@ -6455,6 +8794,8 @@ snapshots: dependencies: json-buffer: 3.0.1 + kleur@3.0.3: {} + language-subtag-registry@0.3.22: {} language-tags@1.0.9: @@ -6474,6 +8815,10 @@ snapshots: 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 @@ -6490,6 +8835,8 @@ snapshots: lodash.isplainobject@4.0.6: {} + lodash.memoize@4.1.2: {} + lodash.merge@4.6.2: {} lodash.omit@4.5.0: {} @@ -6516,6 +8863,10 @@ snapshots: lru-cache@10.1.0: {} + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + lru-cache@6.0.0: dependencies: yallist: 4.0.0 @@ -6526,6 +8877,18 @@ snapshots: luxon@3.4.4: {} + lz-string@1.5.0: {} + + make-dir@4.0.0: + dependencies: + semver: 7.5.4 + + make-error@1.3.6: {} + + makeerror@1.0.12: + dependencies: + tmpl: 1.0.5 + math-expression-evaluator@1.4.0: {} mdn-data@2.0.28: {} @@ -6549,6 +8912,8 @@ snapshots: mimic-fn@2.1.0: {} + min-indent@1.0.1: {} + minimatch@3.1.2: dependencies: brace-expansion: 1.1.11 @@ -6581,7 +8946,7 @@ snapshots: natural-compare@1.4.0: {} - next@14.1.0(react-dom@18.2.0)(react@18.2.0): + next@14.1.0(@babel/core@7.24.5)(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@next/env': 14.1.0 '@swc/helpers': 0.5.2 @@ -6591,7 +8956,7 @@ snapshots: postcss: 8.4.31 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - styled-jsx: 5.1.1(react@18.2.0) + styled-jsx: 5.1.1(@babel/core@7.24.5)(react@18.2.0) optionalDependencies: '@next/swc-darwin-arm64': 14.1.0 '@next/swc-darwin-x64': 14.1.0 @@ -6624,6 +8989,8 @@ snapshots: dependencies: whatwg-url: 5.0.0 + node-int64@0.4.0: {} + node-readfiles@0.2.0: dependencies: es6-promise: 3.3.1 @@ -6642,10 +9009,12 @@ snapshots: dependencies: boolbase: 1.0.0 - nuqs@1.17.0(next@14.1.0): + nuqs@1.17.0(next@14.1.0(@babel/core@7.24.5)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)): dependencies: mitt: 3.0.1 - next: 14.1.0(react-dom@18.2.0)(react@18.2.0) + next: 14.1.0(@babel/core@7.24.5)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + + nwsapi@2.2.10: {} oas-kit-common@1.0.8: dependencies: @@ -6776,18 +9145,39 @@ snapshots: - supports-color - typescript + 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: {} + parent-module@1.0.1: dependencies: callsites: 3.1.0 + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.24.2 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + + parse5@7.1.2: + dependencies: + entities: 4.5.0 + path-exists@4.0.0: {} path-is-absolute@1.0.1: {} @@ -6813,6 +9203,10 @@ snapshots: pirates@4.0.6: {} + pkg-dir@4.2.0: + dependencies: + find-up: 4.1.0 + pluralize@8.0.0: {} pony-cause@1.1.1: {} @@ -6831,11 +9225,13 @@ snapshots: camelcase-css: 2.0.1 postcss: 8.4.33 - postcss-load-config@4.0.2(postcss@8.4.33): + postcss-load-config@4.0.2(postcss@8.4.33)(ts-node@10.9.2(@types/node@20.11.5)(typescript@5.3.3)): dependencies: lilconfig: 3.0.0 - postcss: 8.4.33 yaml: 2.3.4 + optionalDependencies: + postcss: 8.4.33 + ts-node: 10.9.2(@types/node@20.11.5)(typescript@5.3.3) postcss-nested@6.0.1(postcss@8.4.33): dependencies: @@ -6878,6 +9274,23 @@ snapshots: prettier@3.2.4: {} + pretty-format@27.5.1: + dependencies: + ansi-regex: 5.0.1 + ansi-styles: 5.2.0 + react-is: 17.0.2 + + 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 + prop-types@15.8.1: dependencies: loose-envify: 1.4.0 @@ -6886,14 +9299,20 @@ snapshots: proxy-from-env@1.1.0: {} + psl@1.9.0: {} + punycode@2.3.1: {} + pure-rand@6.1.0: {} + query-string@9.0.0: dependencies: decode-uri-component: 0.4.1 filter-obj: 5.1.0 split-on-first: 3.0.0 + querystringify@2.2.0: {} + queue-microtask@1.2.3: {} raf@3.4.1: @@ -6912,48 +9331,56 @@ snapshots: react-is@16.13.1: {} + react-is@17.0.2: {} + + react-is@18.3.1: {} + react-property@2.0.2: {} react-remove-scroll-bar@2.3.4(@types/react@18.2.48)(react@18.2.0): dependencies: - '@types/react': 18.2.48 react: 18.2.0 react-style-singleton: 2.2.1(@types/react@18.2.48)(react@18.2.0) tslib: 2.6.2 + optionalDependencies: + '@types/react': 18.2.48 react-remove-scroll@2.5.4(@types/react@18.2.48)(react@18.2.0): dependencies: - '@types/react': 18.2.48 react: 18.2.0 react-remove-scroll-bar: 2.3.4(@types/react@18.2.48)(react@18.2.0) react-style-singleton: 2.2.1(@types/react@18.2.48)(react@18.2.0) tslib: 2.6.2 use-callback-ref: 1.3.1(@types/react@18.2.48)(react@18.2.0) use-sidecar: 1.1.2(@types/react@18.2.48)(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.48 react-remove-scroll@2.5.5(@types/react@18.2.48)(react@18.2.0): dependencies: - '@types/react': 18.2.48 react: 18.2.0 react-remove-scroll-bar: 2.3.4(@types/react@18.2.48)(react@18.2.0) react-style-singleton: 2.2.1(@types/react@18.2.48)(react@18.2.0) tslib: 2.6.2 use-callback-ref: 1.3.1(@types/react@18.2.48)(react@18.2.0) use-sidecar: 1.1.2(@types/react@18.2.48)(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.48 react-style-singleton@2.2.1(@types/react@18.2.48)(react@18.2.0): dependencies: - '@types/react': 18.2.48 get-nonce: 1.0.1 invariant: 2.2.4 react: 18.2.0 tslib: 2.6.2 + optionalDependencies: + '@types/react': 18.2.48 react-use-cookie@1.5.0(react@18.2.0): dependencies: react: 18.2.0 - react-use-measure@2.1.1(react-dom@18.2.0)(react@18.2.0): + react-use-measure@2.1.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: debounce: 1.2.1 react: 18.2.0 @@ -6978,6 +9405,11 @@ snapshots: dependencies: picomatch: 2.3.1 + redent@3.0.0: + dependencies: + indent-string: 4.0.0 + strip-indent: 3.0.0 + reduce-css-calc@1.3.0: dependencies: balanced-match: 0.4.2 @@ -7013,10 +9445,20 @@ snapshots: require-from-string@2.0.2: {} + requires-port@1.0.0: {} + + resolve-cwd@3.0.0: + dependencies: + resolve-from: 5.0.0 + resolve-from@4.0.0: {} + resolve-from@5.0.0: {} + resolve-pkg-maps@1.0.0: {} + resolve.exports@2.0.2: {} + resolve@1.22.8: dependencies: is-core-module: 2.13.1 @@ -7037,7 +9479,7 @@ snapshots: robust-predicates@3.0.2: {} - rooks@7.14.1(react-dom@18.2.0)(react@18.2.0): + rooks@7.14.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: fast-deep-equal: 3.1.3 lodash.debounce: 4.0.8 @@ -7072,6 +9514,12 @@ snapshots: safe-stable-stringify@1.1.1: {} + safer-buffer@2.1.2: {} + + saxes@6.0.0: + dependencies: + xmlchars: 2.2.0 + scheduler@0.23.0: dependencies: loose-envify: 1.4.0 @@ -7149,6 +9597,8 @@ snapshots: dependencies: is-arrayish: 0.3.2 + sisteransi@1.0.5: {} + slash@3.0.0: {} sortablejs@1.15.0: {} @@ -7157,14 +9607,30 @@ snapshots: source-map-js@1.0.2: {} + source-map-support@0.5.13: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.6.1: {} + split-on-first@3.0.0: {} sprintf-js@1.0.3: {} + stack-utils@2.0.6: + dependencies: + escape-string-regexp: 2.0.0 + streamsearch@1.1.0: {} string-argv@0.3.2: {} + 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 @@ -7236,8 +9702,14 @@ snapshots: strip-bom@3.0.0: {} + strip-bom@4.0.0: {} + strip-final-newline@2.0.0: {} + strip-indent@3.0.0: + dependencies: + min-indent: 1.0.1 + strip-json-comments@3.1.1: {} style-to-js@1.1.12: @@ -7248,10 +9720,12 @@ snapshots: dependencies: inline-style-parser: 0.2.3 - styled-jsx@5.1.1(react@18.2.0): + styled-jsx@5.1.1(@babel/core@7.24.5)(react@18.2.0): dependencies: client-only: 0.0.1 react: 18.2.0 + optionalDependencies: + '@babel/core': 7.24.5 sucrase@3.35.0: dependencies: @@ -7263,10 +9737,18 @@ snapshots: pirates: 4.0.6 ts-interface-checker: 0.1.13 + supports-color@5.5.0: + dependencies: + has-flag: 3.0.0 + supports-color@7.2.0: dependencies: has-flag: 4.0.0 + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + supports-preserve-symlinks-flag@1.0.0: {} svg-country-flags@1.2.10: {} @@ -7297,6 +9779,8 @@ snapshots: transitivePeerDependencies: - encoding + symbol-tree@3.2.4: {} + synckit@0.8.8: dependencies: '@pkgr/core': 0.1.1 @@ -7308,11 +9792,11 @@ snapshots: dependencies: '@babel/runtime': 7.23.8 - tailwindcss-animate@1.0.7(tailwindcss@3.4.1): + tailwindcss-animate@1.0.7(tailwindcss@3.4.1(ts-node@10.9.2(@types/node@20.11.5)(typescript@5.3.3))): dependencies: - tailwindcss: 3.4.1 + tailwindcss: 3.4.1(ts-node@10.9.2(@types/node@20.11.5)(typescript@5.3.3)) - tailwindcss@3.4.1: + tailwindcss@3.4.1(ts-node@10.9.2(@types/node@20.11.5)(typescript@5.3.3)): dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 @@ -7331,7 +9815,7 @@ snapshots: postcss: 8.4.33 postcss-import: 15.1.0(postcss@8.4.33) postcss-js: 4.0.1(postcss@8.4.33) - postcss-load-config: 4.0.2(postcss@8.4.33) + postcss-load-config: 4.0.2(postcss@8.4.33)(ts-node@10.9.2(@types/node@20.11.5)(typescript@5.3.3)) postcss-nested: 6.0.1(postcss@8.4.33) postcss-selector-parser: 6.0.15 resolve: 1.22.8 @@ -7341,6 +9825,12 @@ snapshots: tapable@2.2.1: {} + test-exclude@6.0.0: + dependencies: + '@istanbuljs/schema': 0.1.3 + glob: 7.2.3 + minimatch: 3.1.2 + text-table@0.2.0: {} thenify-all@1.6.0: @@ -7353,12 +9843,27 @@ snapshots: timezone-groups@0.8.0: {} + tmpl@1.0.5: {} + + to-fast-properties@2.0.0: {} + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 + tough-cookie@4.1.4: + dependencies: + psl: 1.9.0 + punycode: 2.3.1 + universalify: 0.2.0 + url-parse: 1.5.10 + tr46@0.0.3: {} + tr46@3.0.0: + dependencies: + punycode: 2.3.1 + ts-api-utils@1.0.3(typescript@5.3.3): dependencies: typescript: 5.3.3 @@ -7367,8 +9872,43 @@ snapshots: ts-interface-checker@0.1.13: {} - tsconfck@2.1.2(typescript@5.3.3): + ts-jest@29.1.2(@babel/core@7.24.5)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.5))(jest@29.7.0(@types/node@20.11.5)(ts-node@10.9.2(@types/node@20.11.5)(typescript@5.3.3)))(typescript@5.3.3): + dependencies: + bs-logger: 0.2.6 + fast-json-stable-stringify: 2.1.0 + jest: 29.7.0(@types/node@20.11.5)(ts-node@10.9.2(@types/node@20.11.5)(typescript@5.3.3)) + jest-util: 29.7.0 + json5: 2.2.3 + lodash.memoize: 4.1.2 + make-error: 1.3.6 + semver: 7.5.4 + typescript: 5.3.3 + yargs-parser: 21.1.1 + optionalDependencies: + '@babel/core': 7.24.5 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.24.5) + + ts-node@10.9.2(@types/node@20.11.5)(typescript@5.3.3): dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 20.11.5 + acorn: 8.11.3 + acorn-walk: 8.3.2 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.3.3 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + + tsconfck@2.1.2(typescript@5.3.3): + optionalDependencies: typescript: 5.3.3 tsconfig-paths@3.15.0: @@ -7386,8 +9926,12 @@ snapshots: dependencies: prelude-ls: 1.2.1 + type-detect@4.0.8: {} + type-fest@0.20.2: {} + type-fest@0.21.3: {} + typed-array-buffer@1.0.2: dependencies: call-bind: 1.0.7 @@ -7440,6 +9984,8 @@ snapshots: undici-types@5.26.5: {} + universalify@0.2.0: {} + universalify@2.0.1: {} update-browserslist-db@1.0.13(browserslist@4.22.2): @@ -7454,18 +10000,25 @@ snapshots: urijs@1.19.11: {} + url-parse@1.5.10: + dependencies: + querystringify: 2.2.0 + requires-port: 1.0.0 + use-callback-ref@1.3.1(@types/react@18.2.48)(react@18.2.0): dependencies: - '@types/react': 18.2.48 react: 18.2.0 tslib: 2.6.2 + optionalDependencies: + '@types/react': 18.2.48 use-sidecar@1.1.2(@types/react@18.2.48)(react@18.2.0): dependencies: - '@types/react': 18.2.48 detect-node-es: 1.1.0 react: 18.2.0 tslib: 2.6.2 + optionalDependencies: + '@types/react': 18.2.48 use-sync-external-store@1.2.0(react@18.2.0): dependencies: @@ -7475,10 +10028,39 @@ snapshots: utility-types@3.11.0: {} + v8-compile-cache-lib@3.0.1: {} + + v8-to-istanbul@9.2.0: + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + '@types/istanbul-lib-coverage': 2.0.6 + convert-source-map: 2.0.0 + validator@13.11.0: {} + w3c-xmlserializer@4.0.0: + dependencies: + xml-name-validator: 4.0.0 + + walker@1.0.8: + dependencies: + makeerror: 1.0.12 + webidl-conversions@3.0.1: {} + webidl-conversions@7.0.0: {} + + whatwg-encoding@2.0.0: + dependencies: + iconv-lite: 0.6.3 + + whatwg-mimetype@3.0.0: {} + + whatwg-url@11.0.0: + dependencies: + tr46: 3.0.0 + webidl-conversions: 7.0.0 + whatwg-url@5.0.0: dependencies: tr46: 0.0.3 @@ -7550,6 +10132,17 @@ snapshots: wrappy@1.0.2: {} + write-file-atomic@4.0.2: + dependencies: + imurmurhash: 0.1.4 + signal-exit: 3.0.7 + + ws@8.17.0: {} + + xml-name-validator@4.0.0: {} + + xmlchars@2.2.0: {} + xss@1.0.13: dependencies: commander: 2.20.3 @@ -7557,6 +10150,8 @@ snapshots: y18n@5.0.8: {} + yallist@3.1.1: {} + yallist@4.0.0: {} yaml@1.10.2: {} @@ -7575,6 +10170,8 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 + yn@3.1.1: {} + yocto-queue@0.1.0: {} zod@3.22.4: {} diff --git a/client/src/app/page.tsx b/client/src/app/page.tsx index d4394888..1030fca3 100644 --- a/client/src/app/page.tsx +++ b/client/src/app/page.tsx @@ -9,7 +9,7 @@ import KeyFeatures from "@/containers/home/key-features"; import Vision from "@/containers/home/vision"; export const metadata: Metadata = { - title: "Amazonia360+", + title: "AmazoniaForever360+", description: "", }; diff --git a/client/src/constants/datasets.ts b/client/src/constants/datasets.ts index 0e90f48e..910fd71b 100644 --- a/client/src/constants/datasets.ts +++ b/client/src/constants/datasets.ts @@ -585,7 +585,7 @@ export const DATASETS = { url: null, data: `

Types of land coverages in the AFP's area of work.

Polygon and raster image versions representing land cover in the AFP's work area.

-

Compiled by Amazonia360+ (2023-2024) , from ESA WorldCover project data, consisting of global land cover products at 10 m resolution for 2021, from Sentinel-1 and 2 data. ( https://worldcover2021.esa.int/)

+

Compiled by AmazoniaForever360+ (2023-2024) , from ESA WorldCover project data, consisting of global land cover products at 10 m resolution for 2021, from Sentinel-1 and 2 data. ( https://worldcover2021.esa.int/)

The legend includes 11 generic classes that adequately describe the land surface at 10 m: "Tree cover", "Shrublands", "Grasslands", "Croplands", "Urbanized", "Bare/shrubby vegetation", "Snow and ice", "Permanent water bodies", "Herbaceous wetlands", "Mangroves" and "Mosses and lichens". The portion of the data for northern South America was extracted, sampled and projected to generate a raster and a vector version for testing the zonal viewer assembly.

`, }, @@ -609,7 +609,7 @@ export const DATASETS = { url: null, data: `

Altitudinal and topographic slope ranges of the terrain.

Layers of polygons representing the ranges of altitude above sea level in meters (AFP_ALTIT) and the topographic slope of the terrain in degrees (AFP_SLOP), for the entire in the AFP's work area.

-

Compiled by Amazonia360+, 2023, from Copernicus DEM elevation data which is a Digital Surface Model (DSM) representing the topographic surface of the Earth including buildings, infrastructure and vegetation. In particular, the GLO-30 product has been used, offering global coverage with a resolution of 30 meters. A Copernicus DEM altitude raster layer has been constructed in Amazonia360+, covering northern South America. The original altitude raster data has been sampled and reclassified into classes relevant to agricultural development and forest management, infrastructure installation feasibility, accessibility and flood risk. The two vector layers of altitude and slope were then assembled from this reclassification. +

Compiled by AmazoniaForever360+, 2023, from Copernicus DEM elevation data which is a Digital Surface Model (DSM) representing the topographic surface of the Earth including buildings, infrastructure and vegetation. In particular, the GLO-30 product has been used, offering global coverage with a resolution of 30 meters. A Copernicus DEM altitude raster layer has been constructed in AmazoniaForever360+, covering northern South America. The original altitude raster data has been sampled and reclassified into classes relevant to agricultural development and forest management, infrastructure installation feasibility, accessibility and flood risk. The two vector layers of altitude and slope were then assembled from this reclassification. Copernicus DEM: https://spacedata.copernicus.eu/es/collections/copernicus-digital-elevation-model

`, }, @@ -634,7 +634,7 @@ export const DATASETS = { url: null, data: `

Frequency ranges of forest fires in the AFP work area.

Forest fire frequency classes, based on remotely sensed hot spot and forest fire data.

-

Compiled by Amazonia360+ based on basic data of hot spots and forest fires from: Fire Information for Resource Management System (FIRMS) NASA. +

Compiled by AmazoniaForever360+ based on basic data of hot spots and forest fires from: Fire Information for Resource Management System (FIRMS) NASA. https://firms.modaps.eosdis.nasa.gov/

The historical data of hot spots between March 2014 and March 2024, from the observation of different types of radiometers in Earth orbit, were requested and downloaded. The resulting event cloud was sampled using a 10 km analysis grid for each rectangular cell, covering the entire AFP working area. The centroids were generated with the accumulated events per cell and transformed into a raster image. This was reclassified to obtain event frequency ranges, cells with industrial or geological hot spots were filtered and polygons were generated to represent regions according to the frequency of fires.

`, @@ -712,7 +712,7 @@ export const DATASETS = { url: null, data: `

Estimate of deprivation, deprivation in living conditions in the AFP's work area.

Raster model that represents the levels of multidimensional deprivation in living conditions of the population, by means of an index assigned to each pixel of one kilometer resolution.

-

Adapted by Amazonia360+, 2023, from the Global Relative Deprivation Index (GRDI), v1 (2010-2020) generated by the Socioeconomic Data and Applications Center (SEDAC; NASA, Columbia University) This is a gridded global relative deprivation index that characterizes multidimensional deprivation levels at each pixel with a resolution of ~1 km. The original GRDI dataset is a one-kilometer pixel model, with a value from 0 to 100, where a value of 100 represents the highest level of relative deprivation and a value of 0 the lowest. GRDIv1. It groups weights of six input components, or dimensions, which are combined to determine the degree of relative deprivation. These dimensions consider economic aspects and living conditions data. The original file is: povmap-grdi-v1-grdiv1-geotiff(1).zip; and comes from: +

Adapted by AmazoniaForever360+, 2023, from the Global Relative Deprivation Index (GRDI), v1 (2010-2020) generated by the Socioeconomic Data and Applications Center (SEDAC; NASA, Columbia University) This is a gridded global relative deprivation index that characterizes multidimensional deprivation levels at each pixel with a resolution of ~1 km. The original GRDI dataset is a one-kilometer pixel model, with a value from 0 to 100, where a value of 100 represents the highest level of relative deprivation and a value of 0 the lowest. GRDIv1. It groups weights of six input components, or dimensions, which are combined to determine the degree of relative deprivation. These dimensions consider economic aspects and living conditions data. The original file is: povmap-grdi-v1-grdiv1-geotiff(1).zip; and comes from: Center for International Earth Science Information Network (CIESIN), Columbia University. 2022. Global Gridded Relative Deprivation Index (GRDI), Version 1. Palisades, New York: NASA Socioeconomic Data and Applications Center (SEDAC). https://doi.org/10.7927/3xxe-ap97

`, }, diff --git a/client/src/constants/test.ts b/client/src/constants/test.ts deleted file mode 100644 index 6200bc19..00000000 --- a/client/src/constants/test.ts +++ /dev/null @@ -1,27 +0,0 @@ -export const test = { - in_feature1: { - url: "https://atlas.iadb.org/server/rest/services/Hosted/AFP_GRANDES_CUENCAS_HIDROGRAFICAS_WM/FeatureServer/0", - }, - in_feature2: { - geometryType: "esriGeometryPolygon", - spatialReference: { - wkid: 102100, - latestWkid: 3857, - }, - features: [ - { - geometry: { - rings: [ - [ - [-7854963.494555618, -1087592.177584162], - [-7851414.5472189095, -1108319.7498636711], - [-7867176.101317018, -1109979.2694074556], - [-7867407.801059008, -1096226.5759589653], - [-7854963.494555618, -1087592.177584162], - ], - ], - }, - }, - ], - }, -}; diff --git a/client/src/containers/card/__snapshots__/index.test.tsx.snap b/client/src/containers/card/__snapshots__/index.test.tsx.snap new file mode 100644 index 00000000..4b7cece0 --- /dev/null +++ b/client/src/containers/card/__snapshots__/index.test.tsx.snap @@ -0,0 +1,91 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CardLoader renders CardLoader Children component when query is not fetching 1`] = ` +
+
+ Test +
+
+`; + +exports[`CardLoader renders CardLoader Skeleton component when query is fetching 1`] = ` +
+
+
+`; + +exports[`CardLoader renders CardLoader component without crashing 1`] = ` +
+
+
+`; + +exports[`CardNoData renders CardNoData Children component when query is fetched and there is data 1`] = ` +
+
+ Test +
+
+`; + +exports[`CardNoData renders CardNoData component when query is fetched and no data 1`] = ` +
+
+ No data +

+ No results for this location at the moment. +
+ Feel free to adjust your search criteria or check back later! +

+
+
+`; + +exports[`CardNoData renders CardNoData component without crashing 1`] = ` +
+
+ No data +

+ No results for this location at the moment. +
+ Feel free to adjust your search criteria or check back later! +

+
+
+`; diff --git a/client/src/containers/card/index.test.tsx b/client/src/containers/card/index.test.tsx new file mode 100644 index 00000000..d9e555d9 --- /dev/null +++ b/client/src/containers/card/index.test.tsx @@ -0,0 +1,85 @@ +import { UseQueryResult } from "@tanstack/react-query"; +import { render, screen } from "@testing-library/react"; + +import { CardLoader, CardNoData } from "@/containers/card"; + +describe("CardLoader", () => { + it("renders CardLoader component without crashing", () => { + const { container } = render( + ]} + > +
Test
+
, + ); + expect(container).toMatchSnapshot(); + }); + + it("renders CardLoader Skeleton component when query is fetching", () => { + const { container } = render( + ]} + > +
Test
+
, + ); + expect(container).toMatchSnapshot(); + expect(screen.queryByRole("presentation")).not.toBeInTheDocument(); + }); + + it("renders CardLoader Children component when query is not fetching", () => { + const { container } = render( + ]} + > +
Test
+
, + ); + expect(container).toMatchSnapshot(); + expect(screen.queryByRole("presentation")).toBeInTheDocument(); + }); +}); + +describe("CardNoData", () => { + it("renders CardNoData component without crashing", () => { + const { container } = render( + ]} + > +
Test
+
, + ); + expect(container).toMatchSnapshot(); + }); + + it("renders CardNoData component when query is fetched and no data", () => { + const { container } = render( + , + ]} + > +
Test
+
, + ); + expect(container).toMatchSnapshot(); + expect(screen.queryByRole("presentation")).not.toBeInTheDocument(); + }); + + it("renders CardNoData Children component when query is fetched and there is data", () => { + const { container } = render( + , + ]} + > +
Test
+
, + ); + expect(container).toMatchSnapshot(); + expect(screen.queryByRole("presentation")).toBeInTheDocument(); + }); +}); diff --git a/client/src/containers/card/index.tsx b/client/src/containers/card/index.tsx index 46a639bb..a355ee3e 100644 --- a/client/src/containers/card/index.tsx +++ b/client/src/containers/card/index.tsx @@ -93,7 +93,7 @@ export function CardLoader({ children: React.ReactNode; } & React.HTMLAttributes) { if (query.some((q) => q.isFetching)) { - return ; + return ; } return <>{children}; diff --git a/client/src/containers/disclaimers/data.tsx b/client/src/containers/disclaimers/data.tsx index 9625452c..1189ba93 100644 --- a/client/src/containers/disclaimers/data.tsx +++ b/client/src/containers/disclaimers/data.tsx @@ -6,15 +6,15 @@ export default function DataDisclaimer() {

- The maps, data, and geographic information presented on Amazonia360+ - are provided for reference purposes only and are intended solely to - enhance territorial knowledge of the Amazonia Forever program's - work area. + The maps, data, and geographic information presented on + AmazoniaForever360+ are provided for reference purposes only and are + intended solely to enhance territorial knowledge of the Amazonia + Forever program's work area.

International boundary lines and other administrative delimitations - used by Amazonia360+ are sourced from carefully selected and + used by AmazoniaForever360+ are sourced from carefully selected and well-referenced external sources. However, the original data may have been modified to meet cartographic visualization requirements. The cartographic material presented does not reflect any position @@ -24,7 +24,7 @@ export default function DataDisclaimer() {

This material is not suitable for precision applications, - navigation, or emergency situations. Amazonia360+ and its + navigation, or emergency situations. AmazoniaForever360+ and its affiliates, including the Inter-American Development Bank (IDB), shall not be held liable for any damages, losses, or claims arising from the use of or reliance on the information provided. diff --git a/client/src/containers/disclaimers/demo.tsx b/client/src/containers/disclaimers/demo.tsx index bbfce00a..4ca73f88 100644 --- a/client/src/containers/disclaimers/demo.tsx +++ b/client/src/containers/disclaimers/demo.tsx @@ -6,10 +6,10 @@ export default function DemoDisclaimer() {

- This website is a prototype of Amazonia360+, designed to facilitate - co-creation with select users. The contents and data are for - demonstration purposes only and have not been fully validated yet. - Please refrain from sharing this link, as the functionalities + This website is a prototype of AmazoniaForever360+, designed to + facilitate co-creation with select users. The contents and data are + for demonstration purposes only and have not been fully validated + yet. Please refrain from sharing this link, as the functionalities presented are intended for demonstration and testing purposes only.

diff --git a/client/src/containers/header/__snapshots__/index.test.tsx.snap b/client/src/containers/header/__snapshots__/index.test.tsx.snap new file mode 100644 index 00000000..ce57abe2 --- /dev/null +++ b/client/src/containers/header/__snapshots__/index.test.tsx.snap @@ -0,0 +1,202 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Header renders the Home link selected 1`] = ` + +`; + +exports[`Header renders the Hub link selected 1`] = ` + +`; + +exports[`Header renders the Report Tool link selected 1`] = ` + +`; diff --git a/client/src/containers/header/index.test.tsx b/client/src/containers/header/index.test.tsx new file mode 100644 index 00000000..df60c25c --- /dev/null +++ b/client/src/containers/header/index.test.tsx @@ -0,0 +1,54 @@ +import Header from "@/containers/header"; + +import { render, screen } from "@/jest.utils"; + +const mockUsePathname = jest.fn(); +jest.mock("next/navigation", () => ({ + usePathname() { + return mockUsePathname(); + }, +})); + +describe("Header", () => { + beforeEach(() => { + mockUsePathname.mockReturnValue("/"); + }); + + it("renders Header component without crashing", () => { + render(
); + expect(screen.getByRole("banner")).toBeInTheDocument(); + }); + + it("renders the title", () => { + render(
); + expect(screen.getByText("AmazoniaForever360+")).toBeInTheDocument(); + }); + + it("renders the logo", () => { + render(
); + expect(screen.getByAltText("IDB")).toBeInTheDocument(); + }); + + it("renders the badge", () => { + render(
); + expect(screen.getByText("Prototype")).toBeInTheDocument(); + }); + + // Selected + it("renders the Home link selected", () => { + const { container } = render(
); + expect(container).toMatchSnapshot(); + }); + + it("renders the Report Tool link selected", () => { + mockUsePathname.mockReturnValue("/report"); + const { container } = render(
); + expect(container).toMatchSnapshot(); + }); + + it("renders the Hub link selected", () => { + mockUsePathname.mockReturnValue("/hub"); + const { container } = render(
); + expect(container).toMatchSnapshot(); + }); +}); diff --git a/client/src/containers/header/index.tsx b/client/src/containers/header/index.tsx index 4b26ff50..9818f171 100644 --- a/client/src/containers/header/index.tsx +++ b/client/src/containers/header/index.tsx @@ -18,7 +18,7 @@ export default function Header() {

IDB
- Amazonia360+ + AmazoniaForever360+ Prototype

diff --git a/client/src/containers/home/help.tsx b/client/src/containers/home/help.tsx index b801b0de..640130e6 100644 --- a/client/src/containers/home/help.tsx +++ b/client/src/containers/home/help.tsx @@ -6,13 +6,13 @@ export default function Help() {

- Amazonia360+ goes beyond simply presenting data, it's making - sense of it. Our goal is to become a focal point that unifies and - amplifies the potential of geospatial data and information produced - by partners and initiatives dedicated to the region. By achieving - this, we aim to cultivate a collective intelligence to support the - Amazonia Forever program and its collaboration and coordination - objectives. + AmazoniaForever360+ goes beyond simply presenting data, it's + making sense of it. Our goal is to become a focal point that unifies + and amplifies the potential of geospatial data and information + produced by partners and initiatives dedicated to the region. By + achieving this, we aim to cultivate a collective intelligence to + support the Amazonia Forever program and its collaboration and + coordination objectives.

Help us improve!

diff --git a/client/src/containers/home/hero.tsx b/client/src/containers/home/hero.tsx index c7585d4d..be3c9e09 100644 --- a/client/src/containers/home/hero.tsx +++ b/client/src/containers/home/hero.tsx @@ -14,8 +14,9 @@ export default function Hero() { Understanding Amazonia like never before

- Amazonia360+ is your gateway to - understanding and achieving the greatest impact in this region. + AmazoniaForever360+ is your + gateway to understanding and achieving the greatest impact in this + region.

+
+
+
+
+`; + +exports[`WidgetPopulation renders WidgetPopulation component without crashing 1`] = ` +
+
+
+

+ Population +

+ +
+
+
+ + 100,000 + + + inhabitants + +
+
+
+
+`; diff --git a/client/src/containers/widgets/overview/population.test.tsx b/client/src/containers/widgets/overview/population.test.tsx new file mode 100644 index 00000000..0ddebe3a --- /dev/null +++ b/client/src/containers/widgets/overview/population.test.tsx @@ -0,0 +1,35 @@ +import WidgetPopulation from "@/containers/widgets/overview/population"; + +import { mockUseGetRasterAnalysis } from "@/jest.setup"; +import { render, screen } from "@/jest.utils"; + +describe("WidgetPopulation", () => { + beforeEach(() => { + mockUseGetRasterAnalysis.mockReturnValue({ + data: 100000, + isFetching: false, + isFetched: true, + }); + }); + + test("renders WidgetPopulation component without crashing", async () => { + const { container } = render(); + expect(container).toMatchSnapshot(); + expect(screen.getByRole("banner")).toBeInTheDocument(); + expect(screen.getByText("Population")).toBeInTheDocument(); + expect(screen.getByText("inhabitants")).toBeInTheDocument(); + expect(screen.getByText("100,000")).toBeInTheDocument(); + }); + + test("renders WidgetPopulation component with loading state", async () => { + mockUseGetRasterAnalysis.mockReturnValue({ + data: undefined, + isFetching: true, + isFetched: false, + }); + + const { container } = render(); + expect(container).toMatchSnapshot(); + expect(screen.getByTestId("card-loader")).toBeInTheDocument(); + }); +}); diff --git a/client/src/jest.setup.ts b/client/src/jest.setup.ts new file mode 100644 index 00000000..659b2409 --- /dev/null +++ b/client/src/jest.setup.ts @@ -0,0 +1,153 @@ +import Polygon from "@arcgis/core/geometry/Polygon"; +import { UseQueryResult } from "@tanstack/react-query"; + +import { CustomLocation, SearchLocation } from "@/app/parsers"; + +import "@testing-library/jest-dom"; + +/**************** + * Node modules + ****************/ +jest.mock("query-string", () => ({ + parse: jest.fn(), + stringify: jest.fn(), +})); + +/**************** + * ArcGIS JS API + ****************/ +jest.mock("@arcgis/core/Map", () => class Map {}); +jest.mock("@arcgis/core/views/MapView", () => class MapView {}); +jest.mock( + "@arcgis/core/widgets/Search/SearchViewModel", + () => class SearchViewModel {}, +); + +// Layers +jest.mock("@arcgis/core/layers/FeatureLayer", () => class FeatureLayer {}); +jest.mock("@arcgis/core/layers/WebTileLayer", () => class WebTileLayer {}); +jest.mock("@arcgis/core/layers/GraphicsLayer", () => class GraphicsLayer {}); +jest.mock( + "@arcgis/core/layers/VectorTileLayer", + () => class VectorTileLayer {}, +); +jest.mock("@arcgis/core/layers/GeoJSONLayer", () => class GeoJSONLayer {}); + +jest.mock("@arcgis/core/geometry/Point", () => class Point {}); +jest.mock( + "@arcgis/core/geometry/Polygon", + () => + class Polygon { + static fromJSON() { + return {}; + } + }, +); +jest.mock("@arcgis/core/geometry/Polyline", () => class Polyline {}); +jest.mock("@arcgis/core/Graphic", () => class Graphic {}); + +// Utils, Query and Geometry +jest.mock("@arcgis/core/rest/support/Query", () => class Query {}); +jest.mock( + "@arcgis/core/geometry/geometryEngine", + () => class geometryEngine {}, +); +jest.mock( + "@arcgis/core/geometry/geometryEngineAsync", + () => class geometryEngineAsync {}, +); +jest.mock( + "@arcgis/core/geometry/projection", + () => class geometryEngineAsync {}, +); + +// Renderers +jest.mock( + "@arcgis/core/renderers/SimpleRenderer", + () => class SimpleRenderer {}, +); +jest.mock( + "@arcgis/core/renderers/UniqueValueRenderer", + () => class UniqueValueRenderer {}, +); + +// Symbols +jest.mock( + "@arcgis/core/symbols/SimpleFillSymbol", + () => class SimpleFillSymbol {}, +); +jest.mock( + "@arcgis/core/symbols/SimpleLineSymbol", + () => class SimpleLineSymbol {}, +); +jest.mock( + "@arcgis/core/symbols/SimpleMarkerSymbol", + () => class SimpleMarkerSymbol {}, +); + +/**************** + * STORE + *********************/ +export const mockUseSyncLocation = jest + .fn<[SearchLocation | CustomLocation | null], unknown[]>() + .mockReturnValue([ + { + type: "polygon", + geometry: { + spatialReference: { wkid: 102100 }, + rings: [ + [ + [-7634755.5820374815, -339864.26614880934], + [-7515666.691969208, -615171.3327748701], + [-7937732.852902768, -672040.4818190257], + [-8078033.018320172, -370362.6404345869], + [-7634755.5820374815, -339864.26614880934], + ], + ], + }, + }, + ]); + +jest.mock("@/app/store", () => ({ + useSyncLocation() { + return mockUseSyncLocation(); + }, +})); + +/**************** + * LOCATION + ******************** */ +export const mockUseLocationGeometry = jest + .fn() + .mockReturnValue( + Polygon.fromJSON({ + spatialReference: { wkid: 102100 }, + rings: [ + [ + [-7634755.5820374815, -339864.26614880934], + [-7515666.691969208, -615171.3327748701], + [-7937732.852902768, -672040.4818190257], + [-8078033.018320172, -370362.6404345869], + [-7634755.5820374815, -339864.26614880934], + ], + ], + }), + ); + +jest.mock("@/lib/location", () => ({ + useLocationGeometry: jest.fn(), +})); + +/**************** + * QUERY + ******************** */ +export const mockUseGetRasterAnalysis = jest + .fn, unknown[]>() + .mockReturnValue({ + data: undefined, + isFetching: false, + isFetched: true, + }); +jest.mock("@/lib/query", () => ({ + useGetRasterAnalysis: mockUseGetRasterAnalysis, +})); diff --git a/client/src/jest.utils.tsx b/client/src/jest.utils.tsx new file mode 100644 index 00000000..f0eba638 --- /dev/null +++ b/client/src/jest.utils.tsx @@ -0,0 +1,33 @@ +import React, { ReactElement } from "react"; + +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import { render, RenderOptions } from "@testing-library/react"; + +import { TooltipProvider } from "@/components/ui/tooltip"; + +const createQueryClient = () => { + return new QueryClient({ + defaultOptions: { + queries: { + retry: false, + }, + }, + }); +}; + +const AllTheProviders = ({ children }: { children: React.ReactNode }) => { + const queryClient = createQueryClient(); + return ( + + {children} + + ); +}; + +const customRender = ( + ui: ReactElement, + options?: Omit, +) => render(ui, { wrapper: AllTheProviders, ...options }); + +export * from "@testing-library/react"; +export { customRender as render }; diff --git a/client/src/lib/formats.test.ts b/client/src/lib/formats.test.ts new file mode 100644 index 00000000..52b0c265 --- /dev/null +++ b/client/src/lib/formats.test.ts @@ -0,0 +1,42 @@ +import { formatNumber, formatPercentage, formatCurrency } from "@/lib/formats"; + +describe("formats", () => { + test("formatNumber formats correctly", () => { + expect(formatNumber(123456.789)).toBe("123,456.79"); + expect(formatNumber(0.005)).toBe("~0"); + expect(formatNumber(undefined)).toBe(""); + }); + + test("formatNumber with options formats correctly", () => { + expect(formatNumber(123456.789, { maximumFractionDigits: 0 })).toBe( + "123,457", + ); + expect(formatNumber(0.005, { maximumFractionDigits: 0 })).toBe("~0"); + }); + + test("formatPercentage formats correctly", () => { + expect(formatPercentage(0.123456)).toBe("12.35%"); + expect(formatPercentage(0.0005)).toBe("<1%"); + expect(formatPercentage(undefined)).toBe(""); + }); + + test("formatPercentage with options formats correctly", () => { + expect(formatPercentage(0.123456, { maximumFractionDigits: 0 })).toBe( + "12%", + ); + expect(formatPercentage(0.0005, { maximumFractionDigits: 0 })).toBe("<1%"); + }); + + test("formatCurrency formats correctly", () => { + expect(formatCurrency(123456.789)).toBe("$123,456.79"); + expect(formatCurrency(0.005)).toBe("~0"); + expect(formatCurrency(undefined)).toBe(""); + }); + + test("formatCurrency with options formats correctly", () => { + expect(formatCurrency(123456.789, { maximumFractionDigits: 0 })).toBe( + "$123,457", + ); + expect(formatCurrency(0.005, { maximumFractionDigits: 0 })).toBe("~0"); + }); +}); diff --git a/client/src/lib/images.test.ts b/client/src/lib/images.test.ts new file mode 100644 index 00000000..8f8e9ab6 --- /dev/null +++ b/client/src/lib/images.test.ts @@ -0,0 +1,21 @@ +import { shimmer, toBase64, PLACEHOLDER } from "./images"; + +describe("images", () => { + test("shimmer generates correct SVG", () => { + const svg = shimmer(100, 200); + expect(svg).toContain(''); + expect(svg).toContain( + '', + ); + }); + + test("toBase64 encodes correctly", () => { + expect(toBase64("hello")).toBe("aGVsbG8="); + }); + + test("PLACEHOLDER generates correct data URL", () => { + const placeholder = PLACEHOLDER(100, 200); + expect(placeholder).toMatch(/^data:image\/svg\+xml;base64,/); + }); +}); diff --git a/client/src/lib/images.ts b/client/src/lib/images.ts index acc4e98f..43bd4983 100644 --- a/client/src/lib/images.ts +++ b/client/src/lib/images.ts @@ -1,6 +1,6 @@ "#004466"; -const shimmer = (w: number, h: number) => ` +export const shimmer = (w: number, h: number) => ` @@ -14,7 +14,7 @@ const shimmer = (w: number, h: number) => ` `; -const toBase64 = (str: string) => +export const toBase64 = (str: string) => typeof window === "undefined" ? Buffer.from(str).toString("base64") : window.btoa(str); diff --git a/client/src/lib/search.ts b/client/src/lib/search.ts index 75f529bb..a4df3699 100644 --- a/client/src/lib/search.ts +++ b/client/src/lib/search.ts @@ -1,4 +1,4 @@ -import * as projection from "@arcgis/core/geometry/projection.js"; +import * as projection from "@arcgis/core/geometry/projection"; import SearchVM from "@arcgis/core/widgets/Search/SearchViewModel"; import { MutationFunction, diff --git a/client/src/lib/utils.test.ts b/client/src/lib/utils.test.ts new file mode 100644 index 00000000..bc0bcdec --- /dev/null +++ b/client/src/lib/utils.test.ts @@ -0,0 +1,58 @@ +import { + cn, + getKeys, + joinWithAnd, + convertHexToRgbaArray, + getTextSize, +} from "./utils"; + +const mockWindow = jest.spyOn(global, "window", "get") as jest.SpyInstance< + (Window & typeof globalThis) | undefined, + [], + unknown +>; +const mockWindowDocument = jest.spyOn(global.document, "createElement"); + +describe("utils", () => { + test("cn merges class names correctly", () => { + expect(cn("class1", "class2")).toBe("class1 class2"); + expect(cn("class1", undefined, "class2")).toBe("class1 class2"); + }); + + test("getKeys gets keys of an object", () => { + expect(getKeys({ a: 1, b: 2 })).toEqual(["a", "b"]); + }); + + test('joinWithAnd joins strings with "and"', () => { + expect(joinWithAnd(["a", "b", "c"])).toBe("a, b and c"); + expect(joinWithAnd(["a", "b"])).toBe("a and b"); + expect(joinWithAnd(["a"])).toBe("a"); + expect(joinWithAnd([])).toBe(""); + }); + + test("convertHexToRgbaArray converts hex color to RGBA array", () => { + expect(convertHexToRgbaArray("#ff0000")).toEqual([255, 0, 0, 255]); + expect(convertHexToRgbaArray("#00ff00", 0.5)).toEqual([0, 255, 0, 127.5]); + }); + + test("getTextSize gets text size", () => { + mockWindowDocument.mockReturnValue({ + getContext: () => ({ + font: "", + measureText: () => ({ width: 100 }), + }), + remove: jest.fn(), + } as unknown as HTMLElement); + + const textSize = getTextSize({ text: "hello", maxWidth: 100 }); + expect(textSize.width).toBeGreaterThan(0); + expect(textSize.height).toBeGreaterThan(0); + }); + + test("getTextSize returns 0 if window is undefined", () => { + mockWindow.mockReturnValue(undefined); + const textSize = getTextSize({ text: "hello", maxWidth: 100 }); + expect(textSize.width).toBe(0); + expect(textSize.height).toBe(0); + }); +}); diff --git a/client/src/types/generated/api.schemas.ts b/client/src/types/generated/api.schemas.ts index 75eb0cb7..5ef630bb 100644 --- a/client/src/types/generated/api.schemas.ts +++ b/client/src/types/generated/api.schemas.ts @@ -1,7 +1,7 @@ /** * Generated by orval v6.26.0 🍺 * Do not edit manually. - * Amazonia360 API + * AmazoniaForever360 API * OpenAPI spec version: 0.1.0 */ export type TilejsonTilejsonJsonGetColormapName = diff --git a/client/src/types/generated/default.ts b/client/src/types/generated/default.ts index 3ad907e8..2dfd28c7 100644 --- a/client/src/types/generated/default.ts +++ b/client/src/types/generated/default.ts @@ -1,7 +1,7 @@ /** * Generated by orval v6.26.0 🍺 * Do not edit manually. - * Amazonia360 API + * AmazoniaForever360 API * OpenAPI spec version: 0.1.0 */ import { API } from "../../services/api"; diff --git a/client/tsconfig.json b/client/tsconfig.json index e2e6f0f4..1b9996b3 100644 --- a/client/tsconfig.json +++ b/client/tsconfig.json @@ -22,6 +22,6 @@ "@/*": ["./src/*"] } }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", "src/jest.setup.ts", "jest.config.ts"], "exclude": ["node_modules"] } diff --git a/docker-compose.yml b/docker-compose.yml index 32aa700e..fffa746f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,19 +10,15 @@ services: environment: - AUTH_TOKEN=${AUTH_TOKEN} - TIFF_PATH=${TIFF_PATH} + - GRID_TILES_PATH=${GRID_TILES_PATH} networks: - amazonia360-network - restart: - always - + restart: always test: build: context: ./api dockerfile: Dockerfile target: development - environment: - - AUTH_TOKEN=secret - - TIFF_PATH=/opt/api/test_data networks: - amazonia360-network diff --git a/infrastructure/README.md b/infrastructure/README.md index 64db2e37..b301541d 100644 --- a/infrastructure/README.md +++ b/infrastructure/README.md @@ -1,4 +1,4 @@ -### Amazonia 360 backend infrastructure +### Amazonia 360+ backend infrastructure This terraform project creates the following resources: @@ -10,7 +10,7 @@ This terraform project creates the following resources: - AWS Certificate Manager certificate for the load balancer - Route 53 record set on main account to point to the load balancer -We are using for now the default profile in aws, which holds the credentials for the test user under de vizz backend sandbox. +We are using for now the default profile in aws, which holds the credentials for the test user under de vizz backend sandbox. THis needs to be updated accordingly By default, the vpc exposes the port 8000 to the internet, where the api will be running @@ -21,4 +21,4 @@ For the ssh access to the EC2, a key pair is created, which the public key is in To grant access to aditional users, a `user_data` block needs to be added to the ec2 instance adding the authorized keys for the users. Sensitive data is stored in the `local.tfvars` file, which is not versioned. A copy of this file is available in the usual place for sensitive data. -The file `terraform.tfvars` is versioned and should only holds the definitions of the variables, not the values. \ No newline at end of file +The file `terraform.tfvars` is versioned and should only holds the definitions of the variables, not the values. diff --git a/infrastructure/main.tf b/infrastructure/main.tf index 178496a7..31fde066 100644 --- a/infrastructure/main.tf +++ b/infrastructure/main.tf @@ -6,18 +6,20 @@ terraform { } } -# backend "s3" { -# region = "eu-west-3" -# key = "core.tfstate" -# dynamodb_table = "tf-lock-state" -# encrypt = true -# bucket = "amazonioa360-tfstate-bucket" -# } + backend "s3" { + region = "eu-west-3" + key = "core.tfstate" + dynamodb_table = "tf-lock-state" + encrypt = true + profile = "amazonia360" + bucket = "amazonioa360-tfstate-bucket" + } } module "ec2" { source = "./modules/ec2" + environment = "prod" ami = "ami-0db612899f2542162" instance_type = "t2.large" subnet_id = module.vpc.subnet_id @@ -27,11 +29,25 @@ module "ec2" { authorized_key = var.authorized_key } + +module "ec2-dev" { + source = "./modules/ec2" + environment = "dev" + ami = "ami-0db612899f2542162" + instance_type = "t2.small" + subnet_id = module.vpc.subnet_id + instance_name = "amazonia360-ec2-dev" + security_group_ids = [module.vpc.security_group_id] + ec2_public_key = var.ec2_public_key + authorized_key = var.authorized_key +} + module "vpc" { source = "./modules/vpc" vpc_cidr_block = "10.0.0.0/16" vpc_name = "amazonia360-vpc" ec2_instance_id = module.ec2.instance_id + ec2_dev_instance_id = module.ec2-dev.instance_id } module "s3" { diff --git a/infrastructure/modules/ec2/main.tf b/infrastructure/modules/ec2/main.tf index 1041a82f..36649138 100644 --- a/infrastructure/modules/ec2/main.tf +++ b/infrastructure/modules/ec2/main.tf @@ -18,6 +18,6 @@ resource "aws_instance" "amazonia360-ec2" { resource "aws_key_pair" "local_public_key" { - key_name = "amazonia360-key-pair" + key_name = "amazonia360-key-pair-${var.environment}" public_key = file("~/.ssh/key_amazonia360_ec2.pub") } diff --git a/infrastructure/modules/ec2/variables.tf b/infrastructure/modules/ec2/variables.tf index a6487fe2..af49f01f 100644 --- a/infrastructure/modules/ec2/variables.tf +++ b/infrastructure/modules/ec2/variables.tf @@ -34,4 +34,9 @@ variable "ec2_public_key" { variable "authorized_key"{ type = string description = "Public key to be added to the authorized_keys file of the ec2-user" +} + +variable "environment" { + type = string + description = "Environment for the EC2 instance" } \ No newline at end of file diff --git a/infrastructure/modules/vpc/main.tf b/infrastructure/modules/vpc/main.tf index d9ad8e32..f574208e 100644 --- a/infrastructure/modules/vpc/main.tf +++ b/infrastructure/modules/vpc/main.tf @@ -111,6 +111,16 @@ resource "aws_lb" "load_balancer" { enable_deletion_protection = false } +resource "aws_lb" "dev_load_balancer" { + name = "dev-amazonia360-load-balancer" + internal = false + load_balancer_type = "application" + security_groups = [aws_security_group.amazonia360-sg.id] + subnets = [aws_subnet.amazonia360-subnet.id, aws_subnet.amazonia360-subnet2.id] + + enable_deletion_protection = false +} + resource "aws_lb_target_group" "my_target_group" { @@ -126,6 +136,19 @@ resource "aws_lb_target_group" "my_target_group" { } } +resource "aws_lb_target_group" "dev_my_target_group" { + name = "dev-amazonia-target-group" + port = 8000 + protocol = "HTTP" + vpc_id = aws_vpc.amazonia360-vpc.id + + health_check { + enabled = true + path = "/health" + protocol = "HTTP" + } +} + resource "aws_lb_target_group_attachment" "my_target_group_attachment" { target_group_arn = aws_lb_target_group.my_target_group.arn @@ -133,6 +156,15 @@ resource "aws_lb_target_group_attachment" "my_target_group_attachment" { port = 8000 } +resource "aws_lb_target_group_attachment" "dev_my_target_group_attachment" { + target_group_arn = aws_lb_target_group.dev_my_target_group.arn + target_id = var.ec2_dev_instance_id + port = 8000 +} + + + + resource "aws_lb_listener" "https_listener" { load_balancer_arn = aws_lb.load_balancer.arn @@ -147,6 +179,19 @@ resource "aws_lb_listener" "https_listener" { } } +resource "aws_lb_listener" "dev_https_listener" { + load_balancer_arn = aws_lb.dev_load_balancer.arn + port = 443 + protocol = "HTTPS" + ssl_policy = "ELBSecurityPolicy-2016-08" + certificate_arn = aws_acm_certificate.dev-acm_certificate.arn + + default_action { + type = "forward" + target_group_arn = aws_lb_target_group.dev_my_target_group.arn + } +} + ## Certificate @@ -164,6 +209,27 @@ resource "aws_acm_certificate" "acm_certificate" { } } +resource "aws_acm_certificate" "dev-acm_certificate" { + domain_name = "dev.api.amazonia360.dev-vizzuality.com" + validation_method = "DNS" + + tags = { + Name = "Amazonia360 API SSL certificate" + } + + lifecycle { + create_before_destroy = true + } +} + + + +resource "aws_acm_certificate_validation" "domain_certificate_validation" { + certificate_arn = aws_acm_certificate.dev-acm_certificate.arn +} + + + # # resource "aws_acm_certificate_validation" "domain_certificate_validation" { # certificate_arn = aws_acm_certificate.acm_certificate.arn diff --git a/infrastructure/modules/vpc/variables.tf b/infrastructure/modules/vpc/variables.tf index 37c9cc7d..d324ce70 100644 --- a/infrastructure/modules/vpc/variables.tf +++ b/infrastructure/modules/vpc/variables.tf @@ -13,4 +13,9 @@ variable "vpc_name" { variable "ec2_instance_id"{ type = string description = "ID of the EC2 instance" +} + +variable "ec2_dev_instance_id"{ + type = string + description = "ID of the DEV EC2 instance" } \ No newline at end of file diff --git a/science/notebooks/check_combine_results.ipynb b/science/notebooks/check_combine_results.ipynb new file mode 100644 index 00000000..415aadc9 --- /dev/null +++ b/science/notebooks/check_combine_results.ipynb @@ -0,0 +1,95 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "0", + "metadata": {}, + "outputs": [], + "source": [ + "import polars as pl" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1", + "metadata": {}, + "outputs": [], + "source": [ + "df = pl.read_ipc(\"../data/processed/grid/0/8057fffffffffff.arrow\")\n", + "df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2", + "metadata": {}, + "outputs": [], + "source": [ + "schema = {\"cell\": pl.UInt64, \"b\": pl.Float32, \"c\": pl.String}\n", + "df = pl.DataFrame(schema=schema)\n", + "\n", + "join1 = pl.DataFrame({\"cell\": [1, 2, 3], \"b\": [9.0, 9.0, 9.0]}, schema_overrides=schema)\n", + "join2 = pl.DataFrame({\"cell\": [1, 2, 3], \"c\": [\"a\", \"b\", \"c\"]}, schema_overrides=schema)\n", + "join3 = pl.DataFrame({\"cell\": [4, 5, 6], \"c\": [\"a\", \"b\", \"c\"]}, schema_overrides=schema)\n", + "\n", + "tojoin = [join1, join2, join3]\n", + "\n", + "res = pl.concat(tojoin, how=\"diagonal\", rechunk=True)\n", + "res = res.group_by(\"cell\", maintain_order=True).agg(pl.all().max())\n", + "print(res)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3", + "metadata": {}, + "outputs": [], + "source": [ + "import polars as pl\n", + "\n", + "# Define the initial DataFrame\n", + "df = pl.DataFrame(\n", + " {\n", + " \"cell\": [1, 2, 3, 1, 2, 3, 4, 5, 6],\n", + " \"b\": [9.0, 9.0, 9.0, None, None, None, None, None, None],\n", + " \"c\": [None, None, None, \"a\", \"b\", \"c\", \"a\", \"b\", \"c\"],\n", + " }\n", + ")\n", + "\n", + "# Perform the group by and aggregation\n", + "agg_df = df.groupby(\"cell\").agg([pl.col(\"b\").max().alias(\"b\"), pl.col(\"c\").max().alias(\"c\")])\n", + "\n", + "# Sort the resulting DataFrame by the 'cell' column\n", + "result_df = agg_df.sort(\"cell\")\n", + "\n", + "# Print the resulting DataFrame\n", + "print(result_df)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.4" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/science/notebooks/grid_table_geometry.ipynb b/science/notebooks/grid_table_geometry.ipynb new file mode 100644 index 00000000..85c60c6d --- /dev/null +++ b/science/notebooks/grid_table_geometry.ipynb @@ -0,0 +1,70 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "0", + "metadata": {}, + "outputs": [], + "source": [ + "import polars as pl\n", + "from h3ronpy.polars.vector import cells_to_wkb_points\n", + "from shapely import wkb" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1", + "metadata": {}, + "outputs": [], + "source": [ + "df = pl.read_csv(\"../data/processed/grid_table.csv\")\n", + "\n", + "df = df.with_columns(\n", + " pl.col(\"cell\").cast(pl.UInt64).h3.cells_to_string(),\n", + " pl.col(\"tile_id\").cast(pl.UInt64).h3.cells_to_string(),\n", + " point=cells_to_wkb_points(df.select(pl.col(\"cell\").cast(pl.UInt64)).to_series()),\n", + ")\n", + "df = df.with_columns(\n", + " lat=pl.col(\"point\").map_elements(lambda p: wkb.loads(p).x, return_dtype=pl.Float64),\n", + " lon=pl.col(\"point\").map_elements(lambda p: wkb.loads(p).y, return_dtype=pl.Float64),\n", + ")\n", + "\n", + "df = df.drop(\"point\")\n", + "df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2", + "metadata": {}, + "outputs": [], + "source": [ + "df.write_csv(\"../data/processed/grid_table_geom.csv\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/science/notebooks/merge_entrega_roberto.ipynb b/science/notebooks/merge_entrega_roberto.ipynb new file mode 100644 index 00000000..f1ea486d --- /dev/null +++ b/science/notebooks/merge_entrega_roberto.ipynb @@ -0,0 +1,167 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from pathlib import Path\n", + "\n", + "import polars as pl" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "csvs = list(Path(\"../data/raw/ENTREGA UNO MUESTRAS HEXA CSV 18072024\").glob(\"*.CSV\"))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "dfs = [pl.read_csv(f, separator=\";\", decimal_comma=True) for f in csvs]\n", + "df = pl.concat(dfs, how=\"align\", rechunk=True)\n", + "df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df = df.with_columns(pl.col(\"GRID_ID\").h3.cells_parse())\n", + "df = df.drop(\"GRID_ID\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df.select(pl.col(\"cell\").h3.cells_resolution()).unique()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "CELLS_RES = 6\n", + "OVERVIEW_LEVEL = CELLS_RES - 5\n", + "\n", + "df = df.with_columns(\n", + " pl.col(\"cell\").h3.change_resolution(OVERVIEW_LEVEL).h3.cells_to_string().alias(\"tile_id\"), # type: ignore[attr-defined]\n", + " pl.col(\"cell\").h3.cells_to_string(),\n", + ")\n", + "partition_dfs = df.partition_by([\"tile_id\"], as_dict=True, include_key=False)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Write tiles to IPC files" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "seen_tiles = set()\n", + "n_cells = 0\n", + "\n", + "for tile_group, tile_df in partition_dfs.items():\n", + " if tile_df.shape[0] == 0: # todo: skip empty tiles ?\n", + " continue\n", + " tile_id = tile_group[0]\n", + " filename = Path(\"../data/processed/grid/1\") / (tile_id + \".arrow\")\n", + " if tile_id in seen_tiles:\n", + " tile_df = pl.concat([pl.read_ipc(filename), tile_df], how=\"vertical_relaxed\").unique(\n", + " subset=[\"cell\"]\n", + " )\n", + " tile_df.write_parquet(filename)\n", + " n_cells += len(tile_df)\n", + " else:\n", + " seen_tiles.add(tile_id)\n", + " tile_df.write_ipc(filename)\n", + " n_cells += len(tile_df)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Make the metadata" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df.select(pl.all().min())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df.select(pl.all().max())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df.columns" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df.dtypes" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.4" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/science/pyproject.toml b/science/pyproject.toml new file mode 100644 index 00000000..079f973f --- /dev/null +++ b/science/pyproject.toml @@ -0,0 +1,24 @@ +[tool.ruff] +line-length = 100 +extend-include = ["*.ipynb"] +src = ["src"] + +[tool.ruff.lint] +select = [ + "D1", # pydocstyle errors + "E", # pycodestyle errors + "W", # pycodestyle warnings + "F", # flake8 + "C", # flake8-comprehensions + "B", # flake8-bugbear + "N", # Naming conventions + "I", # isort +] +ignore = [ + "D100", # Missing docstring in public module + "D104", # Missing docstring in __init__ + "C901", # Too complex +] + +[tool.ruff.lint.per-file-ignores] +"**/{tests}/*" = ["D103"] # Missing docstring in public function diff --git a/science/requirements.in b/science/requirements.in new file mode 100644 index 00000000..8202ff15 --- /dev/null +++ b/science/requirements.in @@ -0,0 +1,5 @@ +h3 +polars +h3ronpy +click +rasterio diff --git a/science/requirements.txt b/science/requirements.txt new file mode 100644 index 00000000..9333a96f --- /dev/null +++ b/science/requirements.txt @@ -0,0 +1,38 @@ +# This file was autogenerated by uv via the following command: +# uv pip compile requirements.in -o requirements.txt +affine==2.4.0 + # via rasterio +attrs==23.2.0 + # via rasterio +certifi==2024.6.2 + # via rasterio +click==8.1.7 + # via + # click-plugins + # cligj + # rasterio +click-plugins==1.1.1 + # via rasterio +cligj==0.7.2 + # via rasterio +h3==3.7.7 +h3ronpy==0.20.2 +numpy==1.26.4 + # via + # h3ronpy + # pyarrow + # rasterio + # shapely + # snuggs +polars==0.20.31 +pyarrow==16.1.0 + # via h3ronpy +pyparsing==3.1.2 + # via snuggs +rasterio==1.3.10 +setuptools==70.0.0 + # via rasterio +shapely==2.0.4 + # via h3ronpy +snuggs==1.4.7 + # via rasterio diff --git a/science/src/__init__.py b/science/src/__init__.py new file mode 100644 index 00000000..e69de29b