diff --git a/.fallowrc.jsonc b/.fallowrc.jsonc
deleted file mode 100644
index de25fe1f..00000000
--- a/.fallowrc.jsonc
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "$schema": "https://raw.githubusercontent.com/fallow-rs/fallow/main/schema.json",
- // Generated code (@hey-api/openapi-ts client, TanStack route tree) stays in the
- // module graph so imports resolve, but its findings are hidden.
- "ignoreFindings": ["frontend/src/client/**", "**/*.gen.ts"],
- "duplicates": {
- "ignore": ["frontend/src/client/**", "**/*.gen.ts"]
- },
- "health": {
- "ignore": ["frontend/src/client/**", "**/*.gen.ts"]
- }
-}
diff --git a/.vscode/settings.json b/.vscode/settings.json
index dd665e2c..6bb1b9fe 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -4,6 +4,7 @@
"makefile.configureOnOpen": false,
"biome.configurationPath": "frontend/biome.json",
"biome.lsp.bin": "frontend/node_modules/.bin/biome",
+ "fallow.configPath": "frontend/.fallowrc.jsonc",
"editor.codeActionsOnSave": {
"source.fixAll.biome": "explicit",
"source.organizeImports.biome": "explicit"
diff --git a/Makefile b/Makefile
index fc9908ae..6c55cf4c 100644
--- a/Makefile
+++ b/Makefile
@@ -50,6 +50,10 @@ setup: ## Setup the backend and frontend
generate-metadata: ## Generate diagnostic metadata YAML from provider registry
$(MAKE) -C backend generate-metadata
+.PHONY: fallow-audit
+fallow-audit: ## run tests with coverage, then audit frontend changes against main with fallow
+ cd frontend && npm run test:coverage && npm run fallow:audit
+
.PHONY: changelog-draft
changelog-draft: ## compile a draft of the next changelog
cd backend && uv run towncrier build --draft --config ../towncrier.toml
diff --git a/backend/ruff.toml b/backend/ruff.toml
index 1301f496..80c4d6cc 100644
--- a/backend/ruff.toml
+++ b/backend/ruff.toml
@@ -13,6 +13,8 @@ select = [
"RUF",
"UP",
"S",
+ "C90",
+ "C4",
]
unfixable = [
"PD002",
@@ -26,8 +28,13 @@ ignore = [
"D200",
"D400",
"UP007",
+ "C408", # dict(key=value) calls read as well as literals
]
+[lint.mccabe]
+# Flags functions with more independent paths than a reader can comfortably follow
+max-complexity = 10
+
[lint.per-file-ignores]
"test*.py" = [
"D", # Documentation not needed in tests
diff --git a/backend/src/ref_backend/api/routes/diagnostics.py b/backend/src/ref_backend/api/routes/diagnostics.py
index 9aa2d833..f516fb1f 100644
--- a/backend/src/ref_backend/api/routes/diagnostics.py
+++ b/backend/src/ref_backend/api/routes/diagnostics.py
@@ -1,4 +1,4 @@
-from typing import Literal
+from typing import Literal, NamedTuple
from fastapi import APIRouter, HTTPException, Query, Request
from sqlalchemy import ColumnElement, Integer, func, select
@@ -92,6 +92,18 @@ def _group_scope(
return group_scope
+def _scoped_diagnostics(
+ app_context: AppContextDep, mip_era: str | None, source_id: str | None
+) -> tuple[list[models.Diagnostic], list[ColumnElement[bool]]]:
+ """
+ Get the listed diagnostics, with the scope that counts their groups for `mip_era` and `source_id`
+
+ Without any listed diagnostic the scope matches no group, so the counts come out empty.
+ """
+ diagnostics = _listed_diagnostics(app_context)
+ return diagnostics, _group_scope([d.id for d in diagnostics], mip_era, source_id)
+
+
def _diagnostics_with_values(
app_context: AppContextDep, value_class: type[models.MetricValue], group_scope: list[ColumnElement[bool]]
) -> set[int]:
@@ -105,6 +117,20 @@ def _diagnostics_with_values(
return {row[0] for row in rows}
+class _ValueTypes(NamedTuple):
+ """The ids of the diagnostics with scalar values and of those with series values"""
+
+ scalar: set[int]
+ series: set[int]
+
+
+def _value_types(app_context: AppContextDep, group_scope: list[ColumnElement[bool]]) -> _ValueTypes:
+ return _ValueTypes(
+ scalar=_diagnostics_with_values(app_context, models.ScalarMetricValue, group_scope),
+ series=_diagnostics_with_values(app_context, models.SeriesMetricValue, group_scope),
+ )
+
+
def _catalog_entries(
app_context: AppContextDep, diagnostics: list[models.Diagnostic], group_scope: list[ColumnElement[bool]]
) -> list[DiagnosticCatalogEntry]:
@@ -188,19 +214,14 @@ async def _list(
Pass `mip_era` to count only the execution groups that ran against that era,
and `source_id` to count only those that ran against that model.
"""
- diagnostics = _listed_diagnostics(app_context)
- if not diagnostics:
- return Collection(data=[])
-
- group_scope = _group_scope([d.id for d in diagnostics], mip_era, source_id)
- scalar_ids = _diagnostics_with_values(app_context, models.ScalarMetricValue, group_scope)
- series_ids = _diagnostics_with_values(app_context, models.SeriesMetricValue, group_scope)
+ diagnostics, group_scope = _scoped_diagnostics(app_context, mip_era, source_id)
+ value_types = _value_types(app_context, group_scope)
return Collection(
data=[
DiagnosticSummary.from_catalog_entry(
entry,
- has_scalar_values=entry.id in scalar_ids,
- has_series_values=entry.id in series_ids,
+ has_scalar_values=entry.id in value_types.scalar,
+ has_series_values=entry.id in value_types.series,
)
for entry in _catalog_entries(app_context, diagnostics, group_scope)
]
@@ -219,11 +240,7 @@ async def catalog(
Pass `mip_era` and `source_id` to count only the execution groups that ran against that era or model.
"""
- diagnostics = _listed_diagnostics(app_context)
- if not diagnostics:
- return Collection(data=[])
-
- group_scope = _group_scope([d.id for d in diagnostics], mip_era, source_id)
+ diagnostics, group_scope = _scoped_diagnostics(app_context, mip_era, source_id)
return Collection(data=_catalog_entries(app_context, diagnostics, group_scope))
@@ -236,20 +253,15 @@ async def value_flags(
These are the flags `/diagnostics/catalog` leaves out.
"""
- diagnostics = _listed_diagnostics(app_context)
- if not diagnostics:
- return Collection(data=[])
-
- group_scope = _group_scope([d.id for d in diagnostics], mip_era, source_id)
- scalar_ids = _diagnostics_with_values(app_context, models.ScalarMetricValue, group_scope)
- series_ids = _diagnostics_with_values(app_context, models.SeriesMetricValue, group_scope)
+ diagnostics, group_scope = _scoped_diagnostics(app_context, mip_era, source_id)
+ value_types = _value_types(app_context, group_scope)
return Collection(
data=[
DiagnosticValueFlags(
id=d.id,
- has_metric_values=d.id in scalar_ids or d.id in series_ids,
- has_scalar_values=d.id in scalar_ids,
- has_series_values=d.id in series_ids,
+ has_metric_values=d.id in value_types.scalar or d.id in value_types.series,
+ has_scalar_values=d.id in value_types.scalar,
+ has_series_values=d.id in value_types.series,
)
for d in diagnostics
]
diff --git a/backend/src/ref_backend/core/filter_utils.py b/backend/src/ref_backend/core/filter_utils.py
index 162ae7b4..71511137 100644
--- a/backend/src/ref_backend/core/filter_utils.py
+++ b/backend/src/ref_backend/core/filter_utils.py
@@ -14,21 +14,16 @@ def _normalize_list_from_value(value: Any) -> list[str] | None:
Returns None if the input should be treated as a single value (no list semantics).
"""
- if value is None:
- return None
-
- # If already a list (e.g. from parsed JSON), coerce & clean
if isinstance(value, list):
- vals = [str(v).strip() for v in value if v is not None and str(v).strip()]
- return vals if vals else None
-
- # If a comma-separated string, split and clean
- if isinstance(value, str) and "," in value:
- vals = [v.strip() for v in value.split(",") if v.strip()]
- return vals if vals else None
+ # e.g. from parsed JSON
+ items = [str(v) for v in value if v is not None]
+ elif isinstance(value, str) and "," in value:
+ items = value.split(",")
+ else:
+ return None
- # Otherwise, treat as a single scalar value
- return None
+ vals = [item.strip() for item in items if item.strip()]
+ return vals or None
def build_filter_clause(column: Any, value: Any) -> BinaryExpression[Any]:
@@ -40,27 +35,15 @@ def build_filter_clause(column: Any, value: Any) -> BinaryExpression[Any]:
an `IN` clause is returned.
- If `value` contains exactly one normalized item, a simple equality
(`column == item`) is returned.
- - Otherwise, fall back to equality with the original `value`.
+ - Otherwise, fall back to equality with the original `value`,
+ including for an empty list.
This function is intended to be used in route handlers where query values
may be single values, comma-separated strings, or parsed JSON lists.
"""
- # Handle lists explicitly
- if isinstance(value, list):
- vals = _normalize_list_from_value(value)
- if vals is None:
- # Empty list -> fallback equality (keeps prior behavior)
- return column == value
- if len(vals) == 1:
- return column == vals[0]
- return column.in_(vals)
-
- # Handle comma-separated strings or other scalars
vals = _normalize_list_from_value(value)
- if vals:
- if len(vals) == 1:
- return column == vals[0]
- return column.in_(vals)
-
- # Default: equality
- return column == value
+ if vals is None:
+ return column == value
+ if len(vals) == 1:
+ return column == vals[0]
+ return column.in_(vals)
diff --git a/backend/src/ref_backend/core/reader_values.py b/backend/src/ref_backend/core/reader_values.py
index 089cb14c..cdab9798 100644
--- a/backend/src/ref_backend/core/reader_values.py
+++ b/backend/src/ref_backend/core/reader_values.py
@@ -2,8 +2,8 @@
import csv
import io
-from collections.abc import Generator, Mapping
-from typing import TYPE_CHECKING, Literal
+from collections.abc import Generator, Iterable, Mapping, Sequence
+from typing import TYPE_CHECKING, Any, Literal
from fastapi import HTTPException
from starlette.responses import StreamingResponse
@@ -31,6 +31,46 @@ def parse_dimension_filters(query_params: Mapping[str, str]) -> dict[str, str]:
return {key: value for key, value in query_params.items() if key in cv_dimensions}
+def _csv_response(
+ rows: Iterable[Sequence[Any]], filename: str, headers: Mapping[str, str] | None = None
+) -> StreamingResponse:
+ """Stream `rows` as a CSV download, writing each row as it is produced."""
+
+ def generate_csv() -> Generator[str]:
+ output = io.StringIO()
+ writer = csv.writer(output)
+ for row in rows:
+ writer.writerow(row)
+ yield output.getvalue()
+ output.seek(0)
+ output.truncate()
+
+ return StreamingResponse(
+ generate_csv(),
+ media_type="text/csv",
+ headers={"Content-Disposition": f"attachment; filename={filename}", **(headers or {})},
+ )
+
+
+def _scalar_csv_rows(collection: ScalarValueCollection, detection_ran: bool) -> Generator[list[Any]]:
+ items = collection.items
+ # Dimension columns come from the values, so an empty collection only has the fixed ones
+ dimensions = sorted(items[0].dimensions.keys()) if items else []
+ header = [*dimensions, "value", "type"]
+ if detection_ran:
+ header.extend(["is_outlier", "verification_status"])
+ yield header
+
+ for item in items:
+ row = [item.dimensions.get(d) for d in dimensions] + [
+ sanitize_float_value(item.value),
+ "scalar",
+ ]
+ if detection_ran:
+ row.extend([item.is_outlier, item.verification_status])
+ yield row
+
+
def generate_csv_response_scalar(
collection: ScalarValueCollection,
detection_ran: bool,
@@ -41,45 +81,35 @@ def generate_csv_response_scalar(
Preserves the historical column layout: sorted dimension columns, then ``value`` and
``type``, and (when detection ran) ``is_outlier`` and ``verification_status``.
+ An empty collection gets a header of the columns that do not depend on the values.
"""
+ headers = {}
+ if detection_ran:
+ headers["X-REF-Had-Outliers"] = "true" if collection.had_outliers else "false"
+ headers["X-REF-Outlier-Count"] = str(collection.outlier_count)
+ return _csv_response(_scalar_csv_rows(collection, detection_ran), filename, headers)
- def generate_csv() -> Generator[str]:
- output = io.StringIO()
- writer = csv.writer(output)
-
- items = collection.items
- if not items:
- yield ""
- return
- dimensions = sorted(items[0].dimensions.keys())
- header = [*dimensions, "value", "type"]
- if detection_ran:
- header.extend(["is_outlier", "verification_status"])
- writer.writerow(header)
+_SERIES_COLUMNS = ["value", "index", "index_name", "type"]
- for item in items:
- row = [item.dimensions.get(d) for d in dimensions] + [
- sanitize_float_value(item.value),
- "scalar",
- ]
- if detection_ran:
- row.extend([item.is_outlier, item.verification_status])
- writer.writerow(row)
- output.seek(0)
- yield output.read()
+def _series_csv_rows(collection: SeriesValueCollection) -> Generator[list[Any]]:
+ if not collection.items:
+ yield list(_SERIES_COLUMNS)
+ return
- headers = {"Content-Disposition": f"attachment; filename={filename}"}
- if detection_ran:
- headers["X-REF-Had-Outliers"] = "true" if collection.had_outliers else "false"
- headers["X-REF-Outlier-Count"] = str(collection.outlier_count)
+ for sv in collection.items:
+ dimensions = sorted(sv.dimensions.keys())
+ yield [*dimensions, *_SERIES_COLUMNS]
- return StreamingResponse(
- generate_csv(),
- media_type="text/csv",
- headers=headers,
- )
+ for i, value in enumerate(sv.values):
+ index_value = sv.index[i] if sv.index and i < len(sv.index) else i
+ yield [sv.dimensions.get(d) for d in dimensions] + [
+ sanitize_float_value(value),
+ index_value,
+ sv.index_name or "index",
+ "series",
+ ]
def generate_csv_response_series(
@@ -90,41 +120,10 @@ def generate_csv_response_series(
Generate a CSV streaming response from a reader series collection.
Preserves the historical flattened layout: one header/data block per series, with a
- row per index point.
+ row per index point. An empty collection gets a header of the columns that do not
+ depend on the values.
"""
-
- def generate_csv() -> Generator[str]:
- output = io.StringIO()
- writer = csv.writer(output)
-
- items = collection.items
- if not items:
- yield ""
- return
-
- for sv in items:
- dimensions = sorted(sv.dimensions.keys())
- header = [*dimensions, "value", "index", "index_name", "type"]
- writer.writerow(header)
-
- for i, value in enumerate(sv.values):
- index_value = sv.index[i] if sv.index and i < len(sv.index) else i
- row = [sv.dimensions.get(d) for d in dimensions] + [
- sanitize_float_value(value),
- index_value,
- sv.index_name or "index",
- "series",
- ]
- writer.writerow(row)
-
- output.seek(0)
- yield output.read()
-
- return StreamingResponse(
- generate_csv(),
- media_type="text/csv",
- headers={"Content-Disposition": f"attachment; filename={filename}"},
- )
+ return _csv_response(_series_csv_rows(collection), filename)
def annotate_mip_eras(app_context: "AppContext", collection: MetricValueCollection) -> MetricValueCollection:
diff --git a/backend/src/ref_backend/models/diagnostics.py b/backend/src/ref_backend/models/diagnostics.py
index 5b87aa0b..04f473f9 100644
--- a/backend/src/ref_backend/models/diagnostics.py
+++ b/backend/src/ref_backend/models/diagnostics.py
@@ -123,8 +123,8 @@ def _build_group_by_summary(diagnostic: models.Diagnostic, app_context: "AppCont
)
return []
data_requirements = sorted(
- list(concrete_diagnostic.data_requirements),
- key=lambda dr: dr[0].source_type.value if isinstance(dr, tuple) else dr.source_type.value, # type: ignore
+ concrete_diagnostic.data_requirements,
+ key=lambda dr: dr[0].source_type.value if isinstance(dr, tuple) else dr.source_type.value,
)
# A diagnostic often declares one data requirement per variable, all grouping the same way,
diff --git a/backend/tests/test_core/test_filter_utils.py b/backend/tests/test_core/test_filter_utils.py
index 571f6b7a..09d92937 100644
--- a/backend/tests/test_core/test_filter_utils.py
+++ b/backend/tests/test_core/test_filter_utils.py
@@ -58,6 +58,16 @@ def test_list_with_empty_strings_after_strip_returns_none(self):
result = _normalize_list_from_value([" ", " "])
assert result is None
+ def test_string_of_only_commas_returns_none(self):
+ """Test that a string of commas and whitespace returns None."""
+ result = _normalize_list_from_value(" , ,")
+ assert result is None
+
+ def test_non_string_scalar_returns_none(self):
+ """Test that a scalar other than a string returns None."""
+ result = _normalize_list_from_value(42)
+ assert result is None
+
class TestBuildFilterClause:
"""Test the build_filter_clause function."""
@@ -115,6 +125,12 @@ def test_numeric_scalar_returns_equality(self):
sql = self._compile_clause(clause)
assert "test.name = 42" in sql
+ def test_comma_separated_string_with_one_item_returns_equality(self):
+ """Test that a comma-separated string with one non-empty item returns equality."""
+ clause = build_filter_clause(self.column, "a, ")
+ sql = self._compile_clause(clause)
+ assert "test.name = 'a'" in sql
+
def test_none_value_returns_equality(self):
"""Test that None value returns equality expression."""
clause = build_filter_clause(self.column, None)
diff --git a/backend/tests/test_core/test_reader_values.py b/backend/tests/test_core/test_reader_values.py
index caf607d0..3b408864 100644
--- a/backend/tests/test_core/test_reader_values.py
+++ b/backend/tests/test_core/test_reader_values.py
@@ -129,11 +129,18 @@ def test_header_with_detection(self):
assert response.headers["X-REF-Had-Outliers"] == "true"
assert response.headers["X-REF-Outlier-Count"] == "3"
- def test_empty_collection_yields_empty_body(self):
- """An empty collection produces an empty body."""
+ def test_empty_collection_yields_fixed_header(self):
+ """An empty collection produces just the header of the columns that do not depend on the values."""
collection = _scalar_collection([])
response = generate_csv_response_scalar(collection, detection_ran=False, filename="out.csv")
- assert _read_body(response) == ""
+ assert _read_body(response).splitlines() == ["value,type"]
+
+ def test_empty_collection_with_detection_includes_outlier_columns(self):
+ """An empty collection keeps the outlier columns when detection ran."""
+ collection = _scalar_collection([])
+ response = generate_csv_response_scalar(collection, detection_ran=True, filename="out.csv")
+ assert _read_body(response).splitlines() == ["value,type,is_outlier,verification_status"]
+ assert response.headers["X-REF-Outlier-Count"] == "0"
def test_nan_value_is_sanitized_to_empty_cell(self):
"""A NaN value renders as an empty CSV cell rather than the literal 'nan'."""
@@ -174,8 +181,8 @@ def test_index_falls_back_to_ordinal(self):
assert lines[1] == "A,10.0,0,index,series"
assert lines[2] == "A,20.0,1,index,series"
- def test_empty_collection_yields_empty_body(self):
- """An empty collection produces an empty body."""
+ def test_empty_collection_yields_fixed_header(self):
+ """An empty collection produces just the header of the columns that do not depend on the values."""
collection = _series_collection([])
response = generate_csv_response_series(collection, filename="out.csv")
- assert _read_body(response) == ""
+ assert _read_body(response).splitlines() == ["value,index,index_name,type"]
diff --git a/changelog/139.fix.md b/changelog/139.fix.md
new file mode 100644
index 00000000..f3fca35d
--- /dev/null
+++ b/changelog/139.fix.md
@@ -0,0 +1,9 @@
+* Execution groups whose latest execution is still running now show as running, and groups that have never run show as not run instead of failed. Their pages open instead of failing.
+* The executions list shows API errors instead of an empty list. Its filters wait until typing pauses, and "Clear All" also empties the inputs.
+* The datasets page no longer breaks on a malformed facet filter in the URL, and typing in the diagnostics search no longer adds a browser history entry per key.
+* Series charts: the tooltip compares values at the highlighted point, y-axis labels stay readable for large values in a small range, toggling a legend group works while a series is soloed, and reference series are visible in dark mode.
+* Explorer cards: "View chart values" and the CSV download use the card's region, MIP era and unverified setting, series cards download series values, and a configured filter default that does not exist falls back to the first option.
+* Execution value tabs keep their filters in the URL, and value tab links with numeric facet values no longer fail.
+* "Try Again" after an error retries the failed part instead of reloading the page, and navigating away from a page that failed shows the new page.
+* The Taylor diagram is readable in dark mode, and links in explorer descriptions are shown as links.
+* Log downloads are named after the execution group, the log view has a Debug filter, and the model page shows the actual error when loading fails.
diff --git a/changelog/139.trivial.md b/changelog/139.trivial.md
new file mode 100644
index 00000000..aa91bc1a
--- /dev/null
+++ b/changelog/139.trivial.md
@@ -0,0 +1,5 @@
+* Added [Fallow](https://fallow.tools) to check the frontend for dead code, duplication and complexity (`make fallow-audit`), skipping generated code and the shadcn/ui components.
+* Removed dead frontend code: unused exports, components, hook state and props, barrel re-exports, and an import cycle between the theme explorer and its route.
+* Merged duplicated code into shared pieces, such as one data table and one panel for the scalar and series value tabs, one execution status badge, and shared stat cards, filter popovers and chart empty states.
+* Moved logic out of components into tested functions (log parsing and summary, filters and search params, pagination, chart data and axes, Taylor diagram geometry, explorer mapping), split the largest components and the chart drawing code into smaller parts, and pointed two tests at the real code instead of copies of it. The frontend test suite grew from 384 to 626 tests.
+* Moved build-only packages to `devDependencies` and `@tailwindcss/typography`, which the styles load, to `dependencies`, and updated the deprecated Biome config.
diff --git a/frontend/.fallowrc.jsonc b/frontend/.fallowrc.jsonc
new file mode 100644
index 00000000..cf7527d8
--- /dev/null
+++ b/frontend/.fallowrc.jsonc
@@ -0,0 +1,24 @@
+{
+ "$schema": "./node_modules/fallow/schema.json",
+ // Generated code (@hey-api/openapi-ts client, TanStack route tree) stays in the
+ // module graph so imports resolve, but its findings are hidden.
+ // Globs start with ** so they match whether Fallow runs from frontend/ (CLI)
+ // or from the repo root (VS Code extension, via fallow.configPath).
+ "ignoreFindings": [
+ "**/src/client/**",
+ "**/*.gen.ts",
+ // shadcn/ui components copied into the repo, which keep their full API
+ "**/src/components/ui/**"
+ ],
+ // Run by scripts/generate-client-sdk.sh, which is outside the project root
+ "entry": ["openapi-ts.config.ts"],
+ // Types used in an exported signature in the same file stay exported, so callers can name them
+ "ignoreExportsUsedInFile": { "type": true, "interface": true },
+ "duplicates": {
+ "ignore": ["**/src/client/**", "**/*.gen.ts"]
+ },
+ "health": {
+ "ignore": ["**/src/client/**", "**/*.gen.ts"],
+ "coverage": "coverage/coverage-final.json"
+ }
+}
diff --git a/frontend/biome.json b/frontend/biome.json
index 775503fc..b52f0c08 100644
--- a/frontend/biome.json
+++ b/frontend/biome.json
@@ -1,5 +1,5 @@
{
- "$schema": "https://biomejs.dev/schemas/2.5.11/schema.json",
+ "$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
"vcs": {
"enabled": false,
"clientKind": "git",
@@ -32,7 +32,7 @@
"linter": {
"enabled": true,
"rules": {
- "recommended": true,
+ "preset": "recommended",
"correctness": {
"useUniqueElementIds": "off"
},
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 787c8b7c..9fd40619 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -10,7 +10,6 @@
"dependencies": {
"@floating-ui/react": "^0.27.16",
"@mdx-js/react": "^3.1.0",
- "@mdx-js/rollup": "^3.1.0",
"@plausible-analytics/tracker": "^0.4.3",
"@radix-ui/react-checkbox": "^1.3.3",
"@radix-ui/react-collapsible": "^1.1.11",
@@ -27,7 +26,7 @@
"@radix-ui/react-tabs": "^1.1.3",
"@radix-ui/react-tooltip": "^1.2.8",
"@sentry/react": "^10.17.0",
- "@tailwindcss/vite": "^4.0.9",
+ "@tailwindcss/typography": "^0.5.20",
"@tanstack/react-query": "^5.66.11",
"@tanstack/react-query-devtools": "^5.67.1",
"@tanstack/react-router": "^1.115.3",
@@ -55,8 +54,9 @@
"devDependencies": {
"@biomejs/biome": "^2.2.4",
"@hey-api/openapi-ts": "^0.99.0",
+ "@mdx-js/rollup": "^3.1.1",
"@sentry/vite-plugin": "^5.0.0",
- "@tailwindcss/typography": "^0.5.18",
+ "@tailwindcss/vite": "^4.3.3",
"@tanstack/react-router-devtools": "^1.115.3",
"@tanstack/router-plugin": "^1.115.3",
"@testing-library/jest-dom": "^7.0.0",
@@ -68,6 +68,7 @@
"@vitejs/plugin-react-swc": "^4.0.0",
"@vitest/coverage-v8": "^5.0.0",
"@welldone-software/why-did-you-render": "^10.0.1",
+ "fallow": "^3.34.1",
"jsdom": "^30.0.0",
"typescript": "~7.0.0",
"vite": ">=7.3.2 <9",
@@ -718,6 +719,118 @@
}
}
},
+ "node_modules/@fallow-cli/darwin-arm64": {
+ "version": "3.34.1",
+ "resolved": "https://registry.npmjs.org/@fallow-cli/darwin-arm64/-/darwin-arm64-3.34.1.tgz",
+ "integrity": "sha512-AmOfH7XLjwUgPKfqyCm/ELr4DU6ShEsOTGL1DRqk8xVf3e+KPFw6tN68Fl6K8wdAzu/kKnWYrjryEVeu849hdg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@fallow-cli/darwin-x64": {
+ "version": "3.34.1",
+ "resolved": "https://registry.npmjs.org/@fallow-cli/darwin-x64/-/darwin-x64-3.34.1.tgz",
+ "integrity": "sha512-ayHBvwNn6ycz9fHxmX6pi0govhZgGEFXq4mRfuesdhpETOkR0RWFaEyLdRaRWXIhR71wKJRycxGUR6pQF8mprg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@fallow-cli/linux-arm64-gnu": {
+ "version": "3.34.1",
+ "resolved": "https://registry.npmjs.org/@fallow-cli/linux-arm64-gnu/-/linux-arm64-gnu-3.34.1.tgz",
+ "integrity": "sha512-4m86btsHBPsBnJ4EJR3FlxC4QPjK7hNrx8i8ek/Tu3sKhTnT0RyNUcuJzlcLFvwMdmyuUaOyQQarLgobKkjxfQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@fallow-cli/linux-arm64-musl": {
+ "version": "3.34.1",
+ "resolved": "https://registry.npmjs.org/@fallow-cli/linux-arm64-musl/-/linux-arm64-musl-3.34.1.tgz",
+ "integrity": "sha512-fDidOlgS/J417ANtt4Ymdliv9PV16RJvFEGc+MKuMnVIwJ5Jh3MZr9idiVEE+8opPQ1XW1Ol2nAo1kyZzxkkzw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@fallow-cli/linux-x64-gnu": {
+ "version": "3.34.1",
+ "resolved": "https://registry.npmjs.org/@fallow-cli/linux-x64-gnu/-/linux-x64-gnu-3.34.1.tgz",
+ "integrity": "sha512-kY8Ks05aMw7xxBXxP99+SbgzbwooCEWScVE5TAiP01iZ5FHuErufesGD1sDwP0/pTGv3NXKQje5v9WMRcPdx4w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@fallow-cli/linux-x64-musl": {
+ "version": "3.34.1",
+ "resolved": "https://registry.npmjs.org/@fallow-cli/linux-x64-musl/-/linux-x64-musl-3.34.1.tgz",
+ "integrity": "sha512-PlEu9whAZgog9RNwVtgTGRT5qxaambXINGi2c2LnRZodUtkUHVrBVNQu3L4nun2kkLAJ2cXCT9puOCFpPqCsiA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@fallow-cli/win32-arm64-msvc": {
+ "version": "3.34.1",
+ "resolved": "https://registry.npmjs.org/@fallow-cli/win32-arm64-msvc/-/win32-arm64-msvc-3.34.1.tgz",
+ "integrity": "sha512-jTnKetAeNMgiz1yMKwWGJRkvTnXctNL6VmuzBv60asaQRIEPReOSbpM52CMahI5fK55j3wmspVhEVm7/dBn4ZA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@fallow-cli/win32-x64-msvc": {
+ "version": "3.34.1",
+ "resolved": "https://registry.npmjs.org/@fallow-cli/win32-x64-msvc/-/win32-x64-msvc-3.34.1.tgz",
+ "integrity": "sha512-rdjchbPiFK5ExxyZnj50FN6+n+KYTtbLrtcEegVg+iL97LvLml9sVvF1YcDP69fWDJVAhAwlE2mQZhW/P2HPyw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
"node_modules/@floating-ui/core": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.8.0.tgz",
@@ -899,6 +1012,7 @@
"version": "0.3.13",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
"integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.5.0",
@@ -909,6 +1023,7 @@
"version": "2.3.5",
"resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
"integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.5",
@@ -919,6 +1034,7 @@
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=6.0.0"
@@ -928,12 +1044,14 @@
"version": "1.5.5",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+ "dev": true,
"license": "MIT"
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.31",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
"integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/resolve-uri": "^3.1.0",
@@ -961,6 +1079,7 @@
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.1.1.tgz",
"integrity": "sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/estree": "^1.0.0",
@@ -1015,6 +1134,7 @@
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@mdx-js/rollup/-/rollup-3.1.1.tgz",
"integrity": "sha512-v8satFmBB+DqDzYohnm1u2JOvxx6Hl3pUvqzJvfs2Zk/ngZ1aRUhsWpXvwPkNeGN9c2NCm/38H29ZqXQUjf8dw==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@mdx-js/mdx": "^3.0.0",
@@ -1034,6 +1154,7 @@
"version": "0.147.0",
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.147.0.tgz",
"integrity": "sha512-IJ3s6ltHLp45S0bh7phkX+gJO7A1Wuz2EaqpAhb8WjqDwbzMiWKHhyyT42tskaWjEYXtHtVCPpnBJVT9+dcRLg==",
+ "dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/Boshen"
@@ -2014,6 +2135,7 @@
"cpu": [
"arm"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -2030,6 +2152,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -2046,6 +2169,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -2062,6 +2186,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -2078,6 +2203,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -2094,6 +2220,7 @@
"cpu": [
"arm"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -2110,6 +2237,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"libc": [
"glibc"
],
@@ -2129,6 +2257,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"libc": [
"musl"
],
@@ -2148,6 +2277,7 @@
"cpu": [
"ppc64"
],
+ "dev": true,
"libc": [
"glibc"
],
@@ -2167,6 +2297,7 @@
"cpu": [
"s390x"
],
+ "dev": true,
"libc": [
"glibc"
],
@@ -2186,6 +2317,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"libc": [
"glibc"
],
@@ -2205,6 +2337,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"libc": [
"musl"
],
@@ -2224,6 +2357,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -2240,6 +2374,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -2256,6 +2391,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -2269,12 +2405,14 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz",
"integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==",
+ "dev": true,
"license": "MIT"
},
"node_modules/@rollup/pluginutils": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz",
"integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/estree": "^1.0.0",
@@ -2297,6 +2435,7 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
+ "dev": true,
"license": "MIT"
},
"node_modules/@rollup/rollup-android-arm-eabi": {
@@ -2306,6 +2445,7 @@
"cpu": [
"arm"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -2320,6 +2460,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -2334,6 +2475,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -2348,6 +2490,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -2362,6 +2505,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -2376,6 +2520,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -2390,6 +2535,7 @@
"cpu": [
"arm"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -2404,6 +2550,7 @@
"cpu": [
"arm"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -2418,6 +2565,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -2432,6 +2580,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -2446,6 +2595,7 @@
"cpu": [
"loong64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -2460,6 +2610,7 @@
"cpu": [
"loong64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -2474,6 +2625,7 @@
"cpu": [
"ppc64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -2488,6 +2640,7 @@
"cpu": [
"ppc64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -2502,6 +2655,7 @@
"cpu": [
"riscv64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -2516,6 +2670,7 @@
"cpu": [
"riscv64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -2530,6 +2685,7 @@
"cpu": [
"s390x"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -2544,6 +2700,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -2558,6 +2715,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -2572,6 +2730,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -2586,6 +2745,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -2600,6 +2760,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -2614,6 +2775,7 @@
"cpu": [
"ia32"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -2628,6 +2790,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -2642,6 +2805,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3436,6 +3600,7 @@
"version": "4.3.3",
"resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.3.tgz",
"integrity": "sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/remapping": "^2.3.5",
@@ -3451,6 +3616,7 @@
"version": "4.3.3",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.3.tgz",
"integrity": "sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">= 20"
@@ -3477,6 +3643,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3493,6 +3660,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3509,6 +3677,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3525,6 +3694,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3541,6 +3711,7 @@
"cpu": [
"arm"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3557,6 +3728,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"libc": [
"glibc"
],
@@ -3576,6 +3748,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"libc": [
"musl"
],
@@ -3595,6 +3768,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"libc": [
"glibc"
],
@@ -3614,6 +3788,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"libc": [
"musl"
],
@@ -3641,6 +3816,7 @@
"cpu": [
"wasm32"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
@@ -3657,6 +3833,7 @@
},
"node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/core": {
"version": "1.11.1",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"optional": true,
@@ -3667,6 +3844,7 @@
},
"node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/runtime": {
"version": "1.11.1",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"optional": true,
@@ -3676,6 +3854,7 @@
},
"node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/wasi-threads": {
"version": "1.2.2",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"optional": true,
@@ -3685,6 +3864,7 @@
},
"node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": {
"version": "1.1.4",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"optional": true,
@@ -3702,6 +3882,7 @@
},
"node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@tybys/wasm-util": {
"version": "0.10.2",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"optional": true,
@@ -3711,6 +3892,7 @@
},
"node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/tslib": {
"version": "2.8.1",
+ "dev": true,
"inBundle": true,
"license": "0BSD",
"optional": true
@@ -3722,6 +3904,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3738,6 +3921,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3751,7 +3935,6 @@
"version": "0.5.20",
"resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.20.tgz",
"integrity": "sha512-hwbzQuNUfcPvbegQFatVPl/MY/tcM9KLl963hQ5laJKPh81TEZ1+dNG9PirGvcaDBkp+BCshExAyKVPW91dozw==",
- "dev": true,
"license": "MIT",
"dependencies": {
"postcss-selector-parser": "6.0.10"
@@ -3764,6 +3947,7 @@
"version": "4.3.3",
"resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.3.3.tgz",
"integrity": "sha512-yYU8cogLeSh/ms2jh8Fj7jaba/EWa7Ja6GoUqYZaraEuCI5YS6ms6ObZgjjedm+jm6XZjdNRWBpPP6Z86oOxcw==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@tailwindcss/node": "4.3.3",
@@ -4519,6 +4703,7 @@
"version": "4.1.13",
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz",
"integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/ms": "*"
@@ -4535,12 +4720,14 @@
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
+ "dev": true,
"license": "MIT"
},
"node_modules/@types/estree-jsx": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz",
"integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/estree": "*"
@@ -4557,6 +4744,7 @@
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz",
"integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/unist": "*"
@@ -4573,6 +4761,7 @@
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz",
"integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/unist": "*"
@@ -4588,13 +4777,14 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz",
"integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==",
+ "dev": true,
"license": "MIT"
},
"node_modules/@types/node": {
"version": "24.13.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.3.tgz",
"integrity": "sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==",
- "devOptional": true,
+ "dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~7.18.0"
@@ -4623,6 +4813,7 @@
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz",
"integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==",
+ "dev": true,
"license": "MIT"
},
"node_modules/@typescript/typescript-aix-ppc64": {
@@ -4969,6 +5160,7 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz",
"integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==",
+ "dev": true,
"license": "ISC"
},
"node_modules/@vitejs/plugin-react-swc": {
@@ -5105,6 +5297,7 @@
"version": "8.16.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
+ "dev": true,
"license": "MIT",
"bin": {
"acorn": "bin/acorn"
@@ -5117,6 +5310,7 @@
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+ "dev": true,
"license": "MIT",
"peerDependencies": {
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
@@ -5242,6 +5436,7 @@
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/astring/-/astring-1.9.0.tgz",
"integrity": "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==",
+ "dev": true,
"license": "MIT",
"bin": {
"astring": "bin/astring"
@@ -5264,6 +5459,7 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz",
"integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==",
+ "dev": true,
"license": "MIT",
"funding": {
"type": "github",
@@ -5410,6 +5606,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz",
"integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==",
+ "dev": true,
"license": "MIT",
"funding": {
"type": "github",
@@ -5430,6 +5627,7 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz",
"integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==",
+ "dev": true,
"license": "MIT",
"funding": {
"type": "github",
@@ -5440,6 +5638,7 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz",
"integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==",
+ "dev": true,
"license": "MIT",
"funding": {
"type": "github",
@@ -5450,6 +5649,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz",
"integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==",
+ "dev": true,
"license": "MIT",
"funding": {
"type": "github",
@@ -5460,6 +5660,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz",
"integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==",
+ "dev": true,
"license": "MIT",
"funding": {
"type": "github",
@@ -5523,6 +5724,7 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-2.1.0.tgz",
"integrity": "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==",
+ "dev": true,
"license": "MIT",
"funding": {
"type": "github",
@@ -5543,6 +5745,7 @@
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz",
"integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==",
+ "dev": true,
"license": "MIT",
"funding": {
"type": "github",
@@ -5618,7 +5821,6 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
- "dev": true,
"license": "MIT",
"bin": {
"cssesc": "bin/cssesc"
@@ -6077,6 +6279,7 @@
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
@@ -6107,6 +6310,7 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz",
"integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"character-entities": "^2.0.0"
@@ -6179,6 +6383,7 @@
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
"integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
@@ -6195,6 +6400,7 @@
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
+ "dev": true,
"license": "Apache-2.0",
"engines": {
"node": ">=8"
@@ -6210,6 +6416,7 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz",
"integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"dequal": "^2.0.0"
@@ -6258,6 +6465,7 @@
"version": "5.24.5",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.5.tgz",
"integrity": "sha512-L1l8TNvomm6UVW5B253AGxQagSQr+vGwhMlrrfRS2qmhx46AMpMVJKQYLvWYbysTMY8VoicOvzHzoHMbyzB+4A==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"graceful-fs": "^4.2.4",
@@ -6291,6 +6499,7 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/esast-util-from-estree/-/esast-util-from-estree-2.0.0.tgz",
"integrity": "sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/estree-jsx": "^1.0.0",
@@ -6307,6 +6516,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/esast-util-from-js/-/esast-util-from-js-2.0.1.tgz",
"integrity": "sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/estree-jsx": "^1.0.0",
@@ -6333,6 +6543,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/estree-util-attach-comments/-/estree-util-attach-comments-3.0.0.tgz",
"integrity": "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/estree": "^1.0.0"
@@ -6346,6 +6557,7 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/estree-util-build-jsx/-/estree-util-build-jsx-3.0.1.tgz",
"integrity": "sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/estree-jsx": "^1.0.0",
@@ -6362,6 +6574,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz",
"integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==",
+ "dev": true,
"license": "MIT",
"funding": {
"type": "opencollective",
@@ -6372,6 +6585,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/estree-util-scope/-/estree-util-scope-1.0.0.tgz",
"integrity": "sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/estree": "^1.0.0",
@@ -6386,6 +6600,7 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/estree-util-to-js/-/estree-util-to-js-2.0.0.tgz",
"integrity": "sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/estree-jsx": "^1.0.0",
@@ -6401,6 +6616,7 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/estree-util-visit/-/estree-util-visit-2.0.0.tgz",
"integrity": "sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/estree-jsx": "^1.0.0",
@@ -6415,6 +6631,7 @@
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
"integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/estree": "^1.0.0"
@@ -6447,8 +6664,58 @@
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+ "dev": true,
"license": "MIT"
},
+ "node_modules/fallow": {
+ "version": "3.34.1",
+ "resolved": "https://registry.npmjs.org/fallow/-/fallow-3.34.1.tgz",
+ "integrity": "sha512-4jmCmr4EsIn8e6D3j7m1nlgOy+Ms9ddzHOiC2cyWaUlcokyLlIZK8IIR8hXRET+oPvnwRcqpansOru1ckBn5KA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "detect-libc": "2.1.2"
+ },
+ "bin": {
+ "fallow": "bin/fallow",
+ "fallow-lsp": "bin/fallow-lsp",
+ "fallow-mcp": "bin/fallow-mcp"
+ },
+ "engines": {
+ "node": ">=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/fallow-rs"
+ },
+ "optionalDependencies": {
+ "@fallow-cli/darwin-arm64": "3.34.1",
+ "@fallow-cli/darwin-x64": "3.34.1",
+ "@fallow-cli/linux-arm64-gnu": "3.34.1",
+ "@fallow-cli/linux-arm64-musl": "3.34.1",
+ "@fallow-cli/linux-x64-gnu": "3.34.1",
+ "@fallow-cli/linux-x64-musl": "3.34.1",
+ "@fallow-cli/win32-arm64-msvc": "3.34.1",
+ "@fallow-cli/win32-x64-msvc": "3.34.1",
+ "fallow-type-aware": "3.34.1"
+ }
+ },
+ "node_modules/fallow-type-aware": {
+ "version": "3.34.1",
+ "resolved": "https://registry.npmjs.org/fallow-type-aware/-/fallow-type-aware-3.34.1.tgz",
+ "integrity": "sha512-81xwRvAe14rMwH0ORAdM1DoXV1TBl2+s7dK+pJ8veM1zJyvrDdjbSwRGWQxRh+Q+l0RsGHlt4kCcE0/1+JS5Yw==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "typescript": "7.0.2"
+ },
+ "bin": {
+ "fallow-type-aware": "fallow-type-aware.mjs"
+ },
+ "engines": {
+ "node": ">=20"
+ }
+ },
"node_modules/fast-equals": {
"version": "5.4.0",
"resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.4.0.tgz",
@@ -6462,6 +6729,7 @@
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=12.0.0"
@@ -6496,6 +6764,7 @@
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
"hasInstallScript": true,
"license": "MIT",
"optional": true,
@@ -6562,12 +6831,14 @@
"version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+ "dev": true,
"license": "ISC"
},
"node_modules/hast-util-to-estree": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-3.1.3.tgz",
"integrity": "sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/estree": "^1.0.0",
@@ -6596,6 +6867,7 @@
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz",
"integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/estree": "^1.0.0",
@@ -6623,6 +6895,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz",
"integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/hast": "^3.0.0"
@@ -6685,6 +6958,7 @@
"version": "0.2.7",
"resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.7.tgz",
"integrity": "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==",
+ "dev": true,
"license": "MIT"
},
"node_modules/internmap": {
@@ -6700,6 +6974,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz",
"integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==",
+ "dev": true,
"license": "MIT",
"funding": {
"type": "github",
@@ -6710,6 +6985,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz",
"integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"is-alphabetical": "^2.0.0",
@@ -6724,6 +7000,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz",
"integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==",
+ "dev": true,
"license": "MIT",
"funding": {
"type": "github",
@@ -6750,6 +7027,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz",
"integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==",
+ "dev": true,
"license": "MIT",
"funding": {
"type": "github",
@@ -6792,6 +7070,7 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz",
"integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
@@ -6843,6 +7122,7 @@
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz",
"integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==",
+ "dev": true,
"license": "MIT",
"bin": {
"jiti": "lib/jiti-cli.mjs"
@@ -7006,6 +7286,7 @@
"version": "1.32.0",
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz",
"integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==",
+ "dev": true,
"license": "MPL-2.0",
"dependencies": {
"detect-libc": "^2.0.3"
@@ -7038,6 +7319,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -7058,6 +7340,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -7078,6 +7361,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -7098,6 +7382,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -7118,6 +7403,7 @@
"cpu": [
"arm"
],
+ "dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -7138,6 +7424,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -7158,6 +7445,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -7178,6 +7466,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -7198,6 +7487,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -7218,6 +7508,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -7238,6 +7529,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -7277,6 +7569,7 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz",
"integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==",
+ "dev": true,
"license": "MIT",
"funding": {
"type": "github",
@@ -7329,6 +7622,7 @@
"version": "0.30.21",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
"integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.5.5"
@@ -7350,6 +7644,7 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-2.0.0.tgz",
"integrity": "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=16"
@@ -7362,6 +7657,7 @@
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.3.tgz",
"integrity": "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/mdast": "^4.0.0",
@@ -7386,6 +7682,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-3.0.0.tgz",
"integrity": "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"mdast-util-from-markdown": "^2.0.0",
@@ -7403,6 +7700,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz",
"integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/estree-jsx": "^1.0.0",
@@ -7421,6 +7719,7 @@
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz",
"integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/estree-jsx": "^1.0.0",
@@ -7445,6 +7744,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz",
"integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/estree-jsx": "^1.0.0",
@@ -7463,6 +7763,7 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz",
"integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/mdast": "^4.0.0",
@@ -7477,6 +7778,7 @@
"version": "13.2.1",
"resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz",
"integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/hast": "^3.0.0",
@@ -7498,6 +7800,7 @@
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz",
"integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/mdast": "^4.0.0",
@@ -7519,6 +7822,7 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz",
"integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/mdast": "^4.0.0"
@@ -7539,6 +7843,7 @@
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz",
"integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==",
+ "dev": true,
"funding": [
{
"type": "GitHub Sponsors",
@@ -7574,6 +7879,7 @@
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz",
"integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==",
+ "dev": true,
"funding": [
{
"type": "GitHub Sponsors",
@@ -7608,6 +7914,7 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.1.tgz",
"integrity": "sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==",
+ "dev": true,
"funding": [
{
"type": "GitHub Sponsors",
@@ -7634,6 +7941,7 @@
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.2.tgz",
"integrity": "sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/estree": "^1.0.0",
@@ -7656,6 +7964,7 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/micromark-extension-mdx-md/-/micromark-extension-mdx-md-2.0.0.tgz",
"integrity": "sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"micromark-util-types": "^2.0.0"
@@ -7669,6 +7978,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/micromark-extension-mdxjs/-/micromark-extension-mdxjs-3.0.0.tgz",
"integrity": "sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"acorn": "^8.0.0",
@@ -7689,6 +7999,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-3.0.0.tgz",
"integrity": "sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/estree": "^1.0.0",
@@ -7710,6 +8021,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz",
"integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==",
+ "dev": true,
"funding": [
{
"type": "GitHub Sponsors",
@@ -7731,6 +8043,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz",
"integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==",
+ "dev": true,
"funding": [
{
"type": "GitHub Sponsors",
@@ -7753,6 +8066,7 @@
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.3.tgz",
"integrity": "sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==",
+ "dev": true,
"funding": [
{
"type": "GitHub Sponsors",
@@ -7780,6 +8094,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz",
"integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==",
+ "dev": true,
"funding": [
{
"type": "GitHub Sponsors",
@@ -7800,6 +8115,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz",
"integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==",
+ "dev": true,
"funding": [
{
"type": "GitHub Sponsors",
@@ -7822,6 +8138,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz",
"integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==",
+ "dev": true,
"funding": [
{
"type": "GitHub Sponsors",
@@ -7844,6 +8161,7 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz",
"integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==",
+ "dev": true,
"funding": [
{
"type": "GitHub Sponsors",
@@ -7864,6 +8182,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz",
"integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==",
+ "dev": true,
"funding": [
{
"type": "GitHub Sponsors",
@@ -7883,6 +8202,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz",
"integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==",
+ "dev": true,
"funding": [
{
"type": "GitHub Sponsors",
@@ -7904,6 +8224,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz",
"integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==",
+ "dev": true,
"funding": [
{
"type": "GitHub Sponsors",
@@ -7924,6 +8245,7 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz",
"integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==",
+ "dev": true,
"funding": [
{
"type": "GitHub Sponsors",
@@ -7943,6 +8265,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz",
"integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==",
+ "dev": true,
"funding": [
{
"type": "GitHub Sponsors",
@@ -7965,6 +8288,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz",
"integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==",
+ "dev": true,
"funding": [
{
"type": "GitHub Sponsors",
@@ -7981,6 +8305,7 @@
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.3.tgz",
"integrity": "sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==",
+ "dev": true,
"funding": [
{
"type": "GitHub Sponsors",
@@ -8006,6 +8331,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz",
"integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==",
+ "dev": true,
"funding": [
{
"type": "GitHub Sponsors",
@@ -8022,6 +8348,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz",
"integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==",
+ "dev": true,
"funding": [
{
"type": "GitHub Sponsors",
@@ -8041,6 +8368,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz",
"integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==",
+ "dev": true,
"funding": [
{
"type": "GitHub Sponsors",
@@ -8060,6 +8388,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz",
"integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==",
+ "dev": true,
"funding": [
{
"type": "GitHub Sponsors",
@@ -8081,6 +8410,7 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz",
"integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==",
+ "dev": true,
"funding": [
{
"type": "GitHub Sponsors",
@@ -8103,6 +8433,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz",
"integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==",
+ "dev": true,
"funding": [
{
"type": "GitHub Sponsors",
@@ -8119,6 +8450,7 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz",
"integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==",
+ "dev": true,
"funding": [
{
"type": "GitHub Sponsors",
@@ -8155,12 +8487,14 @@
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true,
"license": "MIT"
},
"node_modules/nanoid": {
"version": "3.3.18",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz",
"integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==",
+ "dev": true,
"funding": [
{
"type": "github",
@@ -8318,6 +8652,7 @@
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz",
"integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/unist": "^2.0.0",
@@ -8337,6 +8672,7 @@
"version": "2.0.11",
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz",
"integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==",
+ "dev": true,
"license": "MIT"
},
"node_modules/parse5": {
@@ -8390,12 +8726,14 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "dev": true,
"license": "ISC"
},
"node_modules/picomatch": {
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz",
"integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
@@ -8420,6 +8758,7 @@
"version": "8.5.26",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz",
"integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==",
+ "dev": true,
"funding": [
{
"type": "opencollective",
@@ -8448,7 +8787,6 @@
"version": "6.0.10",
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz",
"integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==",
- "dev": true,
"license": "MIT",
"dependencies": {
"cssesc": "^3.0.0",
@@ -8534,6 +8872,7 @@
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz",
"integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==",
+ "dev": true,
"license": "MIT",
"funding": {
"type": "github",
@@ -8775,6 +9114,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/recma-build-jsx/-/recma-build-jsx-1.0.0.tgz",
"integrity": "sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/estree": "^1.0.0",
@@ -8790,6 +9130,7 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/recma-jsx/-/recma-jsx-1.0.1.tgz",
"integrity": "sha512-huSIy7VU2Z5OLv6oFLosQGGDqPqdO1iq6bWNAdhzMxSJP7RAso4fCZ1cKu8j9YHCZf3TPrq4dw3okhrylgcd7w==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"acorn-jsx": "^5.0.0",
@@ -8810,6 +9151,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/recma-parse/-/recma-parse-1.0.0.tgz",
"integrity": "sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/estree": "^1.0.0",
@@ -8826,6 +9168,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/recma-stringify/-/recma-stringify-1.0.0.tgz",
"integrity": "sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/estree": "^1.0.0",
@@ -8856,6 +9199,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/rehype-recma/-/rehype-recma-1.0.0.tgz",
"integrity": "sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/estree": "^1.0.0",
@@ -8871,6 +9215,7 @@
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.1.1.tgz",
"integrity": "sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"mdast-util-mdx": "^3.0.0",
@@ -8885,6 +9230,7 @@
"version": "11.0.0",
"resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz",
"integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/mdast": "^4.0.0",
@@ -8901,6 +9247,7 @@
"version": "11.1.2",
"resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz",
"integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/hast": "^3.0.0",
@@ -8944,6 +9291,7 @@
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.6.tgz",
"integrity": "sha512-vMM4q3aixf46GiF1Kok8jDPFsEpXgFWGjUHXNkNHNm+Y2adXAG2dbX91jkti3i0ZRsOlcmbuzAz1poObSHCmUA==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@oxc-project/types": "=0.147.0",
@@ -8977,6 +9325,7 @@
"version": "4.60.1",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.1.tgz",
"integrity": "sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w==",
+ "dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
@@ -9127,6 +9476,7 @@
"version": "0.7.6",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz",
"integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==",
+ "dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">= 12"
@@ -9136,6 +9486,7 @@
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
@@ -9145,6 +9496,7 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz",
"integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==",
+ "dev": true,
"license": "MIT",
"funding": {
"type": "github",
@@ -9169,6 +9521,7 @@
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz",
"integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"character-entities-html4": "^2.0.0",
@@ -9196,6 +9549,7 @@
"version": "1.1.21",
"resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.21.tgz",
"integrity": "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"style-to-object": "1.0.14"
@@ -9205,6 +9559,7 @@
"version": "1.0.14",
"resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.14.tgz",
"integrity": "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"inline-style-parser": "0.2.7"
@@ -9252,6 +9607,7 @@
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz",
"integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
@@ -9291,6 +9647,7 @@
"version": "0.2.17",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz",
"integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"fdir": "^6.5.0",
@@ -9363,6 +9720,7 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz",
"integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==",
+ "dev": true,
"license": "MIT",
"funding": {
"type": "github",
@@ -9373,6 +9731,7 @@
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz",
"integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==",
+ "dev": true,
"license": "MIT",
"funding": {
"type": "github",
@@ -9434,13 +9793,14 @@
"version": "7.18.2",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz",
"integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==",
- "devOptional": true,
+ "dev": true,
"license": "MIT"
},
"node_modules/unified": {
"version": "11.0.5",
"resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz",
"integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/unist": "^3.0.0",
@@ -9460,6 +9820,7 @@
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz",
"integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/unist": "^3.0.0"
@@ -9473,6 +9834,7 @@
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz",
"integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/unist": "^3.0.0"
@@ -9486,6 +9848,7 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/unist-util-position-from-estree/-/unist-util-position-from-estree-2.0.0.tgz",
"integrity": "sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/unist": "^3.0.0"
@@ -9499,6 +9862,7 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz",
"integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/unist": "^3.0.0"
@@ -9512,6 +9876,7 @@
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz",
"integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/unist": "^3.0.0",
@@ -9527,6 +9892,7 @@
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz",
"integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/unist": "^3.0.0",
@@ -9679,13 +10045,13 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
- "dev": true,
"license": "MIT"
},
"node_modules/vfile": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz",
"integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/unist": "^3.0.0",
@@ -9700,6 +10066,7 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz",
"integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/unist": "^3.0.0",
@@ -9736,6 +10103,7 @@
"version": "8.2.2",
"resolved": "https://registry.npmjs.org/vite/-/vite-8.2.2.tgz",
"integrity": "sha512-cFKLV/PRgAUlIRm5WjMjJ86jrftzpqcgH+Us+DS8mI3CDNiH30Whrz8uHL3+MOLPAgqbMBAqWdAHAphOAM+z/Q==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"lightningcss": "^1.33.0",
@@ -9813,6 +10181,7 @@
"version": "1.33.0",
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz",
"integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==",
+ "dev": true,
"license": "MPL-2.0",
"dependencies": {
"detect-libc": "^2.0.3"
@@ -9845,6 +10214,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -9865,6 +10235,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -9885,6 +10256,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -9905,6 +10277,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -9925,6 +10298,7 @@
"cpu": [
"arm"
],
+ "dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -9945,6 +10319,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"libc": [
"glibc"
],
@@ -9968,6 +10343,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"libc": [
"musl"
],
@@ -9991,6 +10367,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"libc": [
"glibc"
],
@@ -10014,6 +10391,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"libc": [
"musl"
],
@@ -10037,6 +10415,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -10057,6 +10436,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -10318,6 +10698,7 @@
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz",
"integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==",
+ "dev": true,
"license": "MIT",
"funding": {
"type": "github",
diff --git a/frontend/package.json b/frontend/package.json
index 29a501db..40e92b89 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -10,12 +10,13 @@
"preview": "vite preview",
"openapi-ts": "bash ../scripts/generate-client-sdk.sh",
"test": "vitest run",
- "test:coverage": "vitest run --coverage"
+ "test:coverage": "vitest run --coverage",
+ "fallow": "fallow",
+ "fallow:audit": "fallow audit --base main"
},
"dependencies": {
"@floating-ui/react": "^0.27.16",
"@mdx-js/react": "^3.1.0",
- "@mdx-js/rollup": "^3.1.0",
"@plausible-analytics/tracker": "^0.4.3",
"@radix-ui/react-checkbox": "^1.3.3",
"@radix-ui/react-collapsible": "^1.1.11",
@@ -32,7 +33,7 @@
"@radix-ui/react-tabs": "^1.1.3",
"@radix-ui/react-tooltip": "^1.2.8",
"@sentry/react": "^10.17.0",
- "@tailwindcss/vite": "^4.0.9",
+ "@tailwindcss/typography": "^0.5.20",
"@tanstack/react-query": "^5.66.11",
"@tanstack/react-query-devtools": "^5.67.1",
"@tanstack/react-router": "^1.115.3",
@@ -60,8 +61,9 @@
"devDependencies": {
"@biomejs/biome": "^2.2.4",
"@hey-api/openapi-ts": "^0.99.0",
+ "@mdx-js/rollup": "^3.1.1",
"@sentry/vite-plugin": "^5.0.0",
- "@tailwindcss/typography": "^0.5.18",
+ "@tailwindcss/vite": "^4.3.3",
"@tanstack/react-router-devtools": "^1.115.3",
"@tanstack/router-plugin": "^1.115.3",
"@testing-library/jest-dom": "^7.0.0",
@@ -73,6 +75,7 @@
"@vitejs/plugin-react-swc": "^4.0.0",
"@vitest/coverage-v8": "^5.0.0",
"@welldone-software/why-did-you-render": "^10.0.1",
+ "fallow": "^3.34.1",
"jsdom": "^30.0.0",
"typescript": "~7.0.0",
"vite": ">=7.3.2 <9",
diff --git a/frontend/src/components/app/checkboxCommandList.test.tsx b/frontend/src/components/app/checkboxCommandList.test.tsx
new file mode 100644
index 00000000..a11dd2d8
--- /dev/null
+++ b/frontend/src/components/app/checkboxCommandList.test.tsx
@@ -0,0 +1,40 @@
+import { fireEvent, render, screen } from "@testing-library/react";
+import { beforeAll, describe, expect, it, vi } from "vitest";
+import { CheckboxCommandList } from "./checkboxCommandList";
+
+beforeAll(() => {
+ // cmdk measures and scrolls its items, which jsdom does not implement
+ globalThis.ResizeObserver ??= class {
+ observe() {}
+ unobserve() {}
+ disconnect() {}
+ } as unknown as typeof ResizeObserver;
+ Element.prototype.scrollIntoView ??= () => {};
+});
+
+function renderList(selected: string[]) {
+ const onSelectedChange = vi.fn();
+ render(
+ Working {data}
( - Component: React.ComponentType
,
- errorFallback?: ReactNode,
-) {
- const WrappedComponent = (props: P) => (
- {hint}
- {perEra
- ? `${formatCount(perEra.CMIP6 ?? 0)} ran against CMIP6, ${formatCount(perEra.CMIP7 ?? 0)} against CMIP7`
- : "..."}
-
- {formatCount(successCount)} successful, {formatCount(failedCount)}{" "}
- failed
-
- {formatCount(scalarCount)} scalars, {formatCount(seriesCount)}{" "}
- series
-
- {maybeShowLoading(isLoading, totalFiles)} files tracked
- {note} {note}{title}
+ Filter by Providers
- Filter by AFT Diagnostics
- Filter by Themes
- Filter by Metric Values
-