From 016848e7954397dadf57cb7ffb5fe4ab7e0f9e6e Mon Sep 17 00:00:00 2001 From: Xavier Puspus <36430014+xmpuspus@users.noreply.github.com> Date: Wed, 8 Jul 2026 06:23:08 -0700 Subject: [PATCH 01/10] Fix live design crash: llm_call telemetry line kwargs to stdlib logger (v1.6.1) The per-call telemetry log passed structlog-style kwargs (model=, tokens=, ...) to the stdlib logger returned by get_logger(). Under the CLI, which enables root INFO via configure_logging(), this raised TypeError: Logger._log() got an unexpected keyword argument 'model' right after the model responded and tokens were billed, so every live `cloudwright design`/`modify` produced a traceback and no spec. Latent since v1.1.0: pytest leaves the root logger at WARNING, so info() short- circuits and the line never emitted or crashed under tests. Switch both the Anthropic and OpenAI providers to %-style stdlib formatting. Side effect: LLM telemetry (model, latency, tokens, cache hits) now actually emits. Regression: test_llm_telemetry_logging.py runs both providers under configure_logging() and asserts no crash. --- CHANGELOG.md | 8 ++ packages/cli/cloudwright_cli/__init__.py | 2 +- packages/core/cloudwright/__init__.py | 2 +- packages/core/cloudwright/llm/anthropic.py | 13 ++-- packages/core/cloudwright/llm/openai.py | 11 +-- packages/core/pyproject.toml | 8 +- .../core/tests/test_llm_telemetry_logging.py | 74 +++++++++++++++++++ packages/mcp/cloudwright_mcp/__init__.py | 2 +- packages/web/cloudwright_web/__init__.py | 2 +- server.json | 4 +- 10 files changed, 105 insertions(+), 21 deletions(-) create mode 100644 packages/core/tests/test_llm_telemetry_logging.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c16b28..250795a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.6.1] - 2026-07-08 + +Hotfix for a crash in the flagship command, found by the July 2026 product audit. + +### Fixed + +- **`cloudwright design` no longer crashes on a live API key.** The per-call telemetry line passed structlog-style keyword arguments (`model=`, `tokens=`, ...) to a stdlib logger, so the CLI (which enables root INFO logging) raised `TypeError: Logger._log() got an unexpected keyword argument 'model'` right after the model responded and tokens were billed, producing no spec. The line now uses `%`-style stdlib formatting in both the Anthropic and OpenAI providers. Latent since v1.1.0: the test suite leaves the root logger at WARNING, so the line silently never emitted and never crashed under pytest. Regression test `test_llm_telemetry_logging.py` runs both providers under `configure_logging()`. As a side effect, per-call LLM telemetry (model, latency, tokens, cache hits) now actually emits. + ## [1.6.0] - 2026-06-16 This release closes the defensibility + relevance gaps from the June 2026 product audit: diff --git a/packages/cli/cloudwright_cli/__init__.py b/packages/cli/cloudwright_cli/__init__.py index e4adfb8..f49459c 100644 --- a/packages/cli/cloudwright_cli/__init__.py +++ b/packages/cli/cloudwright_cli/__init__.py @@ -1 +1 @@ -__version__ = "1.6.0" +__version__ = "1.6.1" diff --git a/packages/core/cloudwright/__init__.py b/packages/core/cloudwright/__init__.py index 6d25d0d..c4535e6 100644 --- a/packages/core/cloudwright/__init__.py +++ b/packages/core/cloudwright/__init__.py @@ -17,7 +17,7 @@ ValidationResult, ) -__version__ = "1.6.0" +__version__ = "1.6.1" __all__ = [ "Alternative", diff --git a/packages/core/cloudwright/llm/anthropic.py b/packages/core/cloudwright/llm/anthropic.py index e74fbce..d4e0edc 100644 --- a/packages/core/cloudwright/llm/anthropic.py +++ b/packages/core/cloudwright/llm/anthropic.py @@ -190,13 +190,14 @@ def _call( "cached_tokens": cache_read, "cache_creation_tokens": cache_write, } + # stdlib logger: kwargs-style fields crash Logger._log, use %-style log.info( - "llm_call", - model=model, - duration_ms=round((time.perf_counter() - start) * 1000), - tokens=usage["input_tokens"] + usage["output_tokens"], - cache_read=cache_read, - cache_write=cache_write, + "llm_call model=%s duration_ms=%s tokens=%s cache_read=%s cache_write=%s", + model, + round((time.perf_counter() - start) * 1000), + usage["input_tokens"] + usage["output_tokens"], + cache_read, + cache_write, ) return response.content[0].text, usage except _RETRYABLE: diff --git a/packages/core/cloudwright/llm/openai.py b/packages/core/cloudwright/llm/openai.py index e920677..176a527 100644 --- a/packages/core/cloudwright/llm/openai.py +++ b/packages/core/cloudwright/llm/openai.py @@ -217,12 +217,13 @@ def _call( "output_tokens": response.usage.completion_tokens, "cached_tokens": cached, } + # stdlib logger: kwargs-style fields crash Logger._log, use %-style log.info( - "llm_call", - model=model, - duration_ms=round((time.perf_counter() - start) * 1000), - tokens=usage["input_tokens"] + usage["output_tokens"], - cached=cached, + "llm_call model=%s duration_ms=%s tokens=%s cached=%s", + model, + round((time.perf_counter() - start) * 1000), + usage["input_tokens"] + usage["output_tokens"], + cached, ) return content, usage except _RETRYABLE: diff --git a/packages/core/pyproject.toml b/packages/core/pyproject.toml index 58af9a1..708851f 100644 --- a/packages/core/pyproject.toml +++ b/packages/core/pyproject.toml @@ -29,10 +29,10 @@ dependencies = [ ] [project.optional-dependencies] -cli = ["cloudwright-ai-cli==1.6.0"] -web = ["cloudwright-ai-cli==1.6.0", "cloudwright-ai-web==1.6.0"] -mcp = ["cloudwright-ai-mcp==1.6.0"] -all = ["cloudwright-ai-cli==1.6.0", "cloudwright-ai-web==1.6.0", "cloudwright-ai-mcp==1.6.0", "databricks-sdk>=0.38.0"] +cli = ["cloudwright-ai-cli==1.6.1"] +web = ["cloudwright-ai-cli==1.6.1", "cloudwright-ai-web==1.6.1"] +mcp = ["cloudwright-ai-mcp==1.6.1"] +all = ["cloudwright-ai-cli==1.6.1", "cloudwright-ai-web==1.6.1", "cloudwright-ai-mcp==1.6.1", "databricks-sdk>=0.38.0"] pdf = ["weasyprint", "markdown2"] databricks = ["databricks-sdk>=0.38.0"] live-import = [ diff --git a/packages/core/tests/test_llm_telemetry_logging.py b/packages/core/tests/test_llm_telemetry_logging.py new file mode 100644 index 0000000..dbb72a7 --- /dev/null +++ b/packages/core/tests/test_llm_telemetry_logging.py @@ -0,0 +1,74 @@ +"""Regression: the llm_call telemetry line must survive configure_logging(). + +The CLI enables root INFO via configure_logging() on every invocation. Passing +structlog-style kwargs to the stdlib logger returned by get_logger() raised +TypeError: Logger._log() got an unexpected keyword argument 'model' +AFTER the SDK call returned, so every live design/modify billed tokens and then +crashed. pytest masked it because root stays at WARNING and info() short-circuits. +These tests pin the fix by running the providers with root at INFO. +""" + +from __future__ import annotations + +import logging as stdlib_logging +from unittest.mock import MagicMock + +import cloudwright.logging as cw_logging +import pytest +from cloudwright.llm.anthropic import AnthropicLLM +from cloudwright.llm.openai import OpenAILLM + + +@pytest.fixture() +def info_level_logging(): + root = stdlib_logging.getLogger() + saved_handlers = root.handlers[:] + saved_level = root.level + saved_flag = cw_logging._configured + cw_logging._configured = False + cw_logging.configure_logging() + yield + root.handlers[:] = saved_handlers + root.setLevel(saved_level) + cw_logging._configured = saved_flag + + +def _anthropic_response(text="ok"): + response = MagicMock() + response.content = [MagicMock(text=text)] + response.usage.input_tokens = 10 + response.usage.output_tokens = 5 + response.usage.cache_read_input_tokens = 0 + response.usage.cache_creation_input_tokens = 0 + return response + + +def _openai_response(text="ok"): + response = MagicMock() + response.choices = [MagicMock(message=MagicMock(content=text))] + response.usage.prompt_tokens = 10 + response.usage.completion_tokens = 5 + response.usage.prompt_tokens_details = MagicMock(cached_tokens=0) + return response + + +def test_anthropic_call_survives_configure_logging(info_level_logging): + llm = AnthropicLLM(api_key="test") + llm.client = MagicMock() + llm.client.messages.create.return_value = _anthropic_response("result") + + text, usage = llm.generate([{"role": "user", "content": "hi"}], "system") + + assert text == "result" + assert usage["input_tokens"] == 10 + + +def test_openai_call_survives_configure_logging(info_level_logging): + llm = OpenAILLM(api_key="test") + llm.client = MagicMock() + llm.client.chat.completions.create.return_value = _openai_response("result") + + text, usage = llm.generate([{"role": "user", "content": "hi"}], "system") + + assert text == "result" + assert usage["input_tokens"] == 10 diff --git a/packages/mcp/cloudwright_mcp/__init__.py b/packages/mcp/cloudwright_mcp/__init__.py index e4adfb8..f49459c 100644 --- a/packages/mcp/cloudwright_mcp/__init__.py +++ b/packages/mcp/cloudwright_mcp/__init__.py @@ -1 +1 @@ -__version__ = "1.6.0" +__version__ = "1.6.1" diff --git a/packages/web/cloudwright_web/__init__.py b/packages/web/cloudwright_web/__init__.py index 91db08f..b72f32c 100644 --- a/packages/web/cloudwright_web/__init__.py +++ b/packages/web/cloudwright_web/__init__.py @@ -1,6 +1,6 @@ """Cloudwright Web — FastAPI backend for architecture intelligence.""" -__version__ = "1.6.0" +__version__ = "1.6.1" def __getattr__(name: str): diff --git a/server.json b/server.json index 09504d2..92a50d0 100644 --- a/server.json +++ b/server.json @@ -2,7 +2,7 @@ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json", "name": "io.github.xmpuspus/cloudwright", "description": "Natural-language cloud architecture: deployable Terraform/Pulumi, cost, compliance control mapping.", - "version": "1.6.0", + "version": "1.6.1", "repository": { "url": "https://github.com/xmpuspus/cloudwright", "source": "github" @@ -12,7 +12,7 @@ "registryType": "pypi", "registryBaseUrl": "https://pypi.org", "identifier": "cloudwright-ai-mcp", - "version": "1.6.0", + "version": "1.6.1", "transport": { "type": "stdio" } From 510c781767df2640a017d241b7e939db599fcfed Mon Sep 17 00:00:00 2001 From: Xavier Puspus <36430014+xmpuspus@users.noreply.github.com> Date: Wed, 8 Jul 2026 06:40:43 -0700 Subject: [PATCH 02/10] Ops floor: CI pip-audit + version-sync gates, RELEASING/SECURITY docs, spec schema_version --- .github/workflows/ci.yml | 33 +++++++++ RELEASING.md | 105 +++++++++++++++++++++++++++ SECURITY.md | 37 ++++++++++ packages/core/cloudwright/spec.py | 5 ++ packages/core/tests/test_spec.py | 36 ++++++++++ scripts/check_version_sync.py | 115 ++++++++++++++++++++++++++++++ 6 files changed, 331 insertions(+) create mode 100644 RELEASING.md create mode 100644 SECURITY.md create mode 100644 scripts/check_version_sync.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0cbb747..9459a23 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,6 +46,39 @@ jobs: run: pytest packages/mcp/tests/ -x -q --timeout=30 if: hashFiles('packages/mcp/tests/') != '' + security: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + - name: Install packages + run: | + pip install --upgrade pip + pip install -e ./packages/core + pip install -e ./packages/cli + pip install -e ./packages/web + pip install -e ./packages/mcp + - run: pip install pip-audit + - name: Audit dependencies for known CVEs + # Blocking gate: verified locally (2026-07) that the real dependency + # tree (anthropic, openai, pydantic, pyyaml, fastapi, ...) is clean; + # the only prior noise was pip itself on an unpatched runner image, + # which the pip upgrade above resolves. The 4 cloudwright-ai-* local + # editable packages are skipped as "not found on PyPI", which is expected. + run: pip-audit + + version-sync: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + - name: Check version markers agree + run: python3 scripts/check_version_sync.py + build: runs-on: ubuntu-latest steps: diff --git a/RELEASING.md b/RELEASING.md new file mode 100644 index 0000000..6ef7c3f --- /dev/null +++ b/RELEASING.md @@ -0,0 +1,105 @@ +# Releasing Cloudwright + +This repo publishes four PyPI packages from one monorepo: `cloudwright-ai` (core), +`cloudwright-ai-cli`, `cloudwright-ai-web`, `cloudwright-ai-mcp`. All four always ship +together at the same version number. + +## 1. Bump the version in all four packages + +Edit `__version__` in: + +- `packages/core/cloudwright/__init__.py` +- `packages/cli/cloudwright_cli/__init__.py` +- `packages/web/cloudwright_web/__init__.py` +- `packages/mcp/cloudwright_mcp/__init__.py` + +Then update the `==X.Y.Z` extras pins in `packages/core/pyproject.toml` +(`cli`, `web`, `mcp`, `all`) to match. + +## 2. Bump server.json + +`server.json` describes the MCP registry entry. Update both: + +- the top-level `"version"` field +- `"packages"[0]["version"]` + +Keep `"description"` at 100 characters or fewer; the MCP registry rejects longer values. + +## 3. Update the changelog + +Add a new `## [X.Y.Z] - YYYY-MM-DD` section to `CHANGELOG.md` under `[Unreleased]`, +following the existing Keep a Changelog format. Update the README "What's new" section +if the release changes user-facing behavior. + +## 4. Verify version sync locally + +```bash +python3 scripts/check_version_sync.py +``` + +This checks that all four `__init__.py` files, the core package's extras pins, and +both version fields in `server.json` agree. It exits 1 with a listing of every +mismatched source if they don't. The same check runs in CI (`version-sync` job) and +gates every push, PR, and tag build. + +Optionally pass an expected version to check against a specific tag: + +```bash +python3 scripts/check_version_sync.py 1.7.0 +``` + +## 5. Branch, PR, merge + +- Cut a feature branch off `origin/main` for the version bump and changelog entry. +- Open a PR. Wait for CI to go green: `lint`, `test`, `security`, `version-sync`, `build`. +- Squash-merge to `main`. + +## 6. Tag and push + +```bash +git checkout main +git pull origin main +git tag -a vX.Y.Z -m "vX.Y.Z" +git push origin vX.Y.Z +``` + +Pushing a `v*` tag triggers `.github/workflows/publish.yml`, which re-runs the full CI +workflow and then builds and publishes all four wheels to PyPI using the +`PYPI_API_TOKEN` repository secret. + +Watch the run: + +```bash +gh run list --workflow=publish.yml +``` + +## 7. Smoke test the published wheels + +PyPI's CDN can lag a minute or two after a successful publish. Once the workflow +succeeds: + +```bash +python3 -m venv /tmp/release-verify +source /tmp/release-verify/bin/activate +pip install 'cloudwright-ai[cli]==X.Y.Z' +cloudwright --help +# exercise every new or changed CLI command with a minimal real input +``` + +Do not rely on an editable install for this step. Editable installs skip packaging +concerns entirely: missing bundled data files, wheel layout paths, and entry-point +bugs only show up against the built wheel. + +## 8. Publish to the MCP registry + +This step is interactive and requires the maintainer to log in. Once the wheels are +live on PyPI (the registry validates that the referenced package and version exist): + +```bash +mcp-publisher login github +mcp-publisher validate server.json +mcp-publisher publish server.json +``` + +After this, Glama's tool re-introspection for the updated server is a manual click in +the Glama dashboard and must be done by the maintainer separately. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..f881e80 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,37 @@ +# Security Policy + +## Supported Versions + +Cloudwright ships four packages (`cloudwright-ai`, `cloudwright-ai-cli`, +`cloudwright-ai-web`, `cloudwright-ai-mcp`) that always release together at the same +version. Only the latest published version on PyPI is supported with security fixes. +Older versions do not receive backports; upgrade to the latest release to pick up a fix. + +## Reporting a Vulnerability + +Do not open a public GitHub issue for a suspected security vulnerability. + +Instead, open a private security advisory on this repository: +https://github.com/xmpuspus/cloudwright/security/advisories/new + +Include: + +- A description of the vulnerability and its impact +- Steps to reproduce, or a minimal proof of concept +- The affected version(s) + +## Response Window + +Expect an initial response within 5 business days. Confirmed vulnerabilities are fixed +and released as soon as practical given severity; the reporter is credited in the +advisory and the release notes unless anonymity is requested. + +## Scope + +This policy covers the code in this repository: the ArchSpec model, the LLM-driven +architect, cost estimation, security/compliance scanning, the exporters (Terraform, +Pulumi, CloudFormation, OpenTofu), the live cloud importers, the CLI, the web backend +and frontend, and the MCP server. It does not cover the security of the third-party +cloud accounts, credentials, or generated infrastructure a user provisions with +Cloudwright's output; review generated Terraform/Pulumi/CloudFormation before applying +it, as you would any infrastructure code. diff --git a/packages/core/cloudwright/spec.py b/packages/core/cloudwright/spec.py index 21a05a5..d724352 100644 --- a/packages/core/cloudwright/spec.py +++ b/packages/core/cloudwright/spec.py @@ -173,6 +173,11 @@ class ArchSpec(BaseModel): name: str version: int = 1 + # Format version of the ArchSpec schema itself (distinct from `version`, + # which is the user's architecture revision number). Additive field: + # specs persisted before this field existed have no such key and load + # with the default below. + schema_version: str = "1.0" provider: str = "aws" region: str = "us-east-1" constraints: Constraints | None = None diff --git a/packages/core/tests/test_spec.py b/packages/core/tests/test_spec.py index 436000b..d31a70e 100644 --- a/packages/core/tests/test_spec.py +++ b/packages/core/tests/test_spec.py @@ -258,3 +258,39 @@ def test_spec_without_boundaries_backward_compat(): # Re-serialize and confirm boundaries is not emitted (clean_empty strips it) output = spec.to_yaml() assert "boundaries" not in output + + +def test_spec_without_schema_version_defaults(): + """A spec dict with no schema_version key (pre-existing saved specs) still loads.""" + yaml_str = """\ +name: Old Spec +provider: aws +region: us-east-1 +components: + - id: web + service: ec2 + provider: aws + label: Web + tier: 2 +connections: [] +""" + spec = ArchSpec.from_yaml(yaml_str) + assert spec.schema_version == "1.0" + + +def test_schema_version_roundtrip(): + spec = ArchSpec( + name="Versioned Spec", + schema_version="2.0", + components=[Component(id="web", service="ec2", provider="aws", label="Web", tier=2)], + ) + assert spec.schema_version == "2.0" + + yaml_str = spec.to_yaml() + assert "schema_version: '2.0'" in yaml_str or "schema_version: 2.0" in yaml_str + restored = ArchSpec.from_yaml(yaml_str) + assert restored.schema_version == "2.0" + + json_str = spec.to_json() + restored_json = ArchSpec.model_validate_json(json_str) + assert restored_json.schema_version == "2.0" diff --git a/scripts/check_version_sync.py b/scripts/check_version_sync.py new file mode 100644 index 0000000..7dd7331 --- /dev/null +++ b/scripts/check_version_sync.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python3 +"""Assert every version marker in the repo agrees before a release. + +Checks, all against each other (and optionally against an expected version +passed as the first CLI arg, e.g. a git tag stripped of its leading "v"): + + - __version__ in each of the 4 packages/*/*/__init__.py files + - the ==X.Y.Z extras pins in packages/core/pyproject.toml + - server.json top-level "version" + - server.json "packages"[0]["version"] + +No third-party dependencies. Exits 1 with a diff listing on any mismatch. +""" + +from __future__ import annotations + +import json +import re +import sys +from pathlib import Path + +ROOT = Path(__file__).resolve().parent.parent + +INIT_FILES = [ + ROOT / "packages/core/cloudwright/__init__.py", + ROOT / "packages/cli/cloudwright_cli/__init__.py", + ROOT / "packages/web/cloudwright_web/__init__.py", + ROOT / "packages/mcp/cloudwright_mcp/__init__.py", +] + +CORE_PYPROJECT = ROOT / "packages/core/pyproject.toml" +SERVER_JSON = ROOT / "server.json" + +VERSION_ASSIGN_RE = re.compile(r'__version__\s*=\s*"([^"]+)"') +EXTRAS_PIN_RE = re.compile(r"cloudwright-ai-(\w+)==([\d.]+)") + + +class SourceError(RuntimeError): + pass + + +def read_init_version(path: Path) -> str: + text = path.read_text() + match = VERSION_ASSIGN_RE.search(text) + if not match: + raise SourceError(f"no __version__ assignment found in {path}") + return match.group(1) + + +def read_pyproject_pins(path: Path) -> list[tuple[str, str]]: + text = path.read_text() + matches = EXTRAS_PIN_RE.findall(text) + if not matches: + raise SourceError(f"no cloudwright-ai-*==X.Y.Z pins found in {path}") + return [(f"cloudwright-ai-{name}", version) for name, version in matches] + + +def read_server_json(path: Path) -> list[tuple[str, str]]: + data = json.loads(path.read_text()) + if "version" not in data: + raise SourceError(f"no top-level 'version' key in {path}") + packages = data.get("packages") or [] + if not packages or "version" not in packages[0]: + raise SourceError(f"no packages[0].version key in {path}") + return [ + ("server.json version", data["version"]), + ("server.json packages[0].version", packages[0]["version"]), + ] + + +def collect_sources() -> list[tuple[str, str]]: + sources: list[tuple[str, str]] = [] + + for init_path in INIT_FILES: + label = f"{init_path.relative_to(ROOT)} __version__" + sources.append((label, read_init_version(init_path))) + + for i, (name, version) in enumerate(read_pyproject_pins(CORE_PYPROJECT), start=1): + label = f"packages/core/pyproject.toml pin #{i} ({name})" + sources.append((label, version)) + + for label, version in read_server_json(SERVER_JSON): + sources.append((label, version)) + + return sources + + +def main() -> int: + expected = sys.argv[1].lstrip("v") if len(sys.argv) > 1 else None + + try: + sources = collect_sources() + except SourceError as exc: + print(f"check_version_sync: {exc}", file=sys.stderr) + return 1 + + versions = {version for _, version in sources} + ok = len(versions) == 1 + if ok and expected is not None: + ok = expected in versions + + if ok: + print(f"All {len(sources)} version markers agree: {sources[0][1]}") + return 0 + + print("Version mismatch across the repo:", file=sys.stderr) + for label, version in sources: + print(f" {version:12s} {label}", file=sys.stderr) + if expected is not None: + print(f"\nExpected version: {expected}", file=sys.stderr) + return 1 + + +if __name__ == "__main__": + sys.exit(main()) From 8de3a835f0fa0605bb481d5306b5d5807da70b45 Mon Sep 17 00:00:00 2001 From: Xavier Puspus <36430014+xmpuspus@users.noreply.github.com> Date: Wed, 8 Jul 2026 06:40:49 -0700 Subject: [PATCH 03/10] CLI: clean error rendering + JSON error envelope via cloudwright_command decorator --- packages/cli/cloudwright_cli/decorators.py | 32 +++++++------- packages/cli/cloudwright_cli/main.py | 51 +++++++++++----------- packages/cli/cloudwright_cli/output.py | 26 ++++++++++- packages/cli/tests/test_cli.py | 51 ++++++++++++++++++++++ 4 files changed, 118 insertions(+), 42 deletions(-) diff --git a/packages/cli/cloudwright_cli/decorators.py b/packages/cli/cloudwright_cli/decorators.py index 393957e..bf238da 100644 --- a/packages/cli/cloudwright_cli/decorators.py +++ b/packages/cli/cloudwright_cli/decorators.py @@ -1,20 +1,27 @@ from __future__ import annotations import functools -import traceback from typing import Any, Callable import typer from rich.console import Console +from cloudwright_cli.output import emit_error + err_console = Console(stderr=True) def cloudwright_command(json_output: bool = True, dry_run: bool = False) -> Callable: """Decorator that wraps command functions with standard output handling. - Handles: JSON envelope wrapping, Rich console formatting, --verbose stack - traces, --dry-run interception, and exit codes. + Catches any exception the command function doesn't already handle and + renders it cleanly instead of letting a raw traceback reach the user: + a JSON envelope (via `output.emit_error`) in --json mode, a plain + `Error: ...` on stderr otherwise, full traceback only under --verbose. + + Commands that already call `output.emit_error` themselves for specific + known failures are unaffected — that path raises `typer.Exit`, which + this decorator re-raises untouched. Args: json_output: Whether the command supports --json output mode. @@ -26,13 +33,6 @@ def decorator(fn: Callable) -> Callable: def wrapper(*args: Any, **kwargs: Any) -> None: # Extract typer context from positional or keyword args ctx = _extract_ctx(fn, args, kwargs) - verbose = bool(ctx and ctx.obj and ctx.obj.get("verbose")) - is_dry = dry_run and bool(ctx and ctx.obj and ctx.obj.get("dry_run")) - - if is_dry: - # Commands that handle dry_run themselves will see ctx.obj["dry_run"] - # This outer gate lets the inner function emit_dry_run and exit. - pass try: fn(*args, **kwargs) @@ -41,13 +41,13 @@ def wrapper(*args: Any, **kwargs: Any) -> None: except SystemExit: raise except Exception as e: - if verbose: - err_console.print_exception() - else: + if ctx is None: + # Commands without a ctx param (e.g. mcp_serve) can't + # report JSON mode or verbosity — fall back to a plain + # stderr message. err_console.print(f"[red]Error:[/red] {e}") - if verbose: - err_console.print(traceback.format_exc()) - raise typer.Exit(1) + raise typer.Exit(1) from None + emit_error(ctx, e) return wrapper diff --git a/packages/cli/cloudwright_cli/main.py b/packages/cli/cloudwright_cli/main.py index 4f5984f..ab04692 100644 --- a/packages/cli/cloudwright_cli/main.py +++ b/packages/cli/cloudwright_cli/main.py @@ -27,6 +27,7 @@ from cloudwright_cli.commands.score_cmd import score from cloudwright_cli.commands.security_cmd import security_scan from cloudwright_cli.commands.validate import validate +from cloudwright_cli.decorators import cloudwright_command def _version_callback(value: bool) -> None: @@ -63,29 +64,29 @@ def main( ctx.obj["stream"] = stream -app.command()(design) -app.command()(cost) -app.command()(compare) -app.command()(validate) -app.command()(export) -app.command()(diff) -app.command()(drift) -app.command()(modify) -app.command(name="import")(import_infra) -app.command(name="import-live")(import_live) -app.command()(chat) -app.command()(init) -app.command()(plan) -app.command()(policy) -app.command()(score) -app.command()(review) -app.command()(analyze) -app.command()(refresh) -app.command()(lint) -app.command()(databricks_validate) -app.command(name="security")(security_scan) -app.command(name="compliance")(compliance_scan) -app.command(name="adr")(adr) -app.command()(schema) -app.command(name="mcp")(mcp_serve) +app.command()(cloudwright_command()(design)) +app.command()(cloudwright_command()(cost)) +app.command()(cloudwright_command()(compare)) +app.command()(cloudwright_command()(validate)) +app.command()(cloudwright_command()(export)) +app.command()(cloudwright_command()(diff)) +app.command()(cloudwright_command()(drift)) +app.command()(cloudwright_command()(modify)) +app.command(name="import")(cloudwright_command()(import_infra)) +app.command(name="import-live")(cloudwright_command()(import_live)) +app.command()(cloudwright_command()(chat)) +app.command()(cloudwright_command()(init)) +app.command()(cloudwright_command()(plan)) +app.command()(cloudwright_command()(policy)) +app.command()(cloudwright_command()(score)) +app.command()(cloudwright_command()(review)) +app.command()(cloudwright_command()(analyze)) +app.command()(cloudwright_command()(refresh)) +app.command()(cloudwright_command()(lint)) +app.command()(cloudwright_command()(databricks_validate)) +app.command(name="security")(cloudwright_command()(security_scan)) +app.command(name="compliance")(cloudwright_command()(compliance_scan)) +app.command(name="adr")(cloudwright_command()(adr)) +app.command()(cloudwright_command()(schema)) +app.command(name="mcp")(cloudwright_command()(mcp_serve)) app.add_typer(catalog_app, name="catalog") diff --git a/packages/cli/cloudwright_cli/output.py b/packages/cli/cloudwright_cli/output.py index 3eb419a..3eb4894 100644 --- a/packages/cli/cloudwright_cli/output.py +++ b/packages/cli/cloudwright_cli/output.py @@ -39,7 +39,7 @@ def emit_error( if code is None: code = _classify_error(e) - msg = str(e) + msg = _friendly_message(e) if is_json_mode(ctx): envelope: dict[str, Any] = { @@ -129,6 +129,30 @@ def _get_flag(ctx: typer.Context, key: str) -> bool: return bool(ctx.obj and ctx.obj.get(key)) +def _friendly_message(e: Exception) -> str: + """Render a readable message for an exception. + + Pydantic ValidationError (raised by ArchSpec.from_file on a malformed + spec) dumps a multi-line repr with a docs URL — turn its first error + into a one-line "Invalid spec file: field 'x' is required" instead. + Anything else falls back to str(e). + """ + errors_fn = getattr(e, "errors", None) + if not callable(errors_fn): + return str(e) + try: + errs = errors_fn() + except Exception: + return str(e) + if not errs: + return str(e) + + first = errs[0] + loc = ".".join(str(p) for p in first.get("loc", ())) or "spec" + detail = "is required" if first.get("type") == "missing" else first.get("msg", "is invalid") + return f"Invalid spec file: field {loc!r} {detail}" + + def _classify_error(e: Exception) -> str: import yaml diff --git a/packages/cli/tests/test_cli.py b/packages/cli/tests/test_cli.py index da02c11..1e2e14f 100644 --- a/packages/cli/tests/test_cli.py +++ b/packages/cli/tests/test_cli.py @@ -338,3 +338,54 @@ def test_json_error_output(self, tmp_path: Path): def test_verbose_flag_accepted(self, spec_file: Path): result = runner.invoke(app, ["--verbose", "cost", str(spec_file)]) assert result.exit_code == 0 + + def test_missing_field_renders_clean_error_not_raw_traceback(self, tmp_path: Path): + """A spec missing a required field must not leak an unhandled exception + through Click — it should be caught and rendered as `Error: ...` on stderr.""" + bad = tmp_path / "missing_name.yaml" + bad.write_text("version: 1\nprovider: aws\nregion: us-east-1\ncomponents: []\n") + result = runner.invoke(app, ["cost", str(bad)]) + assert result.exit_code == 1 + # A clean exit raises typer.Exit -> SystemExit; anything else means the + # underlying exception (e.g. pydantic ValidationError) leaked uncaught. + assert isinstance(result.exception, SystemExit), f"exception leaked uncaught: {result.exception!r}" + assert "Error:" in result.stderr + assert "name" in result.stderr + + def test_missing_field_json_envelope(self, tmp_path: Path): + """Same malformed spec under global --json prints a parseable error envelope.""" + bad = tmp_path / "missing_name.yaml" + bad.write_text("version: 1\nprovider: aws\nregion: us-east-1\ncomponents: []\n") + result = runner.invoke(app, ["--json", "cost", str(bad)]) + assert result.exit_code == 1 + # A clean exit raises typer.Exit -> SystemExit; anything else means the + # underlying exception (e.g. pydantic ValidationError) leaked uncaught. + assert isinstance(result.exception, SystemExit), f"exception leaked uncaught: {result.exception!r}" + data = json.loads(result.stdout) + assert "error" in data + assert "code" in data["error"] + assert "message" in data["error"] + assert "name" in data["error"]["message"] + + def test_validate_missing_field_no_raw_traceback(self, tmp_path: Path): + bad = tmp_path / "missing_name.yaml" + bad.write_text("version: 1\nprovider: aws\nregion: us-east-1\ncomponents: []\n") + result = runner.invoke(app, ["validate", str(bad), "--compliance", "hipaa"]) + assert result.exit_code == 1 + # A clean exit raises typer.Exit -> SystemExit; anything else means the + # underlying exception (e.g. pydantic ValidationError) leaked uncaught. + assert isinstance(result.exception, SystemExit), f"exception leaked uncaught: {result.exception!r}" + assert "Error:" in result.stderr + + def test_valid_spec_cost_still_succeeds(self, spec_file: Path): + """Success path output must be unaffected by the error-handling change.""" + result = runner.invoke(app, ["cost", str(spec_file)]) + assert result.exit_code == 0 + assert "Cost Breakdown" in result.stdout + + def test_valid_spec_cost_json_still_succeeds(self, spec_file: Path): + result = runner.invoke(app, ["--json", "cost", str(spec_file)]) + assert result.exit_code == 0 + data = json.loads(result.stdout) + assert "data" in data + assert "error" not in data From 5e8d9ee89d6c4d0d83f767af04b4143cab2bee9e Mon Sep 17 00:00:00 2001 From: Xavier Puspus <36430014+xmpuspus@users.noreply.github.com> Date: Wed, 8 Jul 2026 06:45:52 -0700 Subject: [PATCH 04/10] Web hardening: diagram to_thread, body/component caps, rate-limiter eviction, container auth guard, logging on launch --- Dockerfile | 5 + docker-compose.yml | 2 +- packages/web/cloudwright_web/app.py | 34 ++++++ packages/web/cloudwright_web/middleware.py | 115 +++++++++++++++++- .../web/cloudwright_web/routers/compliance.py | 4 +- packages/web/cloudwright_web/routers/cost.py | 6 +- .../web/cloudwright_web/routers/design.py | 15 ++- .../web/cloudwright_web/routers/diagram.py | 43 +++++-- .../web/cloudwright_web/routers/export.py | 6 +- packages/web/cloudwright_web/routers/plan.py | 4 +- .../web/cloudwright_web/routers/validate.py | 4 +- packages/web/tests/test_auth_guard.py | 54 ++++++++ packages/web/tests/test_diagram_hardening.py | 99 +++++++++++++++ .../test_logging_configured_on_launch.py | 38 ++++++ .../web/tests/test_rate_limiter_eviction.py | 90 ++++++++++++++ packages/web/tests/test_spec_size_limits.py | 106 ++++++++++++++++ 16 files changed, 602 insertions(+), 23 deletions(-) create mode 100644 packages/web/tests/test_auth_guard.py create mode 100644 packages/web/tests/test_diagram_hardening.py create mode 100644 packages/web/tests/test_logging_configured_on_launch.py create mode 100644 packages/web/tests/test_rate_limiter_eviction.py create mode 100644 packages/web/tests/test_spec_size_limits.py diff --git a/Dockerfile b/Dockerfile index 7819d50..9a2d6a6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,6 +9,11 @@ COPY packages/web/cloudwright_web/ packages/web/cloudwright_web/ RUN pip install --no-cache-dir ./packages/core ./packages/web +# This CMD binds 0.0.0.0 directly via uvicorn, bypassing the CLI's serve() +# (the only place that used to enforce CLOUDWRIGHT_API_KEY). Setting this +# makes cloudwright_web.app.create_app() refuse to start unauthenticated. +ENV CLOUDWRIGHT_REQUIRE_AUTH=1 + EXPOSE 8000 CMD ["uvicorn", "cloudwright_web.app:app", "--host", "0.0.0.0", "--port", "8000"] diff --git a/docker-compose.yml b/docker-compose.yml index 78490d3..fb81793 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,7 +4,7 @@ services: ports: - "8000:8000" environment: - - CLOUDWRIGHT_API_KEY=${CLOUDWRIGHT_API_KEY} + - CLOUDWRIGHT_API_KEY=${CLOUDWRIGHT_API_KEY:?set CLOUDWRIGHT_API_KEY} - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} - CLOUDWRIGHT_CORS_ORIGINS=${CLOUDWRIGHT_CORS_ORIGINS:-http://localhost:5173} - CLOUDWRIGHT_LOG_FORMAT=json diff --git a/packages/web/cloudwright_web/app.py b/packages/web/cloudwright_web/app.py index 9601b7b..cdf0301 100644 --- a/packages/web/cloudwright_web/app.py +++ b/packages/web/cloudwright_web/app.py @@ -13,6 +13,8 @@ from cloudwright_web import __version__ from cloudwright_web.middleware import ( # noqa: F401 + MAX_BODY_BYTES, + BodySizeLimitMiddleware, PathTraversalMiddleware, RequestIdMiddleware, _rate_limiter, @@ -60,7 +62,38 @@ def _docs_enabled() -> bool: return env != "production" +def _enforce_auth_requirement() -> None: + """Refuse to start unauthenticated when explicitly required. + + ``check_api_key`` silently disables auth when CLOUDWRIGHT_API_KEY is + unset — a deliberate local-dev convenience. But the Dockerfile CMD runs + ``uvicorn cloudwright_web.app:app`` directly, which never calls + ``serve()`` (the only place that used to enforce the key), so a + container started without CLOUDWRIGHT_API_KEY silently serves every + route unauthenticated on 0.0.0.0. + + The Dockerfile sets CLOUDWRIGHT_REQUIRE_AUTH=1 so that path now fails + fast at startup instead. Local uvicorn/pytest runs leave the flag unset + and stay open-by-default, unchanged. + """ + require_auth = os.environ.get("CLOUDWRIGHT_REQUIRE_AUTH", "").strip().lower() in ("1", "true", "yes") + if require_auth and not os.environ.get("CLOUDWRIGHT_API_KEY"): + raise SystemExit( + "CLOUDWRIGHT_REQUIRE_AUTH is set but CLOUDWRIGHT_API_KEY is not. " + "Refusing to start an unauthenticated server. Set CLOUDWRIGHT_API_KEY." + ) + + def create_app() -> FastAPI: + from cloudwright.logging import configure_logging + + # Fire on every import of this module (bare `uvicorn cloudwright_web.app:app`, + # `cloudwright chat --web`, pytest), not just the CLI's serve() path. + # Idempotent — safe to call again from serve(). + configure_logging() + + _enforce_auth_requirement() + docs_on = _docs_enabled() application = FastAPI( title="Cloudwright", @@ -74,6 +107,7 @@ def create_app() -> FastAPI: # RequestIdMiddleware MUST be added LAST so Starlette dispatches it FIRST # (Starlette runs middleware in reverse-add order). This way every later # middleware's log lines carry the request_id. + application.add_middleware(BodySizeLimitMiddleware, max_bytes=MAX_BODY_BYTES) application.add_middleware(SecurityHeadersMiddleware) application.add_middleware(PathTraversalMiddleware) add_cors(application) diff --git a/packages/web/cloudwright_web/middleware.py b/packages/web/cloudwright_web/middleware.py index 70aa337..6458639 100644 --- a/packages/web/cloudwright_web/middleware.py +++ b/packages/web/cloudwright_web/middleware.py @@ -16,6 +16,76 @@ from fastapi.responses import JSONResponse from starlette.middleware.base import BaseHTTPMiddleware +MAX_BODY_BYTES = 1_000_000 # 1 MB + + +class BodySizeLimitMiddleware: + """Reject request bodies over ``max_bytes`` before a route handler ever + buffers or parses them. + + Pure ASGI middleware (not ``BaseHTTPMiddleware``) so we can check the + declared ``Content-Length`` up front AND wrap ``receive`` to enforce the + same cap against the actual bytes streamed in, since a client can lie + about (or omit) Content-Length. + """ + + def __init__(self, app, max_bytes: int = MAX_BODY_BYTES): + self.app = app + self._max_bytes = max_bytes + + async def __call__(self, scope, receive, send): + if scope["type"] != "http": + await self.app(scope, receive, send) + return + + headers = dict(scope.get("headers") or []) + content_length = headers.get(b"content-length") + if content_length is not None: + try: + if int(content_length) > self._max_bytes: + await self._reject(send) + return + except ValueError: + pass + + total = 0 + + async def limited_receive(): + nonlocal total + message = await receive() + if message["type"] == "http.request": + total += len(message.get("body", b"")) + if total > self._max_bytes: + raise _BodyTooLargeError + return message + + try: + await self.app(scope, limited_receive, send) + except _BodyTooLargeError: + await self._reject(send) + + async def _reject(self, send): + await send( + { + "type": "http.response.start", + "status": 413, + "headers": [(b"content-type", b"application/json")], + } + ) + await send( + { + "type": "http.response.body", + "body": ( + b'{"code":"payload_too_large","message":"Request body too large",' + b'"suggestion":"Reduce the request size"}' + ), + } + ) + + +class _BodyTooLargeError(Exception): + pass + class PathTraversalMiddleware(BaseHTTPMiddleware): async def dispatch(self, request: Request, call_next): @@ -103,11 +173,20 @@ def is_allowed(self, ip: str) -> tuple[bool, int]: now = time.time() cutoff = now - self._window with self._lock: - if ip not in self._buckets: - self._buckets[ip] = deque() - bucket = self._buckets[ip] - while bucket and bucket[0] < cutoff: - bucket.popleft() + # Sweep every IP's bucket, not just the one making this request. + # Pruning only the current IP's bucket never actually shrinks the + # dict: a one-off caller (rotating IP, scanner, CDN churn) is + # never seen again to trigger its own prune, so its entry sits + # forever. Sweeping all buckets here bounds dict size by the + # number of distinct IPs active within the last window, not the + # number ever seen over the life of the process. + for other_ip, other_bucket in list(self._buckets.items()): + while other_bucket and other_bucket[0] < cutoff: + other_bucket.popleft() + if not other_bucket: + del self._buckets[other_ip] + + bucket = self._buckets.setdefault(ip, deque()) if len(bucket) >= self._max: retry_after = int(self._window - (now - bucket[0])) + 1 if bucket else int(self._window) + 1 return False, retry_after @@ -148,3 +227,29 @@ def check_rate_limit(request: Request): headers={"Retry-After": str(retry_after)}, ) return None + + +# --- Spec size cap --- + +MAX_SPEC_COMPONENTS = 200 + + +def check_component_limit(spec) -> JSONResponse | None: + """Reject a validated ``ArchSpec`` with an unreasonable component count. + + Downstream work (cost estimation, rendering, terraform export, LLM + modify calls) scales with component count, so an attacker-controlled + spec with thousands of components turns one request into unbounded + server-side work. Mirrors the ``check_rate_limit`` return-on-error + pattern so callers do ``if err := check_component_limit(spec): return err`` + regardless of whether that router otherwise raises HTTPException. + """ + count = len(spec.components) + if count > MAX_SPEC_COMPONENTS: + return error_response( + "spec_too_large", + f"Spec has {count} components; max allowed is {MAX_SPEC_COMPONENTS}", + "Split the architecture into smaller specs", + 422, + ) + return None diff --git a/packages/web/cloudwright_web/routers/compliance.py b/packages/web/cloudwright_web/routers/compliance.py index 061da5e..924cb7a 100644 --- a/packages/web/cloudwright_web/routers/compliance.py +++ b/packages/web/cloudwright_web/routers/compliance.py @@ -10,7 +10,7 @@ from fastapi import APIRouter, HTTPException, Request from pydantic import BaseModel, Field -from cloudwright_web.middleware import check_api_key, check_rate_limit +from cloudwright_web.middleware import check_api_key, check_component_limit, check_rate_limit log = logging.getLogger(__name__) router = APIRouter() @@ -29,6 +29,8 @@ async def compliance(req: ComplianceRequest, request: Request): return err try: spec = ArchSpec.model_validate(req.spec) + if err := check_component_limit(spec): + return err report = await asyncio.to_thread( ComplianceScanner().scan, spec, diff --git a/packages/web/cloudwright_web/routers/cost.py b/packages/web/cloudwright_web/routers/cost.py index ea38ee2..a1c504f 100644 --- a/packages/web/cloudwright_web/routers/cost.py +++ b/packages/web/cloudwright_web/routers/cost.py @@ -13,7 +13,7 @@ from pydantic import BaseModel, Field import cloudwright_web.singletons as _singletons -from cloudwright_web.middleware import check_api_key, check_rate_limit +from cloudwright_web.middleware import check_api_key, check_component_limit, check_rate_limit log = logging.getLogger(__name__) router = APIRouter() @@ -84,6 +84,8 @@ async def cost(req: CostRequest, request: Request): result: dict = {"estimate": cached} if req.compare_providers: spec = ArchSpec.model_validate(spec_dict) + if err := check_component_limit(spec): + return err architect = _singletons.get_architect() alternatives = await asyncio.to_thread(architect.compare, spec, req.compare_providers) result["alternatives"] = [a.model_dump(exclude_none=True) for a in alternatives] @@ -91,6 +93,8 @@ async def cost(req: CostRequest, request: Request): engine = _singletons.get_cost_engine() spec = ArchSpec.model_validate(spec_dict) + if err := check_component_limit(spec): + return err estimate = await asyncio.to_thread(engine.estimate, spec) cache.set_cost(spec_dict, estimate.model_dump()) diff --git a/packages/web/cloudwright_web/routers/design.py b/packages/web/cloudwright_web/routers/design.py index 291ca48..32c29e8 100644 --- a/packages/web/cloudwright_web/routers/design.py +++ b/packages/web/cloudwright_web/routers/design.py @@ -11,7 +11,7 @@ from pydantic import BaseModel, Field import cloudwright_web.singletons as _singletons -from cloudwright_web.middleware import check_api_key, check_rate_limit, error_response +from cloudwright_web.middleware import check_api_key, check_component_limit, check_rate_limit, error_response from cloudwright_web.streaming import sse_event log = logging.getLogger(__name__) @@ -145,6 +145,8 @@ async def modify(req: ModifyRequest, request: Request): try: architect = _singletons.get_architect() spec = ArchSpec.model_validate(req.spec) + if err := check_component_limit(spec): + return err try: updated = await asyncio.wait_for(asyncio.to_thread(architect.modify, spec, req.instruction), timeout=120) except asyncio.TimeoutError: @@ -162,9 +164,18 @@ async def modify_stream(req: ModifyRequest, request: Request): if err := check_rate_limit(request): return err + # Validate and cap the spec before opening the SSE stream: once + # StreamingResponse starts, headers/status are already sent and we can no + # longer turn a bad or oversized spec into a plain 400/422 response. + try: + spec = ArchSpec.model_validate(req.spec) + except Exception as e: + return error_response("invalid_spec", str(e), "Check the spec matches the ArchSpec schema", 400) + if err := check_component_limit(spec): + return err + async def event_generator(): architect = _singletons.get_architect() - spec = ArchSpec.model_validate(req.spec) yield sse_event("modifying", message="Applying modifications...") diff --git a/packages/web/cloudwright_web/routers/diagram.py b/packages/web/cloudwright_web/routers/diagram.py index 46e233e..318e3f9 100644 --- a/packages/web/cloudwright_web/routers/diagram.py +++ b/packages/web/cloudwright_web/routers/diagram.py @@ -2,28 +2,51 @@ from __future__ import annotations +import asyncio +import logging + from cloudwright import ArchSpec from fastapi import APIRouter, Request from fastapi.responses import Response +from pydantic import BaseModel -from cloudwright_web.middleware import check_api_key, check_rate_limit +from cloudwright_web.middleware import check_api_key, check_component_limit, check_rate_limit, error_response +log = logging.getLogger(__name__) router = APIRouter() +class DiagramRequest(BaseModel): + spec: dict + format: str = "svg" + + @router.post("/diagram") -async def render_diagram(request: Request): +async def render_diagram(req: DiagramRequest, request: Request): check_api_key(request) if err := check_rate_limit(request): return err - data = await request.json() - spec = ArchSpec.model_validate(data["spec"]) - fmt = data.get("format", "svg") + try: + spec = ArchSpec.model_validate(req.spec) + except Exception as e: + return error_response("invalid_spec", str(e), "Check the spec matches the ArchSpec schema", 400) + + if err := check_component_limit(spec): + return err + from cloudwright.exporter.renderer import DiagramRenderer renderer = DiagramRenderer() - if fmt == "png": - png_data = renderer.render_png(spec) - return Response(content=png_data, media_type="image/png") - svg = renderer.render_svg(spec) - return Response(content=svg, media_type="image/svg+xml") + try: + # The D2 subprocess can run up to 300s (renderer.py's PNG timeout). + # Running it inline would block the event loop for every other + # request for that long; asyncio.to_thread pushes it off-loop, same + # pattern as routers/plan.py's terraform/pulumi subprocess calls. + if req.format == "png": + png_data = await asyncio.to_thread(renderer.render_png, spec) + return Response(content=png_data, media_type="image/png") + svg = await asyncio.to_thread(renderer.render_svg, spec) + return Response(content=svg, media_type="image/svg+xml") + except Exception as e: + log.exception("Diagram render failed") + return error_response("render_failed", str(e), "Check the D2 binary is installed and the spec is valid", 500) diff --git a/packages/web/cloudwright_web/routers/export.py b/packages/web/cloudwright_web/routers/export.py index 28bb365..b4c1919 100644 --- a/packages/web/cloudwright_web/routers/export.py +++ b/packages/web/cloudwright_web/routers/export.py @@ -11,7 +11,7 @@ from fastapi.responses import Response from pydantic import BaseModel -from cloudwright_web.middleware import check_api_key, check_rate_limit +from cloudwright_web.middleware import check_api_key, check_component_limit, check_rate_limit log = logging.getLogger(__name__) router = APIRouter() @@ -29,6 +29,8 @@ def export(req: ExportRequest, request: Request): return err try: spec = ArchSpec.model_validate(req.spec) + if err := check_component_limit(spec): + return err if req.format not in FORMATS: raise HTTPException( status_code=400, detail=f"Unknown format: {req.format}. Supported: {', '.join(FORMATS)}" @@ -50,6 +52,8 @@ async def download(request: Request): try: data = await request.json() spec = ArchSpec.model_validate(data["spec"]) + if err := check_component_limit(spec): + return err fmt = data.get("format", "terraform") safe_name = re.sub(r"[^\w\-.]", "-", spec.name.lower()) if fmt == "yaml": diff --git a/packages/web/cloudwright_web/routers/plan.py b/packages/web/cloudwright_web/routers/plan.py index 5f5fbe2..ee305af 100644 --- a/packages/web/cloudwright_web/routers/plan.py +++ b/packages/web/cloudwright_web/routers/plan.py @@ -10,7 +10,7 @@ from fastapi import APIRouter, HTTPException, Request from pydantic import BaseModel -from cloudwright_web.middleware import check_api_key, check_rate_limit +from cloudwright_web.middleware import check_api_key, check_component_limit, check_rate_limit log = logging.getLogger(__name__) router = APIRouter() @@ -29,6 +29,8 @@ async def plan(req: PlanRequest, request: Request): return err try: spec = ArchSpec.model_validate(req.spec) + if err := check_component_limit(spec): + return err result = await asyncio.to_thread(run_plan, spec, req.target, run_plan=req.run_plan, timeout=180) return result.as_dict() except ValueError as e: diff --git a/packages/web/cloudwright_web/routers/validate.py b/packages/web/cloudwright_web/routers/validate.py index 3b3a207..d6cdd63 100644 --- a/packages/web/cloudwright_web/routers/validate.py +++ b/packages/web/cloudwright_web/routers/validate.py @@ -10,7 +10,7 @@ from fastapi import APIRouter, HTTPException, Request from pydantic import BaseModel, Field -from cloudwright_web.middleware import check_api_key, check_rate_limit +from cloudwright_web.middleware import check_api_key, check_component_limit, check_rate_limit from cloudwright_web.routers.cost import cache log = logging.getLogger(__name__) @@ -36,6 +36,8 @@ async def validate(req: ValidateRequest, request: Request): validator = Validator() spec = ArchSpec.model_validate(req.spec) + if err := check_component_limit(spec): + return err frameworks = req.compliance if req.compliance else [] results = await asyncio.to_thread( validator.validate, spec, compliance=frameworks or None, well_architected=req.well_architected diff --git a/packages/web/tests/test_auth_guard.py b/packages/web/tests/test_auth_guard.py new file mode 100644 index 0000000..02d41fc --- /dev/null +++ b/packages/web/tests/test_auth_guard.py @@ -0,0 +1,54 @@ +"""HIGH audit finding: Docker path ships auth-open on 0.0.0.0. + +``serve()`` enforces ``CLOUDWRIGHT_API_KEY`` before starting uvicorn, but the +Dockerfile's CMD runs ``uvicorn cloudwright_web.app:app`` directly, which never +calls ``serve()``. Middleware's ``check_api_key`` silently disables auth when +the key is unset, so a container started without the env var serves every +route unauthenticated on ``0.0.0.0``. + +Fix: ``create_app()`` calls a guard that refuses to start when +``CLOUDWRIGHT_REQUIRE_AUTH`` is set (the Dockerfile sets it) and +``CLOUDWRIGHT_API_KEY`` is not. Local ``uvicorn``/pytest runs must stay +open-by-default (``CLOUDWRIGHT_REQUIRE_AUTH`` unset), so the 99 pre-existing +web tests are unaffected. +""" + +from __future__ import annotations + +import pytest +from cloudwright_web.app import _enforce_auth_requirement + + +class TestRequireAuthGuard: + def test_raises_when_required_and_key_missing(self, monkeypatch): + monkeypatch.setenv("CLOUDWRIGHT_REQUIRE_AUTH", "1") + monkeypatch.delenv("CLOUDWRIGHT_API_KEY", raising=False) + with pytest.raises(SystemExit): + _enforce_auth_requirement() + + def test_does_not_raise_when_required_and_key_present(self, monkeypatch): + monkeypatch.setenv("CLOUDWRIGHT_REQUIRE_AUTH", "1") + monkeypatch.setenv("CLOUDWRIGHT_API_KEY", "secret-value") + _enforce_auth_requirement() + + def test_does_not_raise_when_not_required_even_if_key_missing(self, monkeypatch): + """Local dev / pytest default: open when the flag is unset.""" + monkeypatch.delenv("CLOUDWRIGHT_REQUIRE_AUTH", raising=False) + monkeypatch.delenv("CLOUDWRIGHT_API_KEY", raising=False) + _enforce_auth_requirement() + + @pytest.mark.parametrize("falsy_value", ["0", "false", "no", ""]) + def test_falsy_require_auth_values_do_not_raise(self, monkeypatch, falsy_value): + monkeypatch.setenv("CLOUDWRIGHT_REQUIRE_AUTH", falsy_value) + monkeypatch.delenv("CLOUDWRIGHT_API_KEY", raising=False) + _enforce_auth_requirement() + + +class TestAppStillImportsInDefaultTestEnv: + def test_app_module_imports_without_require_auth_set(self): + """The 99 pre-existing web tests import ``cloudwright_web.app`` with + no CLOUDWRIGHT_REQUIRE_AUTH set — module import (which calls + create_app() -> _enforce_auth_requirement()) must not raise.""" + from cloudwright_web.app import app + + assert app is not None diff --git a/packages/web/tests/test_diagram_hardening.py b/packages/web/tests/test_diagram_hardening.py new file mode 100644 index 0000000..2a044ca --- /dev/null +++ b/packages/web/tests/test_diagram_hardening.py @@ -0,0 +1,99 @@ +"""``/api/diagram`` hardening. + +Audit findings fixed here: +1. HIGH — the D2 subprocess render (up to 300s for PNG) ran synchronously on + the event loop, blocking every other request. Must go through + ``asyncio.to_thread`` the same way ``routers/plan.py`` already does. +2. HIGH/MEDIUM — the handler read ``data["spec"]`` off a raw ``request.json()`` + with no request model, so a missing ``spec`` key or malformed spec content + raised an unhandled exception -> 500 instead of a 4xx. +""" + +from __future__ import annotations + +import inspect +from unittest.mock import patch + +import pytest +from fastapi.testclient import TestClient + + +@pytest.fixture +def client(): + from cloudwright_web.app import app + + return TestClient(app) + + +def _spec(n_components: int = 2) -> dict: + return { + "name": "Test", + "provider": "aws", + "region": "us-east-1", + "components": [ + { + "id": f"c{i}", + "service": "lambda", + "provider": "aws", + "label": f"L{i}", + "tier": 2, + "description": "", + "config": {}, + } + for i in range(n_components) + ], + } + + +class TestDiagramRendersOffTheEventLoop: + def test_diagram_router_uses_asyncio_to_thread(self): + from cloudwright_web.routers import diagram as diagram_router + + src = inspect.getsource(diagram_router) + assert "asyncio.to_thread" in src, ( + "diagram render must run via asyncio.to_thread, matching routers/plan.py, " + "so the D2 subprocess (up to 300s) doesn't block the event loop" + ) + + def test_render_svg_success(self, client): + with patch("cloudwright.exporter.renderer.DiagramRenderer.render_svg", return_value="ok"): + resp = client.post("/api/diagram", json={"spec": _spec(), "format": "svg"}) + assert resp.status_code == 200 + assert "svg" in resp.headers.get("content-type", "") + + def test_render_png_success(self, client): + with patch("cloudwright.exporter.renderer.DiagramRenderer.render_png", return_value=b"\x89PNG"): + resp = client.post("/api/diagram", json={"spec": _spec(), "format": "png"}) + assert resp.status_code == 200 + assert resp.headers.get("content-type") == "image/png" + + +class TestDiagramBadBodyIsNotA500: + def test_missing_spec_key_is_4xx_not_500(self, client): + resp = client.post("/api/diagram", json={}) + assert resp.status_code != 500 + assert 400 <= resp.status_code < 500 + + def test_non_dict_spec_is_4xx_not_500(self, client): + resp = client.post("/api/diagram", json={"spec": "not-a-dict"}) + assert resp.status_code != 500 + assert 400 <= resp.status_code < 500 + + def test_structurally_invalid_spec_is_4xx_not_500(self, client): + resp = client.post("/api/diagram", json={"spec": {"components": "not-a-list"}}) + assert resp.status_code != 500 + assert 400 <= resp.status_code < 500 + + def test_render_failure_is_a_structured_response_not_a_bare_crash(self, client): + """A renderer-side RuntimeError (e.g. D2 missing) is a real server-side + failure (legitimately 5xx), but it must be a structured JSON error + response from our own except-block, not an unhandled traceback.""" + with patch( + "cloudwright.exporter.renderer.DiagramRenderer.render_png", + side_effect=RuntimeError("D2 binary not installed"), + ): + resp = client.post("/api/diagram", json={"spec": _spec(), "format": "png"}) + assert resp.status_code == 500 + data = resp.json() + assert "message" in data + assert "suggestion" in data diff --git a/packages/web/tests/test_logging_configured_on_launch.py b/packages/web/tests/test_logging_configured_on_launch.py new file mode 100644 index 0000000..239eb54 --- /dev/null +++ b/packages/web/tests/test_logging_configured_on_launch.py @@ -0,0 +1,38 @@ +"""MEDIUM (observability): structured logging must activate on real launch paths. + +``configure_logging()`` was only called inside ``serve()``, so ``cloudwright +chat --web`` worked (it calls ``serve()``) but a bare +``uvicorn cloudwright_web.app:app`` (the Dockerfile's CMD) and the +``python -c "from cloudwright_web.app import serve; serve(...)"`` path that +skips ``serve()`` (e.g. any ASGI-server-managed deployment) never got +structured logs. + +Fix: call ``configure_logging()`` at app-creation time (``create_app()``), +which fires for every import of ``cloudwright_web.app``, not just the CLI's +``serve()`` path. ``configure_logging()`` is idempotent (module-level +``_configured`` guard in ``cloudwright.logging``), so calling it twice +(once at import, once again in ``serve()``) is a no-op the second time. +""" + +from __future__ import annotations + +import inspect + + +def test_create_app_calls_configure_logging(): + from cloudwright_web import app as app_module + + src = inspect.getsource(app_module.create_app) + assert "configure_logging" in src, ( + "create_app() must call configure_logging() so structured logs activate " + "on every launch path (bare uvicorn, cloudwright chat --web), not just serve()" + ) + + +def test_configure_logging_is_idempotent_across_create_app_and_serve(): + """Calling configure_logging() twice (create_app(), then serve()) must not + raise or double-register handlers.""" + from cloudwright.logging import configure_logging + + configure_logging() + configure_logging() # second call must be a no-op, not an error diff --git a/packages/web/tests/test_rate_limiter_eviction.py b/packages/web/tests/test_rate_limiter_eviction.py new file mode 100644 index 0000000..b379d35 --- /dev/null +++ b/packages/web/tests/test_rate_limiter_eviction.py @@ -0,0 +1,90 @@ +"""``_RateLimiter`` must evict empty IP buckets, not just pop expired entries. + +MEDIUM audit finding: the limiter only ever popped expired timestamps off a +per-IP deque; it never removed the (now-empty) deque from ``_buckets``. Under +IP churn (many one-off or rotating source IPs, e.g. behind a CDN or scanner +traffic) every distinct IP that is seen even once leaves a permanent dict +entry, since pruning for a given IP only happens when that same IP calls +``is_allowed`` again. The dict grows without bound over the life of the +process. + +Fix must not change the limiting semantics for any individual IP (same +window, same max_requests, same retry_after math) — only add eviction. +""" + +from __future__ import annotations + +import collections +import time + +from cloudwright_web.middleware import _RateLimiter + + +class TestBucketEviction: + def test_stale_bucket_is_evicted_from_the_dict(self): + limiter = _RateLimiter(max_requests=5, window_seconds=1) + limiter.is_allowed("1.1.1.1") + assert "1.1.1.1" in limiter._buckets + + # Backdate every entry in 1.1.1.1's bucket past the window so the + # next sweep prunes it to empty. + limiter._buckets["1.1.1.1"] = collections.deque([time.time() - 5]) + + # A completely different IP triggers the sweep; 1.1.1.1 never calls + # back, which is exactly the churn scenario the finding describes. + limiter.is_allowed("2.2.2.2") + + assert "1.1.1.1" not in limiter._buckets + + def test_many_one_off_ips_do_not_grow_the_dict_unbounded(self): + limiter = _RateLimiter(max_requests=5, window_seconds=1) + for i in range(50): + limiter.is_allowed(f"10.0.0.{i}") + # Immediately expire this IP's own entry so it looks like a + # one-off caller that never returns. + limiter._buckets[f"10.0.0.{i}"] = collections.deque([time.time() - 5]) + + # One more call should sweep and evict all the stale one-off buckets. + limiter.is_allowed("9.9.9.9") + + stale_remaining = [k for k in limiter._buckets if k.startswith("10.0.0.")] + assert stale_remaining == [] + + +class TestLimitSemanticsUnchanged: + """Pin the pre-existing behavior so the eviction fix can't drift it.""" + + def test_allows_under_limit(self): + limiter = _RateLimiter(max_requests=5, window_seconds=60) + for _ in range(5): + allowed, retry = limiter.is_allowed("1.2.3.4") + assert allowed is True + assert retry == 0 + + def test_blocks_over_limit(self): + limiter = _RateLimiter(max_requests=3, window_seconds=60) + for _ in range(3): + limiter.is_allowed("1.2.3.4") + + allowed, retry = limiter.is_allowed("1.2.3.4") + assert allowed is False + assert retry > 0 + + def test_different_ips_independent(self): + limiter = _RateLimiter(max_requests=1, window_seconds=60) + limiter.is_allowed("1.1.1.1") + allowed_a, _ = limiter.is_allowed("1.1.1.1") + allowed_b, _ = limiter.is_allowed("2.2.2.2") + assert allowed_a is False + assert allowed_b is True + + def test_resets_after_window(self): + limiter = _RateLimiter(max_requests=2, window_seconds=1) + limiter.is_allowed("1.2.3.4") + limiter.is_allowed("1.2.3.4") + blocked, _ = limiter.is_allowed("1.2.3.4") + assert blocked is False + + limiter._buckets["1.2.3.4"] = collections.deque([time.time() - 2, time.time() - 2]) + allowed, _ = limiter.is_allowed("1.2.3.4") + assert allowed is True diff --git a/packages/web/tests/test_spec_size_limits.py b/packages/web/tests/test_spec_size_limits.py new file mode 100644 index 0000000..89d6f2b --- /dev/null +++ b/packages/web/tests/test_spec_size_limits.py @@ -0,0 +1,106 @@ +"""No request-body / component-count caps on spec-accepting endpoints. + +MEDIUM audit finding: every endpoint that parses a ``spec: dict`` (diagram, +plan, export, download, modify, modify/stream, plus compliance, validate, +and cost) accepted it unbounded, so nothing stopped a single request from +carrying thousands of components (unbounded downstream cost/render/export/ +scan work) or a multi-megabyte body. + +Fix: a shared ``check_component_limit`` helper (mirrors the existing +``check_rate_limit`` return-on-error pattern) rejects specs over +``MAX_SPEC_COMPONENTS`` with 422, applied right after every +``ArchSpec.model_validate(...)`` call site across the routers, and a +body-size ASGI middleware rejects oversized request bodies with 413 before +they ever reach a route handler. +""" + +from __future__ import annotations + +import pytest +from fastapi.testclient import TestClient + + +@pytest.fixture +def client(): + from cloudwright_web.app import app + + return TestClient(app) + + +def _spec_with_components(n: int) -> dict: + return { + "name": "Big", + "provider": "aws", + "region": "us-east-1", + "components": [ + { + "id": f"c{i}", + "service": "lambda", + "provider": "aws", + "label": f"L{i}", + "tier": 2, + "description": "", + "config": {}, + } + for i in range(n) + ], + } + + +class TestComponentCountCap: + def test_diagram_rejects_over_component_limit(self, client): + resp = client.post("/api/diagram", json={"spec": _spec_with_components(201), "format": "svg"}) + assert resp.status_code == 422 + + def test_plan_rejects_over_component_limit(self, client): + resp = client.post( + "/api/plan", json={"spec": _spec_with_components(201), "target": "terraform", "run_plan": False} + ) + assert resp.status_code == 422 + + def test_export_rejects_over_component_limit(self, client): + resp = client.post("/api/export", json={"spec": _spec_with_components(201), "format": "terraform"}) + assert resp.status_code == 422 + + def test_download_rejects_over_component_limit(self, client): + resp = client.post("/api/download", json={"spec": _spec_with_components(201), "format": "terraform"}) + assert resp.status_code == 422 + + def test_modify_rejects_over_component_limit(self, client): + resp = client.post("/api/modify", json={"spec": _spec_with_components(201), "instruction": "add a queue"}) + assert resp.status_code == 422 + + def test_modify_stream_rejects_over_component_limit(self, client): + resp = client.post( + "/api/modify/stream", json={"spec": _spec_with_components(201), "instruction": "add a queue"} + ) + assert resp.status_code == 422 + + def test_compliance_rejects_over_component_limit(self, client): + resp = client.post("/api/compliance", json={"spec": _spec_with_components(201)}) + assert resp.status_code == 422 + + def test_validate_rejects_over_component_limit(self, client): + resp = client.post("/api/validate", json={"spec": _spec_with_components(201)}) + assert resp.status_code == 422 + + def test_cost_rejects_over_component_limit(self, client): + resp = client.post("/api/cost", json={"spec": _spec_with_components(201)}) + assert resp.status_code == 422 + + def test_under_limit_is_not_rejected_by_the_cap(self, client): + """Sanity check: a normal-size spec must not trip the new guard.""" + resp = client.post("/api/export", json={"spec": _spec_with_components(2), "format": "terraform"}) + assert resp.status_code != 422 + + +class TestBodySizeCap: + def test_oversized_body_rejected_with_413(self, client): + huge_spec = _spec_with_components(1) + huge_spec["components"][0]["config"] = {"padding": "x" * 2_000_000} + resp = client.post("/api/diagram", json={"spec": huge_spec, "format": "svg"}) + assert resp.status_code == 413 + + def test_normal_body_not_rejected_by_size_cap(self, client): + resp = client.post("/api/export", json={"spec": _spec_with_components(2), "format": "terraform"}) + assert resp.status_code != 413 From 80e891616f29891290756768dec6885931443607 Mon Sep 17 00:00:00 2001 From: Xavier Puspus <36430014+xmpuspus@users.noreply.github.com> Date: Wed, 8 Jul 2026 07:03:25 -0700 Subject: [PATCH 05/10] MCP tools: review, compliance/OSCAL, plan + session TTL (reach every MCP client) --- packages/mcp/README.md | 5 + packages/mcp/cloudwright_mcp/server.py | 18 +- .../mcp/cloudwright_mcp/tools/compliance.py | 114 +++++++++++++ packages/mcp/cloudwright_mcp/tools/plan.py | 97 +++++++++++ packages/mcp/cloudwright_mcp/tools/review.py | 75 +++++++++ packages/mcp/cloudwright_mcp/tools/session.py | 9 +- packages/mcp/cloudwright_mcp/ttl.py | 101 +++++++++++ packages/mcp/tests/conftest.py | 34 ++++ packages/mcp/tests/test_compliance_tool.py | 93 +++++++++++ packages/mcp/tests/test_plan_tool.py | 82 +++++++++ packages/mcp/tests/test_review_tool.py | 62 +++++++ packages/mcp/tests/test_session_ttl.py | 158 ++++++++++++++++++ 12 files changed, 845 insertions(+), 3 deletions(-) create mode 100644 packages/mcp/cloudwright_mcp/tools/compliance.py create mode 100644 packages/mcp/cloudwright_mcp/tools/plan.py create mode 100644 packages/mcp/cloudwright_mcp/tools/review.py create mode 100644 packages/mcp/cloudwright_mcp/ttl.py create mode 100644 packages/mcp/tests/conftest.py create mode 100644 packages/mcp/tests/test_compliance_tool.py create mode 100644 packages/mcp/tests/test_plan_tool.py create mode 100644 packages/mcp/tests/test_review_tool.py create mode 100644 packages/mcp/tests/test_session_ttl.py diff --git a/packages/mcp/README.md b/packages/mcp/README.md index df998ce..b53d254 100644 --- a/packages/mcp/README.md +++ b/packages/mcp/README.md @@ -40,12 +40,17 @@ Or add to your MCP client configuration: - **validate** — Check compliance against HIPAA, PCI-DSS, SOC 2, FedRAMP, GDPR - **export** — Export to Terraform, CloudFormation, Mermaid, D2, C4, SBOM - **compare** — Compare architectures across cloud providers +- **review_architecture**: free, offline scorer + linter + validator critique (no LLM) +- **scan_compliance_controls**: maps findings to framework control IDs; optional OSCAL 1.1.2 output +- **plan_infrastructure**: proves exported IaC is deployable (`terraform validate`/`plan`, read-only) - **chat_create_session** — Create a persistent multi-turn design session - **chat_send** — Send a message to an existing session - **chat_list_sessions** — List all saved sessions - **chat_delete_session** — Delete a session Sessions persist to `~/.cloudwright/sessions/` and survive process restarts. +Sessions older than `CLOUDWRIGHT_MCP_SESSION_TTL_DAYS` (default 7) are swept on +server start and on every `chat_list_sessions` call. ## License diff --git a/packages/mcp/cloudwright_mcp/server.py b/packages/mcp/cloudwright_mcp/server.py index df81abc..060aa37 100644 --- a/packages/mcp/cloudwright_mcp/server.py +++ b/packages/mcp/cloudwright_mcp/server.py @@ -2,9 +2,14 @@ from __future__ import annotations +import logging + from mcp.server.fastmcp import FastMCP -from cloudwright_mcp.tools import analyze, cost, design, export, session, validate +from cloudwright_mcp.tools import analyze, compliance, cost, design, export, plan, review, session, validate +from cloudwright_mcp.ttl import sweep_expired_sessions + +log = logging.getLogger(__name__) _GROUPS = { "design": design, @@ -13,6 +18,9 @@ "analyze": analyze, "export": export, "session": session, + "review": review, + "compliance": compliance, + "plan": plan, } @@ -21,10 +29,16 @@ def create_server(tools: set[str] | None = None) -> FastMCP: Args: tools: Set of group names to register. None = all groups. - Valid groups: design, cost, validate, analyze, export, session. + Valid groups: design, cost, validate, analyze, export, session, + review, compliance, plan. """ mcp = FastMCP("cloudwright", instructions="Architecture intelligence for cloud engineers") + try: + sweep_expired_sessions() + except Exception: + log.warning("Session TTL sweep failed at server start", exc_info=True) + for name, module in _GROUPS.items(): if tools is None or name in tools: module.register(mcp) diff --git a/packages/mcp/cloudwright_mcp/tools/compliance.py b/packages/mcp/cloudwright_mcp/tools/compliance.py new file mode 100644 index 0000000..35aa0ae --- /dev/null +++ b/packages/mcp/cloudwright_mcp/tools/compliance.py @@ -0,0 +1,114 @@ +from __future__ import annotations + +from typing import Annotated + +from mcp.server.fastmcp import FastMCP +from pydantic import Field + + +def register(mcp: FastMCP) -> None: + @mcp.tool() + def scan_compliance_controls( + spec_json: Annotated[ + dict, + Field( + description=( + "ArchSpec to scan. Runs the built-in component scanner plus a Terraform " + "HCL scan of the exported infrastructure, and folds in a Checkov deep " + "scan when the checkov binary is on PATH." + ), + ), + ], + frameworks: Annotated[ + list[str] | None, + Field( + description=( + "Compliance framework slugs to map findings against. Values: 'hipaa', " + "'soc2', 'pci-dss', 'fedramp', 'gdpr', 'iso27001', 'nist'. When omitted, " + "uses `spec.constraints.compliance` if set, otherwise maps against all " + "7 supported frameworks." + ), + examples=[["hipaa"], ["soc2", "fedramp"], None], + ), + ] = None, + checkov: Annotated[ + bool | None, + Field( + description=( + "Force (True) or skip (False) the optional Checkov deep scan against the " + "exported Terraform. None (default) auto-detects whether the checkov " + "binary is on PATH and runs it only if present." + ), + ), + ] = None, + oscal: Annotated[ + bool, + Field( + description=( + "When True, return an OSCAL 1.1.2 component-definition document (dict) " + "instead of the raw scan report, using the same builder `cloudwright " + "compliance --oscal` uses. `traceability` is ignored in this mode." + ), + ), + ] = False, + traceability: Annotated[ + bool, + Field( + description=( + "When True and `oscal` is False, include a `traceability` key: the " + "design-intent -> component -> IaC resource -> control -> status chain " + "for every finding." + ), + ), + ] = False, + ) -> dict: + """Scan an architecture and map every finding to compliance framework control IDs. + + Unlike `validate_compliance` (5-7 static pass/fail checks per framework), this + maps EVERY finding, from the built-in scanner, a Terraform HCL scan, and an + optional Checkov deep scan, to the specific control IDs it violates (e.g. HIPAA + 164.312(a)(2)(iv), SOC2 CC6.1, FedRAMP SC-28), before any infrastructure exists. + + Returns `{'passed': bool, 'scanner': str, 'checkov_used': bool, 'findings': [...], + 'frameworks': [...]}`. Each finding carries `severity`, `rule`, `component_id`, + `message`, `remediation`, `source` ('builtin' | 'terraform' | 'checkov'), and + `controls` (list of `{framework, control_id, title}`). Each framework summary + carries `controls_total`, `controls_violated`, `controls_satisfied`, `findings`, + and `status` ('pass' | 'fail'). + + Set `oscal=True` to instead receive a machine-readable OSCAL 1.1.2 + component-definition document mapping every architecture component to its + control-implementation status: the interoperability surface for FedRAMP 20x / + OSCAL-consuming tooling. Set `traceability=True` (non-OSCAL mode) for the + component -> resource -> control chain used in audit reports. + + When to use: Pre-deployment compliance posture with control-level detail, or + generating an OSCAL artifact for a FedRAMP/NIST-800-53 pipeline. For a quick + pass/fail per framework without control mapping, use `validate_compliance`. + + Behavior: Pure computation plus an optional local Checkov subprocess (never a + network call; auto-skipped when the checkov binary is absent). Never writes + files; the caller persists the returned content if needed. Invalid or empty + `spec_json` returns `{'error': str}` instead of raising. + """ + from cloudwright.compliance import ComplianceScanner, build_traceability + from cloudwright.spec import ArchSpec + + try: + spec = ArchSpec.model_validate(spec_json) + except Exception as exc: + return {"error": f"Invalid spec: {exc}"} + + scanner = ComplianceScanner() + report = scanner.scan(spec, frameworks=frameworks, run_checkov=checkov) + + if oscal: + from cloudwright.oscal import to_oscal + + resolved = scanner.resolve_frameworks(spec, frameworks) + return to_oscal(spec, report, resolved) + + payload = report.as_dict() + if traceability: + payload["traceability"] = build_traceability(spec, report) + return payload diff --git a/packages/mcp/cloudwright_mcp/tools/plan.py b/packages/mcp/cloudwright_mcp/tools/plan.py new file mode 100644 index 0000000..b4e9902 --- /dev/null +++ b/packages/mcp/cloudwright_mcp/tools/plan.py @@ -0,0 +1,97 @@ +from __future__ import annotations + +from typing import Annotated + +from mcp.server.fastmcp import FastMCP +from pydantic import Field + + +def register(mcp: FastMCP) -> None: + @mcp.tool() + def plan_infrastructure( + spec_json: Annotated[ + dict, + Field( + description=( + "ArchSpec to prove deployable. Exported to Terraform/Pulumi in a " + "throwaway temp directory that is deleted when the call returns, " + "never a persistent workspace." + ), + ), + ], + target: Annotated[ + str, + Field( + description=( + "IaC target. Values: 'terraform' (or 'tf'; prefers OpenTofu when it's " + "on PATH), 'pulumi-python', 'pulumi-ts'." + ), + examples=["terraform", "pulumi-python", "pulumi-ts"], + ), + ] = "terraform", + run_plan: Annotated[ + bool, + Field( + description=( + "When False (default), only exports and runs `terraform validate` (or " + "the Pulumi login/compile step): no cloud credentials needed, fast. " + "When True, additionally runs `terraform plan` / `pulumi preview` for a " + "real resource diff, which needs cloud credentials and can take longer. " + "Neither mode ever applies; there is no apply path in this tool." + ), + ), + ] = False, + timeout: Annotated[ + int, + Field( + description="Seconds before the validate/plan subprocess is aborted.", + examples=[60, 180], + ), + ] = 60, + ) -> dict: + """Prove an architecture's exported infrastructure is deployable. Read-only. + + Exports the spec to a throwaway temp directory and runs `terraform init + -backend=false` + `validate` (no cloud credentials required) as the offline + proof of deployability, or the Pulumi equivalent. This is the same read-only + planner behind `cloudwright plan`. + + Returns `{'tool': str, 'available': bool, 'validated': bool, 'plan_ran': bool, + 'ok': bool, 'summary': {'add','change','destroy'}|None, 'messages': [str], + 'output_tail': str}`. `available=False` means the terraform/tofu/pulumi binary + isn't installed: a structured skip, not an error. `ok` is the overall + deployability verdict; `plan_ran` is True only when a full plan/preview + executed (needs credentials). + + MCP-context boundary: the default here is validate-only (`run_plan=False`) to + keep the call fast and credential-free, unlike the CLI which defaults to + attempting a full plan. Pass `run_plan=True` for a real resource diff when + credentials are available in the server's environment. Under no argument + combination does this tool run `terraform apply` / `pulumi up`; the + underlying planner has no apply code path at all. + + When to use: After `export_architecture` (format='terraform'), to confirm the + generated IaC is syntactically and semantically valid before handing it to a + deploy pipeline. Complementary to `security_scan` / `scan_compliance_controls`, + which check the *design*, not whether the emitted HCL/Pulumi program compiles. + + Behavior: Runs a local subprocess (terraform/tofu/pulumi) against a temp + directory deleted when the call returns. No cloud resources are read, created, + or modified. Degrades to a structured `{'available': False, ...}` result when + the binary is missing, and to `{'error': str}` for an invalid spec or unknown + `target`. Neither case raises. + """ + from cloudwright.planner import plan as run_plan_fn + from cloudwright.spec import ArchSpec + + try: + spec = ArchSpec.model_validate(spec_json) + except Exception as exc: + return {"error": f"Invalid spec: {exc}"} + + try: + result = run_plan_fn(spec, target=target, run_plan=run_plan, timeout=timeout) + except ValueError as exc: + return {"error": str(exc)} + + return result.as_dict() diff --git a/packages/mcp/cloudwright_mcp/tools/review.py b/packages/mcp/cloudwright_mcp/tools/review.py new file mode 100644 index 0000000..9aaf12b --- /dev/null +++ b/packages/mcp/cloudwright_mcp/tools/review.py @@ -0,0 +1,75 @@ +from __future__ import annotations + +from typing import Annotated + +from mcp.server.fastmcp import FastMCP +from pydantic import Field + + +def register(mcp: FastMCP) -> None: + @mcp.tool() + def review_architecture( + spec_json: Annotated[ + dict, + Field( + description=( + "ArchSpec to review. The critic runs the scorer, linter, and validator " + "against the declared components, connections, and constraints. No " + "cloud API access required." + ), + ), + ], + compliance: Annotated[ + list[str] | None, + Field( + description=( + "Optional compliance frameworks to fold validator findings from. When " + "omitted, uses `spec.constraints.compliance` if set, otherwise runs no " + "framework checks. Values: 'hipaa', 'pci-dss', 'soc2', 'fedramp', 'gdpr'." + ), + examples=[["hipaa"], ["soc2", "gdpr"], None], + ), + ] = None, + well_architected: Annotated[ + bool, + Field( + description=( + "When True, additionally runs the AWS Well-Architected Framework pillar " + "checks (multi-AZ, auto-scaling, backup, monitoring, SPOF, cost)." + ), + ), + ] = False, + ) -> dict: + """Run the deterministic offline critic (scorer + linter + validator) on an architecture. + + This is the same generate -> critique -> repair engine `Architect.design()` uses + internally to self-correct a spec before returning it, exposed standalone so an + agent can review any spec (hand-authored, imported, or previously designed) for + free, with no LLM call. + + Returns `{'score': float, 'grade': str, 'findings': [...], 'blocking_count': int, + 'summary': str}`. Findings are severity-ranked (critical/high first) and each + carries `source` ('scorer' | 'linter' | 'validator'), `code`, `message`, + `recommendation`, and an optional `component` id. `blocking_count` counts + critical + high findings; a non-zero count means the architecture should not + ship as-is. + + When to use: A quick, free, structured review of any spec, before deploying, + after a `modify_architecture` edit, or auditing an imported/hand-written spec. + For a numeric-only quality score use `score_architecture`; for anti-pattern + detail alone use `lint_architecture` or `security_scan`. This tool merges all + three plus compliance checks into one severity-ranked report. + + Behavior: Pure computation, no LLM, no network, no API key required. Read-only. + Invalid or empty `spec_json` returns `{'error': str}` instead of raising. + """ + from cloudwright.critique import critique + from cloudwright.spec import ArchSpec + + try: + spec = ArchSpec.model_validate(spec_json) + except Exception as exc: + return {"error": f"Invalid spec: {exc}"} + + report = critique(spec, compliance=compliance, well_architected=well_architected) + return report.as_dict() diff --git a/packages/mcp/cloudwright_mcp/tools/session.py b/packages/mcp/cloudwright_mcp/tools/session.py index b44a759..148421d 100644 --- a/packages/mcp/cloudwright_mcp/tools/session.py +++ b/packages/mcp/cloudwright_mcp/tools/session.py @@ -7,6 +7,8 @@ from mcp.server.fastmcp import FastMCP from pydantic import Field +from cloudwright_mcp.ttl import sweep_expired_sessions + _lock = threading.Lock() @@ -146,10 +148,15 @@ def chat_list_sessions() -> list[dict]: When to use: Resuming prior work, cleaning up abandoned sessions, or auditing session token spend. - Behavior: Pure disk read — no LLM, no network. Read-only. + Behavior: Pure disk read, no LLM, no network. Read-only, except for an + age-based expiry sweep run first: sessions whose last save is older than + `CLOUDWRIGHT_MCP_SESSION_TTL_DAYS` (default 7 days) are deleted before the + remaining sessions are listed. Set the TTL to 0 or below to disable the sweep. """ from cloudwright.session_store import SessionStore + with _lock: + sweep_expired_sessions() return SessionStore().list_sessions() @mcp.tool() diff --git a/packages/mcp/cloudwright_mcp/ttl.py b/packages/mcp/cloudwright_mcp/ttl.py new file mode 100644 index 0000000..3a16ae5 --- /dev/null +++ b/packages/mcp/cloudwright_mcp/ttl.py @@ -0,0 +1,101 @@ +"""Age-based sweep for MCP session files. + +`SessionStore` (`cloudwright.session_store`) persists every `chat_create_session` +call to `~/.cloudwright/sessions/*.json` with no expiry. A long-running MCP +server accumulates one file per session forever. This module adds an age-based +sweep on top of SessionStore's existing public API (`list_sessions` / `delete`) +without touching core: it never opens session files directly, so SessionStore's +atomic-write semantics (write-temp, fsync, `os.replace`) are unaffected. + +Concurrency note: there is no cross-process lock between a sweep and a +concurrent `chat_send` that is about to re-save the same session. If a sweep +and a save race on the same session id, whichever filesystem operation lands +last wins: a session mid-save when a sweep runs may survive one extra sweep +cycle before the next one catches it, or a session deleted by a sweep just +before a save completes gets recreated by that save. Either outcome is safe +(atomic writes, whole-file delete). This is last-writer-wins housekeeping, +not a distributed lock. +""" + +from __future__ import annotations + +import logging +import os +import time + +log = logging.getLogger(__name__) + +DEFAULT_TTL_DAYS = 7 +TTL_ENV_VAR = "CLOUDWRIGHT_MCP_SESSION_TTL_DAYS" + + +def session_ttl_seconds() -> float: + """Resolve the configured session TTL, in seconds. + + Reads `CLOUDWRIGHT_MCP_SESSION_TTL_DAYS` (a float number of days). Unset + or non-numeric falls back to `DEFAULT_TTL_DAYS`. A value <= 0 disables + the sweep entirely (no expiry) so operators can opt out. + """ + raw = os.environ.get(TTL_ENV_VAR, "").strip() + if not raw: + return DEFAULT_TTL_DAYS * 86400 + try: + days = float(raw) + except ValueError: + log.warning("Invalid %s=%r; using default %d days", TTL_ENV_VAR, raw, DEFAULT_TTL_DAYS) + return DEFAULT_TTL_DAYS * 86400 + return days * 86400 + + +def sweep_expired_sessions( + store=None, + *, + ttl_seconds: float | None = None, + now: float | None = None, +) -> list[str]: + """Delete session files older than the TTL. Returns the deleted session IDs. + + A session's age is `now - saved_at`, falling back to `created_at` for + sessions written before the `saved_at` field existed. Called from + `chat_list_sessions` and once at server start (`create_server`); safe to + call repeatedly. It is a no-op once expired sessions are already gone. + + Args: + store: SessionStore instance to sweep. Defaults to + `SessionStore()` (the real `~/.cloudwright/sessions/` dir). + Tests should always pass an explicit store pointed at a + temp directory. + ttl_seconds: Override for the resolved TTL. Defaults to + `session_ttl_seconds()`. + now: Override for the current time (epoch seconds). Defaults to + `time.time()`. + """ + from cloudwright.session_store import SessionStore + + store = store or SessionStore() + ttl = session_ttl_seconds() if ttl_seconds is None else ttl_seconds + if ttl <= 0: + return [] + + current = time.time() if now is None else now + deleted: list[str] = [] + for meta in store.list_sessions(): + stamp = meta.get("saved_at") + if stamp is None: + stamp = meta.get("created_at") + if stamp is None: + continue + try: + age = current - float(stamp) + except (TypeError, ValueError): + continue + if age <= ttl: + continue + session_id = meta["session_id"] + try: + if store.delete(session_id): + deleted.append(session_id) + except ValueError: + # session_id failed SessionStore's safe-id check. Skip, don't raise. + log.warning("Skipping sweep of unsafe session_id %r", session_id) + return deleted diff --git a/packages/mcp/tests/conftest.py b/packages/mcp/tests/conftest.py new file mode 100644 index 0000000..b460ef1 --- /dev/null +++ b/packages/mcp/tests/conftest.py @@ -0,0 +1,34 @@ +from __future__ import annotations + +from unittest.mock import MagicMock + +import pytest + + +@pytest.fixture +def register_tools(): + """Register a tools module's functions against a fake FastMCP. + + Mirrors the `mcp.tool()` decorator contract (a zero-arg call returning a + decorator) without a real FastMCP server or transport, so tool functions + can be invoked directly in tests. Same pattern as the inline + `_register_tools` helper in test_session_lifecycle.py, shared here for + the newer tool modules. + """ + + def _register(module) -> dict: + mcp = MagicMock() + captured_fn: dict = {} + + def tool_decorator(): + def decorator(fn): + captured_fn[fn.__name__] = fn + return fn + + return decorator + + mcp.tool = tool_decorator + module.register(mcp) + return captured_fn + + return _register diff --git a/packages/mcp/tests/test_compliance_tool.py b/packages/mcp/tests/test_compliance_tool.py new file mode 100644 index 0000000..62ab77e --- /dev/null +++ b/packages/mcp/tests/test_compliance_tool.py @@ -0,0 +1,93 @@ +from __future__ import annotations + +from cloudwright.spec import ArchSpec, Component, Constraints + + +def _hipaa_spec_dict() -> dict: + # Unencrypted RDS trips missing_encryption, which the control catalog maps + # to HIPAA 164.312(a)(2)(iv) and FedRAMP SC-28 deterministically. + spec = ArchSpec( + name="ComplianceTest", + provider="aws", + region="us-east-1", + constraints=Constraints(compliance=["hipaa"]), + components=[ + Component( + id="db", + service="rds", + provider="aws", + label="DB", + tier=3, + config={"backup": True, "multi_az": True}, + ), + ], + ) + return spec.model_dump(exclude_none=True) + + +class TestScanComplianceControls: + def test_valid_spec_maps_findings_to_controls(self, register_tools): + import cloudwright_mcp.tools.compliance as mod + + fns = register_tools(mod) + result = fns["scan_compliance_controls"](spec_json=_hipaa_spec_dict(), frameworks=["hipaa"], checkov=False) + + assert {"passed", "scanner", "checkov_used", "findings", "frameworks"} <= set(result) + assert result["findings"], "unencrypted RDS should trip a HIPAA-mapped finding" + assert any(c["framework"] == "HIPAA" for f in result["findings"] for c in f["controls"]) + + def test_oscal_returns_component_definition_not_raw_report(self, register_tools): + import cloudwright_mcp.tools.compliance as mod + + fns = register_tools(mod) + result = fns["scan_compliance_controls"]( + spec_json=_hipaa_spec_dict(), frameworks=["hipaa"], checkov=False, oscal=True + ) + + assert "component-definition" in result + assert result["component-definition"]["metadata"]["oscal-version"] == "1.1.2" + assert "findings" not in result + + def test_traceability_included_when_requested(self, register_tools): + import cloudwright_mcp.tools.compliance as mod + + fns = register_tools(mod) + result = fns["scan_compliance_controls"]( + spec_json=_hipaa_spec_dict(), frameworks=["hipaa"], checkov=False, traceability=True + ) + + assert "traceability" in result + + def test_traceability_absent_by_default(self, register_tools): + import cloudwright_mcp.tools.compliance as mod + + fns = register_tools(mod) + result = fns["scan_compliance_controls"](spec_json=_hipaa_spec_dict(), frameworks=["hipaa"], checkov=False) + + assert "traceability" not in result + + def test_invalid_spec_returns_error_dict_not_exception(self, register_tools): + import cloudwright_mcp.tools.compliance as mod + + fns = register_tools(mod) + result = fns["scan_compliance_controls"](spec_json={"components": [{"id": "1bad"}]}, frameworks=["hipaa"]) + + assert "error" in result + + def test_empty_spec_returns_error_dict_not_exception(self, register_tools): + import cloudwright_mcp.tools.compliance as mod + + fns = register_tools(mod) + result = fns["scan_compliance_controls"](spec_json={}, frameworks=None) + + assert "error" in result + + def test_works_with_no_api_key_set(self, monkeypatch, register_tools): + monkeypatch.delenv("ANTHROPIC_API_KEY", raising=False) + monkeypatch.delenv("OPENAI_API_KEY", raising=False) + import cloudwright_mcp.tools.compliance as mod + + fns = register_tools(mod) + result = fns["scan_compliance_controls"](spec_json=_hipaa_spec_dict(), checkov=False) + + assert "error" not in result diff --git a/packages/mcp/tests/test_plan_tool.py b/packages/mcp/tests/test_plan_tool.py new file mode 100644 index 0000000..32b0a5c --- /dev/null +++ b/packages/mcp/tests/test_plan_tool.py @@ -0,0 +1,82 @@ +from __future__ import annotations + +from unittest import mock + +from cloudwright.spec import ArchSpec, Component + + +def _spec_dict() -> dict: + spec = ArchSpec( + name="PlanMcpTest", + provider="aws", + region="us-east-1", + components=[ + Component( + id="db", + service="rds", + provider="aws", + label="DB", + tier=3, + config={"encryption": True, "backup": True, "multi_az": True}, + ), + ], + ) + return spec.model_dump(exclude_none=True) + + +class TestPlanInfrastructure: + def test_missing_binary_returns_structured_not_available(self, register_tools): + import cloudwright_mcp.tools.plan as mod + + fns = register_tools(mod) + with mock.patch("cloudwright.planner.shutil.which", return_value=None): + result = fns["plan_infrastructure"](spec_json=_spec_dict()) + + assert result["available"] is False + assert result["ok"] is False + assert "error" not in result # structured skip, not an exception + + def test_default_is_validate_only_never_plan(self, register_tools): + """MCP boundary: run_plan defaults to False, unlike the CLI.""" + import cloudwright_mcp.tools.plan as mod + + fns = register_tools(mod) + with mock.patch("cloudwright.planner.shutil.which", return_value=None): + result = fns["plan_infrastructure"](spec_json=_spec_dict()) + + assert result["plan_ran"] is False + + def test_invalid_spec_returns_error_dict_not_exception(self, register_tools): + import cloudwright_mcp.tools.plan as mod + + fns = register_tools(mod) + result = fns["plan_infrastructure"](spec_json={"components": [{"id": "1bad"}]}) + + assert "error" in result + + def test_empty_spec_returns_error_dict_not_exception(self, register_tools): + import cloudwright_mcp.tools.plan as mod + + fns = register_tools(mod) + result = fns["plan_infrastructure"](spec_json={}) + + assert "error" in result + + def test_unknown_target_returns_error_dict_not_exception(self, register_tools): + import cloudwright_mcp.tools.plan as mod + + fns = register_tools(mod) + result = fns["plan_infrastructure"](spec_json=_spec_dict(), target="bogus-target") + + assert "error" in result + + def test_works_with_no_api_key_set(self, monkeypatch, register_tools): + monkeypatch.delenv("ANTHROPIC_API_KEY", raising=False) + monkeypatch.delenv("OPENAI_API_KEY", raising=False) + import cloudwright_mcp.tools.plan as mod + + fns = register_tools(mod) + with mock.patch("cloudwright.planner.shutil.which", return_value=None): + result = fns["plan_infrastructure"](spec_json=_spec_dict()) + + assert "error" not in result diff --git a/packages/mcp/tests/test_review_tool.py b/packages/mcp/tests/test_review_tool.py new file mode 100644 index 0000000..ea81bde --- /dev/null +++ b/packages/mcp/tests/test_review_tool.py @@ -0,0 +1,62 @@ +from __future__ import annotations + +from cloudwright.spec import ArchSpec, Component + + +def _flawed_spec_dict() -> dict: + # Bare compute + DB, no monitoring/backup/LB scaffolding: trips linter rules + # deterministically so the review always returns findings. + spec = ArchSpec( + name="flawed", + components=[ + Component(id="web", service="ec2", provider="aws", label="Web", tier=2), + Component(id="db", service="rds", provider="aws", label="DB", tier=3), + ], + ) + return spec.model_dump(exclude_none=True) + + +class TestReviewArchitecture: + def test_valid_spec_returns_expected_shape(self, register_tools): + import cloudwright_mcp.tools.review as mod + + fns = register_tools(mod) + result = fns["review_architecture"](spec_json=_flawed_spec_dict()) + + assert {"score", "grade", "findings", "blocking_count", "summary"} <= set(result) + assert result["findings"], "a bare 2-component spec should surface findings" + + def test_compliance_frameworks_fold_in_validator_findings(self, register_tools): + import cloudwright_mcp.tools.review as mod + + fns = register_tools(mod) + result = fns["review_architecture"](spec_json=_flawed_spec_dict(), compliance=["hipaa"]) + + assert any(f["source"] == "validator" for f in result["findings"]) + + def test_invalid_spec_returns_error_dict_not_exception(self, register_tools): + import cloudwright_mcp.tools.review as mod + + fns = register_tools(mod) + result = fns["review_architecture"](spec_json={"components": [{"id": "1bad"}]}) + + assert "error" in result + + def test_empty_spec_returns_error_dict_not_exception(self, register_tools): + import cloudwright_mcp.tools.review as mod + + fns = register_tools(mod) + result = fns["review_architecture"](spec_json={}) + + assert "error" in result + + def test_works_with_no_api_key_set(self, monkeypatch, register_tools): + monkeypatch.delenv("ANTHROPIC_API_KEY", raising=False) + monkeypatch.delenv("OPENAI_API_KEY", raising=False) + import cloudwright_mcp.tools.review as mod + + fns = register_tools(mod) + result = fns["review_architecture"](spec_json=_flawed_spec_dict()) + + assert "error" not in result + assert "score" in result diff --git a/packages/mcp/tests/test_session_ttl.py b/packages/mcp/tests/test_session_ttl.py new file mode 100644 index 0000000..3892adc --- /dev/null +++ b/packages/mcp/tests/test_session_ttl.py @@ -0,0 +1,158 @@ +from __future__ import annotations + +import json +import tempfile +import time +from pathlib import Path +from unittest.mock import MagicMock + +from cloudwright.session_store import SessionStore +from cloudwright_mcp.ttl import DEFAULT_TTL_DAYS, session_ttl_seconds, sweep_expired_sessions + + +def _make_mock_cs(): + session = MagicMock() + session.current_spec = None + session.last_usage = {"input_tokens": 10, "output_tokens": 5} + session.history = [] + session.send.return_value = ("ok", None) + session.get_usage_summary.return_value = {"total_input": 10, "total_output": 5} + session.to_dict.return_value = { + "session_id": "test", + "history": [], + "current_spec": None, + "constraints": None, + "cumulative_usage": {"input_tokens": 0, "output_tokens": 0, "total_cost": 0.0}, + "_error_hints": [], + "max_history_turns": 50, + "created_at": 0, + } + return session + + +def _backdate(tmpdir: str, session_id: str, saved_at: float) -> None: + path = Path(tmpdir) / f"{session_id}.json" + data = json.loads(path.read_text()) + data["saved_at"] = saved_at + path.write_text(json.dumps(data)) + + +class TestSweepExpiredSessions: + def test_old_session_is_swept(self): + with tempfile.TemporaryDirectory() as tmpdir: + store = SessionStore(base_dir=Path(tmpdir)) + store.save("old", _make_mock_cs()) + _backdate(tmpdir, "old", time.time() - (DEFAULT_TTL_DAYS + 1) * 86400) + + deleted = sweep_expired_sessions(store=store) + + assert deleted == ["old"] + assert not (Path(tmpdir) / "old.json").exists() + + def test_fresh_session_is_kept(self): + with tempfile.TemporaryDirectory() as tmpdir: + store = SessionStore(base_dir=Path(tmpdir)) + store.save("fresh", _make_mock_cs()) + + deleted = sweep_expired_sessions(store=store) + + assert deleted == [] + assert any(s["session_id"] == "fresh" for s in store.list_sessions()) + + def test_old_and_fresh_sessions_together(self): + with tempfile.TemporaryDirectory() as tmpdir: + store = SessionStore(base_dir=Path(tmpdir)) + store.save("old", _make_mock_cs()) + store.save("fresh", _make_mock_cs()) + _backdate(tmpdir, "old", time.time() - (DEFAULT_TTL_DAYS + 1) * 86400) + + deleted = sweep_expired_sessions(store=store) + remaining = {s["session_id"] for s in store.list_sessions()} + + assert deleted == ["old"] + assert remaining == {"fresh"} + + def test_ttl_zero_disables_sweep(self): + with tempfile.TemporaryDirectory() as tmpdir: + store = SessionStore(base_dir=Path(tmpdir)) + store.save("old", _make_mock_cs()) + _backdate(tmpdir, "old", 0) + + deleted = sweep_expired_sessions(store=store, ttl_seconds=0) + + assert deleted == [] + assert (Path(tmpdir) / "old.json").exists() + + def test_custom_ttl_seconds_boundary(self): + with tempfile.TemporaryDirectory() as tmpdir: + store = SessionStore(base_dir=Path(tmpdir)) + store.save("borderline", _make_mock_cs()) + _backdate(tmpdir, "borderline", time.time() - 120) + + deleted = sweep_expired_sessions(store=store, ttl_seconds=60) + + assert deleted == ["borderline"] + + def test_missing_timestamp_is_skipped_not_raised(self): + with tempfile.TemporaryDirectory() as tmpdir: + store = SessionStore(base_dir=Path(tmpdir)) + store.save("no_stamp", _make_mock_cs()) + path = Path(tmpdir) / "no_stamp.json" + data = json.loads(path.read_text()) + data.pop("saved_at", None) + data.pop("created_at", None) + path.write_text(json.dumps(data)) + + deleted = sweep_expired_sessions(store=store) + + assert deleted == [] + assert path.exists() + + +class TestSessionTtlSecondsResolution: + def test_env_var_overrides_default(self, monkeypatch): + monkeypatch.setenv("CLOUDWRIGHT_MCP_SESSION_TTL_DAYS", "1") + assert session_ttl_seconds() == 86400 + + def test_unset_env_var_uses_default(self, monkeypatch): + monkeypatch.delenv("CLOUDWRIGHT_MCP_SESSION_TTL_DAYS", raising=False) + assert session_ttl_seconds() == DEFAULT_TTL_DAYS * 86400 + + def test_invalid_env_var_falls_back_to_default(self, monkeypatch): + monkeypatch.setenv("CLOUDWRIGHT_MCP_SESSION_TTL_DAYS", "not-a-number") + assert session_ttl_seconds() == DEFAULT_TTL_DAYS * 86400 + + +class TestChatListSessionsTriggersSweep: + def test_chat_list_sessions_invokes_sweep(self, monkeypatch, register_tools): + import cloudwright_mcp.tools.session as mod + + called = {} + + def fake_sweep(*args, **kwargs): + called["ran"] = True + return [] + + monkeypatch.setattr(mod, "sweep_expired_sessions", fake_sweep) + fns = register_tools(mod) + + fns["chat_list_sessions"]() + + assert called.get("ran") is True + + +class TestCreateServerTriggersSweepAtStartup: + def test_create_server_invokes_sweep_once(self, monkeypatch): + import cloudwright_mcp.server as server_mod + + called = {"count": 0} + + def fake_sweep(*args, **kwargs): + called["count"] += 1 + return [] + + monkeypatch.setattr(server_mod, "sweep_expired_sessions", fake_sweep) + + server_mod.create_server(tools=set()) + + assert called["count"] == 1 From 469a0cdbe7b40fed61bcf1dd6c98adbd164069ab Mon Sep 17 00:00:00 2001 From: Xavier Puspus <36430014+xmpuspus@users.noreply.github.com> Date: Wed, 8 Jul 2026 07:06:26 -0700 Subject: [PATCH 06/10] Web review surface: /api/review + /api/compliance OSCAL, Review tab + OSCAL download, rebuilt bundle --- packages/web/cloudwright_web/app.py | 2 + .../web/cloudwright_web/routers/__init__.py | 2 + .../web/cloudwright_web/routers/compliance.py | 35 +++- .../web/cloudwright_web/routers/review.py | 45 +++++ .../static/assets/index-B1XNG5bU.js | 71 +++++++ .../static/assets/index-DU-cIjQd.js | 71 ------- .../web/cloudwright_web/static/index.html | 2 +- packages/web/frontend/src/App.tsx | 12 +- .../src/components/CompliancePanel.tsx | 83 ++++++-- .../frontend/src/components/ReviewPanel.tsx | 189 ++++++++++++++++++ packages/web/tests/test_review_and_oscal.py | 146 ++++++++++++++ 11 files changed, 562 insertions(+), 96 deletions(-) create mode 100644 packages/web/cloudwright_web/routers/review.py create mode 100644 packages/web/cloudwright_web/static/assets/index-B1XNG5bU.js delete mode 100644 packages/web/cloudwright_web/static/assets/index-DU-cIjQd.js create mode 100644 packages/web/frontend/src/components/ReviewPanel.tsx create mode 100644 packages/web/tests/test_review_and_oscal.py diff --git a/packages/web/cloudwright_web/app.py b/packages/web/cloudwright_web/app.py index cdf0301..ee0f2b0 100644 --- a/packages/web/cloudwright_web/app.py +++ b/packages/web/cloudwright_web/app.py @@ -32,6 +32,7 @@ health_router, modules_router, plan_router, + review_router, validate_router, ) from cloudwright_web.singletons import get_architect, get_catalog, get_cost_engine # noqa: F401 @@ -119,6 +120,7 @@ def create_app() -> FastAPI: application.include_router(validate_router, prefix="/api") application.include_router(compliance_router, prefix="/api") application.include_router(plan_router, prefix="/api") + application.include_router(review_router, prefix="/api") application.include_router(export_router, prefix="/api") application.include_router(catalog_router, prefix="/api") application.include_router(modules_router, prefix="/api") diff --git a/packages/web/cloudwright_web/routers/__init__.py b/packages/web/cloudwright_web/routers/__init__.py index c9031ff..b5598f1 100644 --- a/packages/web/cloudwright_web/routers/__init__.py +++ b/packages/web/cloudwright_web/routers/__init__.py @@ -10,6 +10,7 @@ from cloudwright_web.routers.health import router as health_router from cloudwright_web.routers.modules import router as modules_router from cloudwright_web.routers.plan import router as plan_router +from cloudwright_web.routers.review import router as review_router from cloudwright_web.routers.validate import router as validate_router __all__ = [ @@ -23,5 +24,6 @@ "health_router", "modules_router", "plan_router", + "review_router", "validate_router", ] diff --git a/packages/web/cloudwright_web/routers/compliance.py b/packages/web/cloudwright_web/routers/compliance.py index 924cb7a..63aca4d 100644 --- a/packages/web/cloudwright_web/routers/compliance.py +++ b/packages/web/cloudwright_web/routers/compliance.py @@ -1,9 +1,10 @@ -"""POST /api/compliance — control-ID-mapped compliance scan.""" +"""POST /api/compliance — control-ID-mapped compliance scan, with optional OSCAL export.""" from __future__ import annotations import asyncio import logging +from typing import Any from cloudwright import ArchSpec from cloudwright.compliance import ComplianceScanner @@ -20,6 +21,27 @@ class ComplianceRequest(BaseModel): spec: dict frameworks: list[str] = Field(default_factory=list) checkov: bool | None = None + oscal: bool = False + + +def _scan_and_maybe_oscal(spec: ArchSpec, frameworks: list[str], checkov: bool | None, want_oscal: bool) -> dict: + """Run the compliance scan and, when requested, attach the OSCAL document. + + Mirrors ``cloudwright compliance --oscal`` line for line: ``scan()`` gets + the raw requested frameworks (it resolves them itself), and a second, + independent ``resolve_frameworks`` call feeds ``to_oscal`` — the exact + builder the CLI uses — so the web surface can never drift from the CLI's + OSCAL output. + """ + scanner = ComplianceScanner() + report = scanner.scan(spec, frameworks or None, checkov) + payload = report.as_dict() + if want_oscal: + from cloudwright.oscal import to_oscal + + resolved = scanner.resolve_frameworks(spec, frameworks or None) + payload["oscal"] = to_oscal(spec, report, resolved) + return payload @router.post("/compliance") @@ -31,13 +53,12 @@ async def compliance(req: ComplianceRequest, request: Request): spec = ArchSpec.model_validate(req.spec) if err := check_component_limit(spec): return err - report = await asyncio.to_thread( - ComplianceScanner().scan, - spec, - req.frameworks or None, - req.checkov, + payload: dict[str, Any] = await asyncio.to_thread( + _scan_and_maybe_oscal, spec, req.frameworks, req.checkov, req.oscal ) - return report.as_dict() + return payload + except ValueError as e: + raise HTTPException(status_code=400, detail=str(e)) from e except Exception as e: log.exception("Compliance endpoint failed") raise HTTPException(status_code=500, detail="Internal server error") from e diff --git a/packages/web/cloudwright_web/routers/review.py b/packages/web/cloudwright_web/routers/review.py new file mode 100644 index 0000000..f55c105 --- /dev/null +++ b/packages/web/cloudwright_web/routers/review.py @@ -0,0 +1,45 @@ +"""POST /api/review — deterministic architecture critique (offline, no LLM).""" + +from __future__ import annotations + +import asyncio +import logging + +from cloudwright import ArchSpec +from cloudwright.critique import critique +from fastapi import APIRouter, HTTPException, Request +from pydantic import BaseModel, Field + +from cloudwright_web.middleware import check_api_key, check_component_limit, check_rate_limit + +log = logging.getLogger(__name__) +router = APIRouter() + + +class ReviewRequest(BaseModel): + spec: dict + compliance: list[str] = Field(default_factory=list) + well_architected: bool = False + + +@router.post("/review") +async def review(req: ReviewRequest, request: Request): + check_api_key(request) + if err := check_rate_limit(request): + return err + try: + spec = ArchSpec.model_validate(req.spec) + if err := check_component_limit(spec): + return err + report = await asyncio.to_thread( + critique, + spec, + compliance=req.compliance or None, + well_architected=req.well_architected, + ) + return report.as_dict() + except ValueError as e: + raise HTTPException(status_code=400, detail=str(e)) from e + except Exception as e: + log.exception("Review endpoint failed") + raise HTTPException(status_code=500, detail="Internal server error") from e diff --git a/packages/web/cloudwright_web/static/assets/index-B1XNG5bU.js b/packages/web/cloudwright_web/static/assets/index-B1XNG5bU.js new file mode 100644 index 0000000..61038d0 --- /dev/null +++ b/packages/web/cloudwright_web/static/assets/index-B1XNG5bU.js @@ -0,0 +1,71 @@ +(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const o of document.querySelectorAll('link[rel="modulepreload"]'))r(o);new MutationObserver(o=>{for(const i of o)if(i.type==="childList")for(const s of i.addedNodes)s.tagName==="LINK"&&s.rel==="modulepreload"&&r(s)}).observe(document,{childList:!0,subtree:!0});function n(o){const i={};return o.integrity&&(i.integrity=o.integrity),o.referrerPolicy&&(i.referrerPolicy=o.referrerPolicy),o.crossOrigin==="use-credentials"?i.credentials="include":o.crossOrigin==="anonymous"?i.credentials="omit":i.credentials="same-origin",i}function r(o){if(o.ep)return;o.ep=!0;const i=n(o);fetch(o.href,i)}})();function rp(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var op={exports:{}},Ns={},ip={exports:{}},te={};/** + * @license React + * react.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var Oo=Symbol.for("react.element"),py=Symbol.for("react.portal"),hy=Symbol.for("react.fragment"),gy=Symbol.for("react.strict_mode"),my=Symbol.for("react.profiler"),yy=Symbol.for("react.provider"),xy=Symbol.for("react.context"),vy=Symbol.for("react.forward_ref"),wy=Symbol.for("react.suspense"),Sy=Symbol.for("react.memo"),ky=Symbol.for("react.lazy"),zc=Symbol.iterator;function _y(e){return e===null||typeof e!="object"?null:(e=zc&&e[zc]||e["@@iterator"],typeof e=="function"?e:null)}var sp={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},lp=Object.assign,ap={};function Er(e,t,n){this.props=e,this.context=t,this.refs=ap,this.updater=n||sp}Er.prototype.isReactComponent={};Er.prototype.setState=function(e,t){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")};Er.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function up(){}up.prototype=Er.prototype;function au(e,t,n){this.props=e,this.context=t,this.refs=ap,this.updater=n||sp}var uu=au.prototype=new up;uu.constructor=au;lp(uu,Er.prototype);uu.isPureReactComponent=!0;var Tc=Array.isArray,cp=Object.prototype.hasOwnProperty,cu={current:null},dp={key:!0,ref:!0,__self:!0,__source:!0};function fp(e,t,n){var r,o={},i=null,s=null;if(t!=null)for(r in t.ref!==void 0&&(s=t.ref),t.key!==void 0&&(i=""+t.key),t)cp.call(t,r)&&!dp.hasOwnProperty(r)&&(o[r]=t[r]);var l=arguments.length-2;if(l===1)o.children=n;else if(1>>1,B=j[O];if(0>>1;Oo(Y,$))Xo(Q,Y)?(j[O]=Q,j[X]=$,O=X):(j[O]=Y,j[V]=$,O=V);else if(Xo(Q,$))j[O]=Q,j[X]=$,O=X;else break e}}return N}function o(j,N){var $=j.sortIndex-N.sortIndex;return $!==0?$:j.id-N.id}if(typeof performance=="object"&&typeof performance.now=="function"){var i=performance;e.unstable_now=function(){return i.now()}}else{var s=Date,l=s.now();e.unstable_now=function(){return s.now()-l}}var a=[],u=[],p=1,c=null,f=3,x=!1,y=!1,v=!1,k=typeof setTimeout=="function"?setTimeout:null,m=typeof clearTimeout=="function"?clearTimeout:null,g=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function h(j){for(var N=n(u);N!==null;){if(N.callback===null)r(u);else if(N.startTime<=j)r(u),N.sortIndex=N.expirationTime,t(a,N);else break;N=n(u)}}function w(j){if(v=!1,h(j),!y)if(n(a)!==null)y=!0,z(_);else{var N=n(u);N!==null&&R(w,N.startTime-j)}}function _(j,N){y=!1,v&&(v=!1,m(E),E=-1),x=!0;var $=f;try{for(h(N),c=n(a);c!==null&&(!(c.expirationTime>N)||j&&!P());){var O=c.callback;if(typeof O=="function"){c.callback=null,f=c.priorityLevel;var B=O(c.expirationTime<=N);N=e.unstable_now(),typeof B=="function"?c.callback=B:c===n(a)&&r(a),h(N)}else r(a);c=n(a)}if(c!==null)var W=!0;else{var V=n(u);V!==null&&R(w,V.startTime-N),W=!1}return W}finally{c=null,f=$,x=!1}}var S=!1,b=null,E=-1,A=5,D=-1;function P(){return!(e.unstable_now()-Dj||125O?(j.sortIndex=$,t(u,j),n(a)===null&&j===n(u)&&(v?(m(E),E=-1):v=!0,R(w,$-O))):(j.sortIndex=B,t(a,j),y||x||(y=!0,z(_))),j},e.unstable_shouldYield=P,e.unstable_wrapCallback=function(j){var N=f;return function(){var $=f;f=N;try{return j.apply(this,arguments)}finally{f=$}}}})(xp);yp.exports=xp;var Ry=yp.exports;/** + * @license React + * react-dom.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var Ly=M,Qe=Ry;function F(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),ql=Object.prototype.hasOwnProperty,Ay=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,Ic={},Rc={};function $y(e){return ql.call(Rc,e)?!0:ql.call(Ic,e)?!1:Ay.test(e)?Rc[e]=!0:(Ic[e]=!0,!1)}function Dy(e,t,n,r){if(n!==null&&n.type===0)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return r?!1:n!==null?!n.acceptsBooleans:(e=e.toLowerCase().slice(0,5),e!=="data-"&&e!=="aria-");default:return!1}}function Oy(e,t,n,r){if(t===null||typeof t>"u"||Dy(e,t,n,r))return!0;if(r)return!1;if(n!==null)switch(n.type){case 3:return!t;case 4:return t===!1;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}function Ae(e,t,n,r,o,i,s){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=r,this.attributeNamespace=o,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=i,this.removeEmptyString=s}var je={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){je[e]=new Ae(e,0,!1,e,null,!1,!1)});[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0];je[t]=new Ae(t,1,!1,e[1],null,!1,!1)});["contentEditable","draggable","spellCheck","value"].forEach(function(e){je[e]=new Ae(e,2,!1,e.toLowerCase(),null,!1,!1)});["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){je[e]=new Ae(e,2,!1,e,null,!1,!1)});"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){je[e]=new Ae(e,3,!1,e.toLowerCase(),null,!1,!1)});["checked","multiple","muted","selected"].forEach(function(e){je[e]=new Ae(e,3,!0,e,null,!1,!1)});["capture","download"].forEach(function(e){je[e]=new Ae(e,4,!1,e,null,!1,!1)});["cols","rows","size","span"].forEach(function(e){je[e]=new Ae(e,6,!1,e,null,!1,!1)});["rowSpan","start"].forEach(function(e){je[e]=new Ae(e,5,!1,e.toLowerCase(),null,!1,!1)});var fu=/[\-:]([a-z])/g;function pu(e){return e[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var t=e.replace(fu,pu);je[t]=new Ae(t,1,!1,e,null,!1,!1)});"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var t=e.replace(fu,pu);je[t]=new Ae(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)});["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(fu,pu);je[t]=new Ae(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)});["tabIndex","crossOrigin"].forEach(function(e){je[e]=new Ae(e,1,!1,e.toLowerCase(),null,!1,!1)});je.xlinkHref=new Ae("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1);["src","href","action","formAction"].forEach(function(e){je[e]=new Ae(e,1,!1,e.toLowerCase(),null,!0,!0)});function hu(e,t,n,r){var o=je.hasOwnProperty(t)?je[t]:null;(o!==null?o.type!==0:r||!(2l||o[s]!==i[l]){var a=` +`+o[s].replace(" at new "," at ");return e.displayName&&a.includes("")&&(a=a.replace("",e.displayName)),a}while(1<=s&&0<=l);break}}}finally{al=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?Qr(e):""}function By(e){switch(e.tag){case 5:return Qr(e.type);case 16:return Qr("Lazy");case 13:return Qr("Suspense");case 19:return Qr("SuspenseList");case 0:case 2:case 15:return e=ul(e.type,!1),e;case 11:return e=ul(e.type.render,!1),e;case 1:return e=ul(e.type,!0),e;default:return""}}function na(e){if(e==null)return null;if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case Wn:return"Fragment";case Vn:return"Portal";case Jl:return"Profiler";case gu:return"StrictMode";case ea:return"Suspense";case ta:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case Sp:return(e.displayName||"Context")+".Consumer";case wp:return(e._context.displayName||"Context")+".Provider";case mu:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case yu:return t=e.displayName||null,t!==null?t:na(e.type)||"Memo";case Xt:t=e._payload,e=e._init;try{return na(e(t))}catch{}}return null}function Fy(e){var t=e.type;switch(e.tag){case 24:return"Cache";case 9:return(t.displayName||"Context")+".Consumer";case 10:return(t._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=t.render,e=e.displayName||e.name||"",t.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return t;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return na(t);case 8:return t===gu?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof t=="function")return t.displayName||t.name||null;if(typeof t=="string")return t}return null}function cn(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function _p(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function Hy(e){var t=_p(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=""+e[t];if(!e.hasOwnProperty(t)&&typeof n<"u"&&typeof n.get=="function"&&typeof n.set=="function"){var o=n.get,i=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return o.call(this)},set:function(s){r=""+s,i.call(this,s)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(s){r=""+s},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function ei(e){e._valueTracker||(e._valueTracker=Hy(e))}function bp(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=_p(e)?e.checked?"true":"false":e.value),e=r,e!==n?(t.setValue(e),!0):!1}function Xi(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}function ra(e,t){var n=t.checked;return me({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:n??e._wrapperState.initialChecked})}function Ac(e,t){var n=t.defaultValue==null?"":t.defaultValue,r=t.checked!=null?t.checked:t.defaultChecked;n=cn(t.value!=null?t.value:n),e._wrapperState={initialChecked:r,initialValue:n,controlled:t.type==="checkbox"||t.type==="radio"?t.checked!=null:t.value!=null}}function Cp(e,t){t=t.checked,t!=null&&hu(e,"checked",t,!1)}function oa(e,t){Cp(e,t);var n=cn(t.value),r=t.type;if(n!=null)r==="number"?(n===0&&e.value===""||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if(r==="submit"||r==="reset"){e.removeAttribute("value");return}t.hasOwnProperty("value")?ia(e,t.type,n):t.hasOwnProperty("defaultValue")&&ia(e,t.type,cn(t.defaultValue)),t.checked==null&&t.defaultChecked!=null&&(e.defaultChecked=!!t.defaultChecked)}function $c(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var r=t.type;if(!(r!=="submit"&&r!=="reset"||t.value!==void 0&&t.value!==null))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}n=e.name,n!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,n!==""&&(e.name=n)}function ia(e,t,n){(t!=="number"||Xi(e.ownerDocument)!==e)&&(n==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}var Gr=Array.isArray;function rr(e,t,n,r){if(e=e.options,t){t={};for(var o=0;o"+t.valueOf().toString()+"",t=ti.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}});function po(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&n.nodeType===3){n.nodeValue=t;return}}e.textContent=t}var eo={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},Vy=["Webkit","ms","Moz","O"];Object.keys(eo).forEach(function(e){Vy.forEach(function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),eo[t]=eo[e]})});function Mp(e,t,n){return t==null||typeof t=="boolean"||t===""?"":n||typeof t!="number"||t===0||eo.hasOwnProperty(e)&&eo[e]?(""+t).trim():t+"px"}function zp(e,t){e=e.style;for(var n in t)if(t.hasOwnProperty(n)){var r=n.indexOf("--")===0,o=Mp(n,t[n],r);n==="float"&&(n="cssFloat"),r?e.setProperty(n,o):e[n]=o}}var Wy=me({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function aa(e,t){if(t){if(Wy[e]&&(t.children!=null||t.dangerouslySetInnerHTML!=null))throw Error(F(137,e));if(t.dangerouslySetInnerHTML!=null){if(t.children!=null)throw Error(F(60));if(typeof t.dangerouslySetInnerHTML!="object"||!("__html"in t.dangerouslySetInnerHTML))throw Error(F(61))}if(t.style!=null&&typeof t.style!="object")throw Error(F(62))}}function ua(e,t){if(e.indexOf("-")===-1)return typeof t.is=="string";switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var ca=null;function xu(e){return e=e.target||e.srcElement||window,e.correspondingUseElement&&(e=e.correspondingUseElement),e.nodeType===3?e.parentNode:e}var da=null,or=null,ir=null;function Bc(e){if(e=Ho(e)){if(typeof da!="function")throw Error(F(280));var t=e.stateNode;t&&(t=Is(t),da(e.stateNode,e.type,t))}}function Tp(e){or?ir?ir.push(e):ir=[e]:or=e}function Pp(){if(or){var e=or,t=ir;if(ir=or=null,Bc(e),t)for(e=0;e>>=0,e===0?32:31-(tx(e)/nx|0)|0}var ni=64,ri=4194304;function Kr(e){switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return e&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return e}}function Zi(e,t){var n=e.pendingLanes;if(n===0)return 0;var r=0,o=e.suspendedLanes,i=e.pingedLanes,s=n&268435455;if(s!==0){var l=s&~o;l!==0?r=Kr(l):(i&=s,i!==0&&(r=Kr(i)))}else s=n&~o,s!==0?r=Kr(s):i!==0&&(r=Kr(i));if(r===0)return 0;if(t!==0&&t!==r&&!(t&o)&&(o=r&-r,i=t&-t,o>=i||o===16&&(i&4194240)!==0))return t;if(r&4&&(r|=n&16),t=e.entangledLanes,t!==0)for(e=e.entanglements,t&=r;0n;n++)t.push(e);return t}function Bo(e,t,n){e.pendingLanes|=t,t!==536870912&&(e.suspendedLanes=0,e.pingedLanes=0),e=e.eventTimes,t=31-ft(t),e[t]=n}function sx(e,t){var n=e.pendingLanes&~t;e.pendingLanes=t,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=t,e.mutableReadLanes&=t,e.entangledLanes&=t,t=e.entanglements;var r=e.eventTimes;for(e=e.expirationTimes;0=no),Gc=" ",Kc=!1;function qp(e,t){switch(e){case"keyup":return Rx.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Jp(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var Un=!1;function Ax(e,t){switch(e){case"compositionend":return Jp(t);case"keypress":return t.which!==32?null:(Kc=!0,Gc);case"textInput":return e=t.data,e===Gc&&Kc?null:e;default:return null}}function $x(e,t){if(Un)return e==="compositionend"||!Eu&&qp(e,t)?(e=Kp(),Ii=_u=qt=null,Un=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}e:{for(;n;){if(n.nextSibling){n=n.nextSibling;break e}n=n.parentNode}n=void 0}n=ed(n)}}function rh(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?rh(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function oh(){for(var e=window,t=Xi();t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href=="string"}catch{n=!1}if(n)e=t.contentWindow;else break;t=Xi(e.document)}return t}function ju(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}function Yx(e){var t=oh(),n=e.focusedElem,r=e.selectionRange;if(t!==n&&n&&n.ownerDocument&&rh(n.ownerDocument.documentElement,n)){if(r!==null&&ju(n)){if(t=r.start,e=r.end,e===void 0&&(e=t),"selectionStart"in n)n.selectionStart=t,n.selectionEnd=Math.min(e,n.value.length);else if(e=(t=n.ownerDocument||document)&&t.defaultView||window,e.getSelection){e=e.getSelection();var o=n.textContent.length,i=Math.min(r.start,o);r=r.end===void 0?i:Math.min(r.end,o),!e.extend&&i>r&&(o=r,r=i,i=o),o=td(n,i);var s=td(n,r);o&&s&&(e.rangeCount!==1||e.anchorNode!==o.node||e.anchorOffset!==o.offset||e.focusNode!==s.node||e.focusOffset!==s.offset)&&(t=t.createRange(),t.setStart(o.node,o.offset),e.removeAllRanges(),i>r?(e.addRange(t),e.extend(s.node,s.offset)):(t.setEnd(s.node,s.offset),e.addRange(t)))}}for(t=[],e=n;e=e.parentNode;)e.nodeType===1&&t.push({element:e,left:e.scrollLeft,top:e.scrollTop});for(typeof n.focus=="function"&&n.focus(),n=0;n=document.documentMode,Yn=null,ya=null,oo=null,xa=!1;function nd(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;xa||Yn==null||Yn!==Xi(r)||(r=Yn,"selectionStart"in r&&ju(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),oo&&vo(oo,r)||(oo=r,r=es(ya,"onSelect"),0Gn||(e.current=ba[Gn],ba[Gn]=null,Gn--)}function ae(e,t){Gn++,ba[Gn]=e.current,e.current=t}var dn={},Pe=pn(dn),Be=pn(!1),jn=dn;function fr(e,t){var n=e.type.contextTypes;if(!n)return dn;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var o={},i;for(i in n)o[i]=t[i];return r&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=o),o}function Fe(e){return e=e.childContextTypes,e!=null}function ns(){ce(Be),ce(Pe)}function ud(e,t,n){if(Pe.current!==dn)throw Error(F(168));ae(Pe,t),ae(Be,n)}function ph(e,t,n){var r=e.stateNode;if(t=t.childContextTypes,typeof r.getChildContext!="function")return n;r=r.getChildContext();for(var o in r)if(!(o in t))throw Error(F(108,Fy(e)||"Unknown",o));return me({},n,r)}function rs(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||dn,jn=Pe.current,ae(Pe,e),ae(Be,Be.current),!0}function cd(e,t,n){var r=e.stateNode;if(!r)throw Error(F(169));n?(e=ph(e,t,jn),r.__reactInternalMemoizedMergedChildContext=e,ce(Be),ce(Pe),ae(Pe,e)):ce(Be),ae(Be,n)}var Tt=null,Rs=!1,_l=!1;function hh(e){Tt===null?Tt=[e]:Tt.push(e)}function o1(e){Rs=!0,hh(e)}function hn(){if(!_l&&Tt!==null){_l=!0;var e=0,t=se;try{var n=Tt;for(se=1;e>=s,o-=s,Pt=1<<32-ft(t)+o|n<E?(A=b,b=null):A=b.sibling;var D=f(m,b,h[E],w);if(D===null){b===null&&(b=A);break}e&&b&&D.alternate===null&&t(m,b),g=i(D,g,E),S===null?_=D:S.sibling=D,S=D,b=A}if(E===h.length)return n(m,b),de&&mn(m,E),_;if(b===null){for(;EE?(A=b,b=null):A=b.sibling;var P=f(m,b,D.value,w);if(P===null){b===null&&(b=A);break}e&&b&&P.alternate===null&&t(m,b),g=i(P,g,E),S===null?_=P:S.sibling=P,S=P,b=A}if(D.done)return n(m,b),de&&mn(m,E),_;if(b===null){for(;!D.done;E++,D=h.next())D=c(m,D.value,w),D!==null&&(g=i(D,g,E),S===null?_=D:S.sibling=D,S=D);return de&&mn(m,E),_}for(b=r(m,b);!D.done;E++,D=h.next())D=x(b,m,E,D.value,w),D!==null&&(e&&D.alternate!==null&&b.delete(D.key===null?E:D.key),g=i(D,g,E),S===null?_=D:S.sibling=D,S=D);return e&&b.forEach(function(I){return t(m,I)}),de&&mn(m,E),_}function k(m,g,h,w){if(typeof h=="object"&&h!==null&&h.type===Wn&&h.key===null&&(h=h.props.children),typeof h=="object"&&h!==null){switch(h.$$typeof){case Jo:e:{for(var _=h.key,S=g;S!==null;){if(S.key===_){if(_=h.type,_===Wn){if(S.tag===7){n(m,S.sibling),g=o(S,h.props.children),g.return=m,m=g;break e}}else if(S.elementType===_||typeof _=="object"&&_!==null&&_.$$typeof===Xt&&pd(_)===S.type){n(m,S.sibling),g=o(S,h.props),g.ref=Or(m,S,h),g.return=m,m=g;break e}n(m,S);break}else t(m,S);S=S.sibling}h.type===Wn?(g=bn(h.props.children,m.mode,w,h.key),g.return=m,m=g):(w=Fi(h.type,h.key,h.props,null,m.mode,w),w.ref=Or(m,g,h),w.return=m,m=w)}return s(m);case Vn:e:{for(S=h.key;g!==null;){if(g.key===S)if(g.tag===4&&g.stateNode.containerInfo===h.containerInfo&&g.stateNode.implementation===h.implementation){n(m,g.sibling),g=o(g,h.children||[]),g.return=m,m=g;break e}else{n(m,g);break}else t(m,g);g=g.sibling}g=Tl(h,m.mode,w),g.return=m,m=g}return s(m);case Xt:return S=h._init,k(m,g,S(h._payload),w)}if(Gr(h))return y(m,g,h,w);if(Rr(h))return v(m,g,h,w);ci(m,h)}return typeof h=="string"&&h!==""||typeof h=="number"?(h=""+h,g!==null&&g.tag===6?(n(m,g.sibling),g=o(g,h),g.return=m,m=g):(n(m,g),g=zl(h,m.mode,w),g.return=m,m=g),s(m)):n(m,g)}return k}var hr=xh(!0),vh=xh(!1),ss=pn(null),ls=null,qn=null,Tu=null;function Pu(){Tu=qn=ls=null}function Iu(e){var t=ss.current;ce(ss),e._currentValue=t}function ja(e,t,n){for(;e!==null;){var r=e.alternate;if((e.childLanes&t)!==t?(e.childLanes|=t,r!==null&&(r.childLanes|=t)):r!==null&&(r.childLanes&t)!==t&&(r.childLanes|=t),e===n)break;e=e.return}}function lr(e,t){ls=e,Tu=qn=null,e=e.dependencies,e!==null&&e.firstContext!==null&&(e.lanes&t&&(De=!0),e.firstContext=null)}function nt(e){var t=e._currentValue;if(Tu!==e)if(e={context:e,memoizedValue:t,next:null},qn===null){if(ls===null)throw Error(F(308));qn=e,ls.dependencies={lanes:0,firstContext:e}}else qn=qn.next=e;return t}var wn=null;function Ru(e){wn===null?wn=[e]:wn.push(e)}function wh(e,t,n,r){var o=t.interleaved;return o===null?(n.next=n,Ru(t)):(n.next=o.next,o.next=n),t.interleaved=n,Dt(e,r)}function Dt(e,t){e.lanes|=t;var n=e.alternate;for(n!==null&&(n.lanes|=t),n=e,e=e.return;e!==null;)e.childLanes|=t,n=e.alternate,n!==null&&(n.childLanes|=t),n=e,e=e.return;return n.tag===3?n.stateNode:null}var Qt=!1;function Lu(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,interleaved:null,lanes:0},effects:null}}function Sh(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,effects:e.effects})}function Lt(e,t){return{eventTime:e,lane:t,tag:0,payload:null,callback:null,next:null}}function on(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,oe&2){var o=r.pending;return o===null?t.next=t:(t.next=o.next,o.next=t),r.pending=t,Dt(e,n)}return o=r.interleaved,o===null?(t.next=t,Ru(r)):(t.next=o.next,o.next=t),r.interleaved=t,Dt(e,n)}function Li(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,(n&4194240)!==0)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,wu(e,n)}}function hd(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var o=null,i=null;if(n=n.firstBaseUpdate,n!==null){do{var s={eventTime:n.eventTime,lane:n.lane,tag:n.tag,payload:n.payload,callback:n.callback,next:null};i===null?o=i=s:i=i.next=s,n=n.next}while(n!==null);i===null?o=i=t:i=i.next=t}else o=i=t;n={baseState:r.baseState,firstBaseUpdate:o,lastBaseUpdate:i,shared:r.shared,effects:r.effects},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}function as(e,t,n,r){var o=e.updateQueue;Qt=!1;var i=o.firstBaseUpdate,s=o.lastBaseUpdate,l=o.shared.pending;if(l!==null){o.shared.pending=null;var a=l,u=a.next;a.next=null,s===null?i=u:s.next=u,s=a;var p=e.alternate;p!==null&&(p=p.updateQueue,l=p.lastBaseUpdate,l!==s&&(l===null?p.firstBaseUpdate=u:l.next=u,p.lastBaseUpdate=a))}if(i!==null){var c=o.baseState;s=0,p=u=a=null,l=i;do{var f=l.lane,x=l.eventTime;if((r&f)===f){p!==null&&(p=p.next={eventTime:x,lane:0,tag:l.tag,payload:l.payload,callback:l.callback,next:null});e:{var y=e,v=l;switch(f=t,x=n,v.tag){case 1:if(y=v.payload,typeof y=="function"){c=y.call(x,c,f);break e}c=y;break e;case 3:y.flags=y.flags&-65537|128;case 0:if(y=v.payload,f=typeof y=="function"?y.call(x,c,f):y,f==null)break e;c=me({},c,f);break e;case 2:Qt=!0}}l.callback!==null&&l.lane!==0&&(e.flags|=64,f=o.effects,f===null?o.effects=[l]:f.push(l))}else x={eventTime:x,lane:f,tag:l.tag,payload:l.payload,callback:l.callback,next:null},p===null?(u=p=x,a=c):p=p.next=x,s|=f;if(l=l.next,l===null){if(l=o.shared.pending,l===null)break;f=l,l=f.next,f.next=null,o.lastBaseUpdate=f,o.shared.pending=null}}while(!0);if(p===null&&(a=c),o.baseState=a,o.firstBaseUpdate=u,o.lastBaseUpdate=p,t=o.shared.interleaved,t!==null){o=t;do s|=o.lane,o=o.next;while(o!==t)}else i===null&&(o.shared.lanes=0);zn|=s,e.lanes=s,e.memoizedState=c}}function gd(e,t,n){if(e=t.effects,t.effects=null,e!==null)for(t=0;tn?n:4,e(!0);var r=Cl.transition;Cl.transition={};try{e(!1),t()}finally{se=n,Cl.transition=r}}function Dh(){return rt().memoizedState}function a1(e,t,n){var r=ln(e);if(n={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null},Oh(e))Bh(t,n);else if(n=wh(e,t,n,r),n!==null){var o=Re();pt(n,e,r,o),Fh(n,t,r)}}function u1(e,t,n){var r=ln(e),o={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null};if(Oh(e))Bh(t,o);else{var i=e.alternate;if(e.lanes===0&&(i===null||i.lanes===0)&&(i=t.lastRenderedReducer,i!==null))try{var s=t.lastRenderedState,l=i(s,n);if(o.hasEagerState=!0,o.eagerState=l,ht(l,s)){var a=t.interleaved;a===null?(o.next=o,Ru(t)):(o.next=a.next,a.next=o),t.interleaved=o;return}}catch{}finally{}n=wh(e,t,o,r),n!==null&&(o=Re(),pt(n,e,r,o),Fh(n,t,r))}}function Oh(e){var t=e.alternate;return e===ge||t!==null&&t===ge}function Bh(e,t){io=cs=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function Fh(e,t,n){if(n&4194240){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,wu(e,n)}}var ds={readContext:nt,useCallback:Me,useContext:Me,useEffect:Me,useImperativeHandle:Me,useInsertionEffect:Me,useLayoutEffect:Me,useMemo:Me,useReducer:Me,useRef:Me,useState:Me,useDebugValue:Me,useDeferredValue:Me,useTransition:Me,useMutableSource:Me,useSyncExternalStore:Me,useId:Me,unstable_isNewReconciler:!1},c1={readContext:nt,useCallback:function(e,t){return wt().memoizedState=[e,t===void 0?null:t],e},useContext:nt,useEffect:yd,useImperativeHandle:function(e,t,n){return n=n!=null?n.concat([e]):null,$i(4194308,4,Ih.bind(null,t,e),n)},useLayoutEffect:function(e,t){return $i(4194308,4,e,t)},useInsertionEffect:function(e,t){return $i(4,2,e,t)},useMemo:function(e,t){var n=wt();return t=t===void 0?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var r=wt();return t=n!==void 0?n(t):t,r.memoizedState=r.baseState=t,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:t},r.queue=e,e=e.dispatch=a1.bind(null,ge,e),[r.memoizedState,e]},useRef:function(e){var t=wt();return e={current:e},t.memoizedState=e},useState:md,useDebugValue:Vu,useDeferredValue:function(e){return wt().memoizedState=e},useTransition:function(){var e=md(!1),t=e[0];return e=l1.bind(null,e[1]),wt().memoizedState=e,[t,e]},useMutableSource:function(){},useSyncExternalStore:function(e,t,n){var r=ge,o=wt();if(de){if(n===void 0)throw Error(F(407));n=n()}else{if(n=t(),be===null)throw Error(F(349));Mn&30||Ch(r,t,n)}o.memoizedState=n;var i={value:n,getSnapshot:t};return o.queue=i,yd(jh.bind(null,r,i,e),[e]),r.flags|=2048,jo(9,Eh.bind(null,r,i,n,t),void 0,null),n},useId:function(){var e=wt(),t=be.identifierPrefix;if(de){var n=It,r=Pt;n=(r&~(1<<32-ft(r)-1)).toString(32)+n,t=":"+t+"R"+n,n=Co++,0<\/script>",e=e.removeChild(e.firstChild)):typeof r.is=="string"?e=s.createElement(n,{is:r.is}):(e=s.createElement(n),n==="select"&&(s=e,r.multiple?s.multiple=!0:r.size&&(s.size=r.size))):e=s.createElementNS(e,n),e[kt]=t,e[ko]=r,Zh(e,t,!1,!1),t.stateNode=e;e:{switch(s=ua(n,r),n){case"dialog":ue("cancel",e),ue("close",e),o=r;break;case"iframe":case"object":case"embed":ue("load",e),o=r;break;case"video":case"audio":for(o=0;oyr&&(t.flags|=128,r=!0,Br(i,!1),t.lanes=4194304)}else{if(!r)if(e=us(s),e!==null){if(t.flags|=128,r=!0,n=e.updateQueue,n!==null&&(t.updateQueue=n,t.flags|=4),Br(i,!0),i.tail===null&&i.tailMode==="hidden"&&!s.alternate&&!de)return ze(t),null}else 2*xe()-i.renderingStartTime>yr&&n!==1073741824&&(t.flags|=128,r=!0,Br(i,!1),t.lanes=4194304);i.isBackwards?(s.sibling=t.child,t.child=s):(n=i.last,n!==null?n.sibling=s:t.child=s,i.last=s)}return i.tail!==null?(t=i.tail,i.rendering=t,i.tail=t.sibling,i.renderingStartTime=xe(),t.sibling=null,n=he.current,ae(he,r?n&1|2:n&1),t):(ze(t),null);case 22:case 23:return Gu(),r=t.memoizedState!==null,e!==null&&e.memoizedState!==null!==r&&(t.flags|=8192),r&&t.mode&1?We&1073741824&&(ze(t),t.subtreeFlags&6&&(t.flags|=8192)):ze(t),null;case 24:return null;case 25:return null}throw Error(F(156,t.tag))}function x1(e,t){switch(Mu(t),t.tag){case 1:return Fe(t.type)&&ns(),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return gr(),ce(Be),ce(Pe),Du(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 5:return $u(t),null;case 13:if(ce(he),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(F(340));pr()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return ce(he),null;case 4:return gr(),null;case 10:return Iu(t.type._context),null;case 22:case 23:return Gu(),null;case 24:return null;default:return null}}var fi=!1,Te=!1,v1=typeof WeakSet=="function"?WeakSet:Set,U=null;function Jn(e,t){var n=e.ref;if(n!==null)if(typeof n=="function")try{n(null)}catch(r){ye(e,t,r)}else n.current=null}function Aa(e,t,n){try{n()}catch(r){ye(e,t,r)}}var Nd=!1;function w1(e,t){if(va=qi,e=oh(),ju(e)){if("selectionStart"in e)var n={start:e.selectionStart,end:e.selectionEnd};else e:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var o=r.anchorOffset,i=r.focusNode;r=r.focusOffset;try{n.nodeType,i.nodeType}catch{n=null;break e}var s=0,l=-1,a=-1,u=0,p=0,c=e,f=null;t:for(;;){for(var x;c!==n||o!==0&&c.nodeType!==3||(l=s+o),c!==i||r!==0&&c.nodeType!==3||(a=s+r),c.nodeType===3&&(s+=c.nodeValue.length),(x=c.firstChild)!==null;)f=c,c=x;for(;;){if(c===e)break t;if(f===n&&++u===o&&(l=s),f===i&&++p===r&&(a=s),(x=c.nextSibling)!==null)break;c=f,f=c.parentNode}c=x}n=l===-1||a===-1?null:{start:l,end:a}}else n=null}n=n||{start:0,end:0}}else n=null;for(wa={focusedElem:e,selectionRange:n},qi=!1,U=t;U!==null;)if(t=U,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,U=e;else for(;U!==null;){t=U;try{var y=t.alternate;if(t.flags&1024)switch(t.tag){case 0:case 11:case 15:break;case 1:if(y!==null){var v=y.memoizedProps,k=y.memoizedState,m=t.stateNode,g=m.getSnapshotBeforeUpdate(t.elementType===t.type?v:it(t.type,v),k);m.__reactInternalSnapshotBeforeUpdate=g}break;case 3:var h=t.stateNode.containerInfo;h.nodeType===1?h.textContent="":h.nodeType===9&&h.documentElement&&h.removeChild(h.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(F(163))}}catch(w){ye(t,t.return,w)}if(e=t.sibling,e!==null){e.return=t.return,U=e;break}U=t.return}return y=Nd,Nd=!1,y}function so(e,t,n){var r=t.updateQueue;if(r=r!==null?r.lastEffect:null,r!==null){var o=r=r.next;do{if((o.tag&e)===e){var i=o.destroy;o.destroy=void 0,i!==void 0&&Aa(t,n,i)}o=o.next}while(o!==r)}}function $s(e,t){if(t=t.updateQueue,t=t!==null?t.lastEffect:null,t!==null){var n=t=t.next;do{if((n.tag&e)===e){var r=n.create;n.destroy=r()}n=n.next}while(n!==t)}}function $a(e){var t=e.ref;if(t!==null){var n=e.stateNode;switch(e.tag){case 5:e=n;break;default:e=n}typeof t=="function"?t(e):t.current=e}}function eg(e){var t=e.alternate;t!==null&&(e.alternate=null,eg(t)),e.child=null,e.deletions=null,e.sibling=null,e.tag===5&&(t=e.stateNode,t!==null&&(delete t[kt],delete t[ko],delete t[_a],delete t[n1],delete t[r1])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function tg(e){return e.tag===5||e.tag===3||e.tag===4}function Md(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||tg(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function Da(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.nodeType===8?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(n.nodeType===8?(t=n.parentNode,t.insertBefore(e,n)):(t=n,t.appendChild(e)),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=ts));else if(r!==4&&(e=e.child,e!==null))for(Da(e,t,n),e=e.sibling;e!==null;)Da(e,t,n),e=e.sibling}function Oa(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(e=e.child,e!==null))for(Oa(e,t,n),e=e.sibling;e!==null;)Oa(e,t,n),e=e.sibling}var Ce=null,st=!1;function Wt(e,t,n){for(n=n.child;n!==null;)ng(e,t,n),n=n.sibling}function ng(e,t,n){if(_t&&typeof _t.onCommitFiberUnmount=="function")try{_t.onCommitFiberUnmount(Ms,n)}catch{}switch(n.tag){case 5:Te||Jn(n,t);case 6:var r=Ce,o=st;Ce=null,Wt(e,t,n),Ce=r,st=o,Ce!==null&&(st?(e=Ce,n=n.stateNode,e.nodeType===8?e.parentNode.removeChild(n):e.removeChild(n)):Ce.removeChild(n.stateNode));break;case 18:Ce!==null&&(st?(e=Ce,n=n.stateNode,e.nodeType===8?kl(e.parentNode,n):e.nodeType===1&&kl(e,n),yo(e)):kl(Ce,n.stateNode));break;case 4:r=Ce,o=st,Ce=n.stateNode.containerInfo,st=!0,Wt(e,t,n),Ce=r,st=o;break;case 0:case 11:case 14:case 15:if(!Te&&(r=n.updateQueue,r!==null&&(r=r.lastEffect,r!==null))){o=r=r.next;do{var i=o,s=i.destroy;i=i.tag,s!==void 0&&(i&2||i&4)&&Aa(n,t,s),o=o.next}while(o!==r)}Wt(e,t,n);break;case 1:if(!Te&&(Jn(n,t),r=n.stateNode,typeof r.componentWillUnmount=="function"))try{r.props=n.memoizedProps,r.state=n.memoizedState,r.componentWillUnmount()}catch(l){ye(n,t,l)}Wt(e,t,n);break;case 21:Wt(e,t,n);break;case 22:n.mode&1?(Te=(r=Te)||n.memoizedState!==null,Wt(e,t,n),Te=r):Wt(e,t,n);break;default:Wt(e,t,n)}}function zd(e){var t=e.updateQueue;if(t!==null){e.updateQueue=null;var n=e.stateNode;n===null&&(n=e.stateNode=new v1),t.forEach(function(r){var o=M1.bind(null,e,r);n.has(r)||(n.add(r),r.then(o,o))})}}function ot(e,t){var n=t.deletions;if(n!==null)for(var r=0;ro&&(o=s),r&=~i}if(r=o,r=xe()-r,r=(120>r?120:480>r?480:1080>r?1080:1920>r?1920:3e3>r?3e3:4320>r?4320:1960*k1(r/1960))-r,10e?16:e,Jt===null)var r=!1;else{if(e=Jt,Jt=null,hs=0,oe&6)throw Error(F(331));var o=oe;for(oe|=4,U=e.current;U!==null;){var i=U,s=i.child;if(U.flags&16){var l=i.deletions;if(l!==null){for(var a=0;axe()-Xu?_n(e,0):Yu|=n),He(e,t)}function cg(e,t){t===0&&(e.mode&1?(t=ri,ri<<=1,!(ri&130023424)&&(ri=4194304)):t=1);var n=Re();e=Dt(e,t),e!==null&&(Bo(e,t,n),He(e,n))}function N1(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),cg(e,n)}function M1(e,t){var n=0;switch(e.tag){case 13:var r=e.stateNode,o=e.memoizedState;o!==null&&(n=o.retryLane);break;case 19:r=e.stateNode;break;default:throw Error(F(314))}r!==null&&r.delete(t),cg(e,n)}var dg;dg=function(e,t,n){if(e!==null)if(e.memoizedProps!==t.pendingProps||Be.current)De=!0;else{if(!(e.lanes&n)&&!(t.flags&128))return De=!1,m1(e,t,n);De=!!(e.flags&131072)}else De=!1,de&&t.flags&1048576&&gh(t,is,t.index);switch(t.lanes=0,t.tag){case 2:var r=t.type;Di(e,t),e=t.pendingProps;var o=fr(t,Pe.current);lr(t,n),o=Bu(null,t,r,e,o,n);var i=Fu();return t.flags|=1,typeof o=="object"&&o!==null&&typeof o.render=="function"&&o.$$typeof===void 0?(t.tag=1,t.memoizedState=null,t.updateQueue=null,Fe(r)?(i=!0,rs(t)):i=!1,t.memoizedState=o.state!==null&&o.state!==void 0?o.state:null,Lu(t),o.updater=As,t.stateNode=o,o._reactInternals=t,Ma(t,r,e,n),t=Pa(null,t,r,!0,i,n)):(t.tag=0,de&&i&&Nu(t),Ie(null,t,o,n),t=t.child),t;case 16:r=t.elementType;e:{switch(Di(e,t),e=t.pendingProps,o=r._init,r=o(r._payload),t.type=r,o=t.tag=T1(r),e=it(r,e),o){case 0:t=Ta(null,t,r,e,n);break e;case 1:t=Cd(null,t,r,e,n);break e;case 11:t=_d(null,t,r,e,n);break e;case 14:t=bd(null,t,r,it(r.type,e),n);break e}throw Error(F(306,r,""))}return t;case 0:return r=t.type,o=t.pendingProps,o=t.elementType===r?o:it(r,o),Ta(e,t,r,o,n);case 1:return r=t.type,o=t.pendingProps,o=t.elementType===r?o:it(r,o),Cd(e,t,r,o,n);case 3:e:{if(Qh(t),e===null)throw Error(F(387));r=t.pendingProps,i=t.memoizedState,o=i.element,Sh(e,t),as(t,r,null,n);var s=t.memoizedState;if(r=s.element,i.isDehydrated)if(i={element:r,isDehydrated:!1,cache:s.cache,pendingSuspenseBoundaries:s.pendingSuspenseBoundaries,transitions:s.transitions},t.updateQueue.baseState=i,t.memoizedState=i,t.flags&256){o=mr(Error(F(423)),t),t=Ed(e,t,r,n,o);break e}else if(r!==o){o=mr(Error(F(424)),t),t=Ed(e,t,r,n,o);break e}else for(Ye=rn(t.stateNode.containerInfo.firstChild),Xe=t,de=!0,at=null,n=vh(t,null,r,n),t.child=n;n;)n.flags=n.flags&-3|4096,n=n.sibling;else{if(pr(),r===o){t=Ot(e,t,n);break e}Ie(e,t,r,n)}t=t.child}return t;case 5:return kh(t),e===null&&Ea(t),r=t.type,o=t.pendingProps,i=e!==null?e.memoizedProps:null,s=o.children,Sa(r,o)?s=null:i!==null&&Sa(r,i)&&(t.flags|=32),Xh(e,t),Ie(e,t,s,n),t.child;case 6:return e===null&&Ea(t),null;case 13:return Gh(e,t,n);case 4:return Au(t,t.stateNode.containerInfo),r=t.pendingProps,e===null?t.child=hr(t,null,r,n):Ie(e,t,r,n),t.child;case 11:return r=t.type,o=t.pendingProps,o=t.elementType===r?o:it(r,o),_d(e,t,r,o,n);case 7:return Ie(e,t,t.pendingProps,n),t.child;case 8:return Ie(e,t,t.pendingProps.children,n),t.child;case 12:return Ie(e,t,t.pendingProps.children,n),t.child;case 10:e:{if(r=t.type._context,o=t.pendingProps,i=t.memoizedProps,s=o.value,ae(ss,r._currentValue),r._currentValue=s,i!==null)if(ht(i.value,s)){if(i.children===o.children&&!Be.current){t=Ot(e,t,n);break e}}else for(i=t.child,i!==null&&(i.return=t);i!==null;){var l=i.dependencies;if(l!==null){s=i.child;for(var a=l.firstContext;a!==null;){if(a.context===r){if(i.tag===1){a=Lt(-1,n&-n),a.tag=2;var u=i.updateQueue;if(u!==null){u=u.shared;var p=u.pending;p===null?a.next=a:(a.next=p.next,p.next=a),u.pending=a}}i.lanes|=n,a=i.alternate,a!==null&&(a.lanes|=n),ja(i.return,n,t),l.lanes|=n;break}a=a.next}}else if(i.tag===10)s=i.type===t.type?null:i.child;else if(i.tag===18){if(s=i.return,s===null)throw Error(F(341));s.lanes|=n,l=s.alternate,l!==null&&(l.lanes|=n),ja(s,n,t),s=i.sibling}else s=i.child;if(s!==null)s.return=i;else for(s=i;s!==null;){if(s===t){s=null;break}if(i=s.sibling,i!==null){i.return=s.return,s=i;break}s=s.return}i=s}Ie(e,t,o.children,n),t=t.child}return t;case 9:return o=t.type,r=t.pendingProps.children,lr(t,n),o=nt(o),r=r(o),t.flags|=1,Ie(e,t,r,n),t.child;case 14:return r=t.type,o=it(r,t.pendingProps),o=it(r.type,o),bd(e,t,r,o,n);case 15:return Uh(e,t,t.type,t.pendingProps,n);case 17:return r=t.type,o=t.pendingProps,o=t.elementType===r?o:it(r,o),Di(e,t),t.tag=1,Fe(r)?(e=!0,rs(t)):e=!1,lr(t,n),Hh(t,r,o),Ma(t,r,o,n),Pa(null,t,r,!0,e,n);case 19:return Kh(e,t,n);case 22:return Yh(e,t,n)}throw Error(F(156,t.tag))};function fg(e,t){return Op(e,t)}function z1(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function et(e,t,n,r){return new z1(e,t,n,r)}function Zu(e){return e=e.prototype,!(!e||!e.isReactComponent)}function T1(e){if(typeof e=="function")return Zu(e)?1:0;if(e!=null){if(e=e.$$typeof,e===mu)return 11;if(e===yu)return 14}return 2}function an(e,t){var n=e.alternate;return n===null?(n=et(e.tag,t,e.key,e.mode),n.elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.subtreeFlags=0,n.deletions=null),n.flags=e.flags&14680064,n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=t===null?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function Fi(e,t,n,r,o,i){var s=2;if(r=e,typeof e=="function")Zu(e)&&(s=1);else if(typeof e=="string")s=5;else e:switch(e){case Wn:return bn(n.children,o,i,t);case gu:s=8,o|=8;break;case Jl:return e=et(12,n,t,o|2),e.elementType=Jl,e.lanes=i,e;case ea:return e=et(13,n,t,o),e.elementType=ea,e.lanes=i,e;case ta:return e=et(19,n,t,o),e.elementType=ta,e.lanes=i,e;case kp:return Os(n,o,i,t);default:if(typeof e=="object"&&e!==null)switch(e.$$typeof){case wp:s=10;break e;case Sp:s=9;break e;case mu:s=11;break e;case yu:s=14;break e;case Xt:s=16,r=null;break e}throw Error(F(130,e==null?e:typeof e,""))}return t=et(s,n,t,o),t.elementType=e,t.type=r,t.lanes=i,t}function bn(e,t,n,r){return e=et(7,e,r,t),e.lanes=n,e}function Os(e,t,n,r){return e=et(22,e,r,t),e.elementType=kp,e.lanes=n,e.stateNode={isHidden:!1},e}function zl(e,t,n){return e=et(6,e,null,t),e.lanes=n,e}function Tl(e,t,n){return t=et(4,e.children!==null?e.children:[],e.key,t),t.lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function P1(e,t,n,r,o){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=dl(0),this.expirationTimes=dl(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=dl(0),this.identifierPrefix=r,this.onRecoverableError=o,this.mutableSourceEagerHydrationData=null}function qu(e,t,n,r,o,i,s,l,a){return e=new P1(e,t,n,l,a),t===1?(t=1,i===!0&&(t|=8)):t=0,i=et(3,null,null,t),e.current=i,i.stateNode=e,i.memoizedState={element:r,isDehydrated:n,cache:null,transitions:null,pendingSuspenseBoundaries:null},Lu(i),e}function I1(e,t,n){var r=3"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(mg)}catch(e){console.error(e)}}mg(),mp.exports=Ke;var D1=mp.exports,Dd=D1;Zl.createRoot=Dd.createRoot,Zl.hydrateRoot=Dd.hydrateRoot;function we(e){if(typeof e=="string"||typeof e=="number")return""+e;let t="";if(Array.isArray(e))for(let n=0,r;n{}};function Ws(){for(var e=0,t=arguments.length,n={},r;e=0&&(r=n.slice(o+1),n=n.slice(0,o)),n&&!t.hasOwnProperty(n))throw new Error("unknown type: "+n);return{type:n,name:r}})}Hi.prototype=Ws.prototype={constructor:Hi,on:function(e,t){var n=this._,r=B1(e+"",n),o,i=-1,s=r.length;if(arguments.length<2){for(;++i0)for(var n=new Array(o),r=0,o,i;r=0&&(t=e.slice(0,n))!=="xmlns"&&(e=e.slice(n+1)),Bd.hasOwnProperty(t)?{space:Bd[t],local:e}:e}function H1(e){return function(){var t=this.ownerDocument,n=this.namespaceURI;return n===Wa&&t.documentElement.namespaceURI===Wa?t.createElement(e):t.createElementNS(n,e)}}function V1(e){return function(){return this.ownerDocument.createElementNS(e.space,e.local)}}function yg(e){var t=Us(e);return(t.local?V1:H1)(t)}function W1(){}function nc(e){return e==null?W1:function(){return this.querySelector(e)}}function U1(e){typeof e!="function"&&(e=nc(e));for(var t=this._groups,n=t.length,r=new Array(n),o=0;o=h&&(h=g+1);!(_=k[h])&&++h=0;)(s=r[o])&&(i&&s.compareDocumentPosition(i)^4&&i.parentNode.insertBefore(s,i),i=s);return this}function mv(e){e||(e=yv);function t(c,f){return c&&f?e(c.__data__,f.__data__):!c-!f}for(var n=this._groups,r=n.length,o=new Array(r),i=0;it?1:e>=t?0:NaN}function xv(){var e=arguments[0];return arguments[0]=this,e.apply(null,arguments),this}function vv(){return Array.from(this)}function wv(){for(var e=this._groups,t=0,n=e.length;t1?this.each((t==null?Tv:typeof t=="function"?Iv:Pv)(e,t,n??"")):xr(this.node(),e)}function xr(e,t){return e.style.getPropertyValue(t)||kg(e).getComputedStyle(e,null).getPropertyValue(t)}function Lv(e){return function(){delete this[e]}}function Av(e,t){return function(){this[e]=t}}function $v(e,t){return function(){var n=t.apply(this,arguments);n==null?delete this[e]:this[e]=n}}function Dv(e,t){return arguments.length>1?this.each((t==null?Lv:typeof t=="function"?$v:Av)(e,t)):this.node()[e]}function _g(e){return e.trim().split(/^|\s+/)}function rc(e){return e.classList||new bg(e)}function bg(e){this._node=e,this._names=_g(e.getAttribute("class")||"")}bg.prototype={add:function(e){var t=this._names.indexOf(e);t<0&&(this._names.push(e),this._node.setAttribute("class",this._names.join(" ")))},remove:function(e){var t=this._names.indexOf(e);t>=0&&(this._names.splice(t,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(e){return this._names.indexOf(e)>=0}};function Cg(e,t){for(var n=rc(e),r=-1,o=t.length;++r=0&&(n=t.slice(r+1),t=t.slice(0,r)),{type:t,name:n}})}function fw(e){return function(){var t=this.__on;if(t){for(var n=0,r=-1,o=t.length,i;n()=>e;function Ua(e,{sourceEvent:t,subject:n,target:r,identifier:o,active:i,x:s,y:l,dx:a,dy:u,dispatch:p}){Object.defineProperties(this,{type:{value:e,enumerable:!0,configurable:!0},sourceEvent:{value:t,enumerable:!0,configurable:!0},subject:{value:n,enumerable:!0,configurable:!0},target:{value:r,enumerable:!0,configurable:!0},identifier:{value:o,enumerable:!0,configurable:!0},active:{value:i,enumerable:!0,configurable:!0},x:{value:s,enumerable:!0,configurable:!0},y:{value:l,enumerable:!0,configurable:!0},dx:{value:a,enumerable:!0,configurable:!0},dy:{value:u,enumerable:!0,configurable:!0},_:{value:p}})}Ua.prototype.on=function(){var e=this._.on.apply(this._,arguments);return e===this._?this:e};function kw(e){return!e.ctrlKey&&!e.button}function _w(){return this.parentNode}function bw(e,t){return t??{x:e.x,y:e.y}}function Cw(){return navigator.maxTouchPoints||"ontouchstart"in this}function Tg(){var e=kw,t=_w,n=bw,r=Cw,o={},i=Ws("start","drag","end"),s=0,l,a,u,p,c=0;function f(w){w.on("mousedown.drag",x).filter(r).on("touchstart.drag",k).on("touchmove.drag",m,Sw).on("touchend.drag touchcancel.drag",g).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function x(w,_){if(!(p||!e.call(this,w,_))){var S=h(this,t.call(this,w,_),w,_,"mouse");S&&(Ue(w.view).on("mousemove.drag",y,Mo).on("mouseup.drag",v,Mo),Mg(w.view),Pl(w),u=!1,l=w.clientX,a=w.clientY,S("start",w))}}function y(w){if(ur(w),!u){var _=w.clientX-l,S=w.clientY-a;u=_*_+S*S>c}o.mouse("drag",w)}function v(w){Ue(w.view).on("mousemove.drag mouseup.drag",null),zg(w.view,u),ur(w),o.mouse("end",w)}function k(w,_){if(e.call(this,w,_)){var S=w.changedTouches,b=t.call(this,w,_),E=S.length,A,D;for(A=0;A>8&15|t>>4&240,t>>4&15|t&240,(t&15)<<4|t&15,1):n===8?mi(t>>24&255,t>>16&255,t>>8&255,(t&255)/255):n===4?mi(t>>12&15|t>>8&240,t>>8&15|t>>4&240,t>>4&15|t&240,((t&15)<<4|t&15)/255):null):(t=jw.exec(e))?new Oe(t[1],t[2],t[3],1):(t=Nw.exec(e))?new Oe(t[1]*255/100,t[2]*255/100,t[3]*255/100,1):(t=Mw.exec(e))?mi(t[1],t[2],t[3],t[4]):(t=zw.exec(e))?mi(t[1]*255/100,t[2]*255/100,t[3]*255/100,t[4]):(t=Tw.exec(e))?Xd(t[1],t[2]/100,t[3]/100,1):(t=Pw.exec(e))?Xd(t[1],t[2]/100,t[3]/100,t[4]):Fd.hasOwnProperty(e)?Wd(Fd[e]):e==="transparent"?new Oe(NaN,NaN,NaN,0):null}function Wd(e){return new Oe(e>>16&255,e>>8&255,e&255,1)}function mi(e,t,n,r){return r<=0&&(e=t=n=NaN),new Oe(e,t,n,r)}function Lw(e){return e instanceof Uo||(e=Pn(e)),e?(e=e.rgb(),new Oe(e.r,e.g,e.b,e.opacity)):new Oe}function Ya(e,t,n,r){return arguments.length===1?Lw(e):new Oe(e,t,n,r??1)}function Oe(e,t,n,r){this.r=+e,this.g=+t,this.b=+n,this.opacity=+r}oc(Oe,Ya,Pg(Uo,{brighter(e){return e=e==null?xs:Math.pow(xs,e),new Oe(this.r*e,this.g*e,this.b*e,this.opacity)},darker(e){return e=e==null?zo:Math.pow(zo,e),new Oe(this.r*e,this.g*e,this.b*e,this.opacity)},rgb(){return this},clamp(){return new Oe(Cn(this.r),Cn(this.g),Cn(this.b),vs(this.opacity))},displayable(){return-.5<=this.r&&this.r<255.5&&-.5<=this.g&&this.g<255.5&&-.5<=this.b&&this.b<255.5&&0<=this.opacity&&this.opacity<=1},hex:Ud,formatHex:Ud,formatHex8:Aw,formatRgb:Yd,toString:Yd}));function Ud(){return`#${kn(this.r)}${kn(this.g)}${kn(this.b)}`}function Aw(){return`#${kn(this.r)}${kn(this.g)}${kn(this.b)}${kn((isNaN(this.opacity)?1:this.opacity)*255)}`}function Yd(){const e=vs(this.opacity);return`${e===1?"rgb(":"rgba("}${Cn(this.r)}, ${Cn(this.g)}, ${Cn(this.b)}${e===1?")":`, ${e})`}`}function vs(e){return isNaN(e)?1:Math.max(0,Math.min(1,e))}function Cn(e){return Math.max(0,Math.min(255,Math.round(e)||0))}function kn(e){return e=Cn(e),(e<16?"0":"")+e.toString(16)}function Xd(e,t,n,r){return r<=0?e=t=n=NaN:n<=0||n>=1?e=t=NaN:t<=0&&(e=NaN),new ut(e,t,n,r)}function Ig(e){if(e instanceof ut)return new ut(e.h,e.s,e.l,e.opacity);if(e instanceof Uo||(e=Pn(e)),!e)return new ut;if(e instanceof ut)return e;e=e.rgb();var t=e.r/255,n=e.g/255,r=e.b/255,o=Math.min(t,n,r),i=Math.max(t,n,r),s=NaN,l=i-o,a=(i+o)/2;return l?(t===i?s=(n-r)/l+(n0&&a<1?0:s,new ut(s,l,a,e.opacity)}function $w(e,t,n,r){return arguments.length===1?Ig(e):new ut(e,t,n,r??1)}function ut(e,t,n,r){this.h=+e,this.s=+t,this.l=+n,this.opacity=+r}oc(ut,$w,Pg(Uo,{brighter(e){return e=e==null?xs:Math.pow(xs,e),new ut(this.h,this.s,this.l*e,this.opacity)},darker(e){return e=e==null?zo:Math.pow(zo,e),new ut(this.h,this.s,this.l*e,this.opacity)},rgb(){var e=this.h%360+(this.h<0)*360,t=isNaN(e)||isNaN(this.s)?0:this.s,n=this.l,r=n+(n<.5?n:1-n)*t,o=2*n-r;return new Oe(Il(e>=240?e-240:e+120,o,r),Il(e,o,r),Il(e<120?e+240:e-120,o,r),this.opacity)},clamp(){return new ut(Qd(this.h),yi(this.s),yi(this.l),vs(this.opacity))},displayable(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1},formatHsl(){const e=vs(this.opacity);return`${e===1?"hsl(":"hsla("}${Qd(this.h)}, ${yi(this.s)*100}%, ${yi(this.l)*100}%${e===1?")":`, ${e})`}`}}));function Qd(e){return e=(e||0)%360,e<0?e+360:e}function yi(e){return Math.max(0,Math.min(1,e||0))}function Il(e,t,n){return(e<60?t+(n-t)*e/60:e<180?n:e<240?t+(n-t)*(240-e)/60:t)*255}const ic=e=>()=>e;function Dw(e,t){return function(n){return e+n*t}}function Ow(e,t,n){return e=Math.pow(e,n),t=Math.pow(t,n)-e,n=1/n,function(r){return Math.pow(e+r*t,n)}}function Bw(e){return(e=+e)==1?Rg:function(t,n){return n-t?Ow(t,n,e):ic(isNaN(t)?n:t)}}function Rg(e,t){var n=t-e;return n?Dw(e,n):ic(isNaN(e)?t:e)}const ws=function e(t){var n=Bw(t);function r(o,i){var s=n((o=Ya(o)).r,(i=Ya(i)).r),l=n(o.g,i.g),a=n(o.b,i.b),u=Rg(o.opacity,i.opacity);return function(p){return o.r=s(p),o.g=l(p),o.b=a(p),o.opacity=u(p),o+""}}return r.gamma=e,r}(1);function Fw(e,t){t||(t=[]);var n=e?Math.min(t.length,e.length):0,r=t.slice(),o;return function(i){for(o=0;on&&(i=t.slice(n,i),l[s]?l[s]+=i:l[++s]=i),(r=r[0])===(o=o[0])?l[s]?l[s]+=o:l[++s]=o:(l[++s]=null,a.push({i:s,x:St(r,o)})),n=Rl.lastIndex;return n180?p+=360:p-u>180&&(u+=360),f.push({i:c.push(o(c)+"rotate(",null,r)-2,x:St(u,p)})):p&&c.push(o(c)+"rotate("+p+r)}function l(u,p,c,f){u!==p?f.push({i:c.push(o(c)+"skewX(",null,r)-2,x:St(u,p)}):p&&c.push(o(c)+"skewX("+p+r)}function a(u,p,c,f,x,y){if(u!==c||p!==f){var v=x.push(o(x)+"scale(",null,",",null,")");y.push({i:v-4,x:St(u,c)},{i:v-2,x:St(p,f)})}else(c!==1||f!==1)&&x.push(o(x)+"scale("+c+","+f+")")}return function(u,p){var c=[],f=[];return u=e(u),p=e(p),i(u.translateX,u.translateY,p.translateX,p.translateY,c,f),s(u.rotate,p.rotate,c,f),l(u.skewX,p.skewX,c,f),a(u.scaleX,u.scaleY,p.scaleX,p.scaleY,c,f),u=p=null,function(x){for(var y=-1,v=f.length,k;++y=0&&e._call.call(void 0,t),e=e._next;--vr}function Zd(){In=(ks=Po.now())+Ys,vr=qr=0;try{n2()}finally{vr=0,o2(),In=0}}function r2(){var e=Po.now(),t=e-ks;t>Dg&&(Ys-=t,ks=e)}function o2(){for(var e,t=Ss,n,r=1/0;t;)t._call?(r>t._time&&(r=t._time),e=t,t=t._next):(n=t._next,t._next=null,t=e?e._next=n:Ss=n);Jr=e,Ga(r)}function Ga(e){if(!vr){qr&&(qr=clearTimeout(qr));var t=e-In;t>24?(e<1/0&&(qr=setTimeout(Zd,e-Po.now()-Ys)),Hr&&(Hr=clearInterval(Hr))):(Hr||(ks=Po.now(),Hr=setInterval(r2,Dg)),vr=1,Og(Zd))}}function qd(e,t,n){var r=new _s;return t=t==null?0:+t,r.restart(o=>{r.stop(),e(o+t)},t,n),r}var i2=Ws("start","end","cancel","interrupt"),s2=[],Fg=0,Jd=1,Ka=2,Wi=3,ef=4,Za=5,Ui=6;function Xs(e,t,n,r,o,i){var s=e.__transition;if(!s)e.__transition={};else if(n in s)return;l2(e,n,{name:t,index:r,group:o,on:i2,tween:s2,time:i.time,delay:i.delay,duration:i.duration,ease:i.ease,timer:null,state:Fg})}function lc(e,t){var n=gt(e,t);if(n.state>Fg)throw new Error("too late; already scheduled");return n}function jt(e,t){var n=gt(e,t);if(n.state>Wi)throw new Error("too late; already running");return n}function gt(e,t){var n=e.__transition;if(!n||!(n=n[t]))throw new Error("transition not found");return n}function l2(e,t,n){var r=e.__transition,o;r[t]=n,n.timer=Bg(i,0,n.time);function i(u){n.state=Jd,n.timer.restart(s,n.delay,n.time),n.delay<=u&&s(u-n.delay)}function s(u){var p,c,f,x;if(n.state!==Jd)return a();for(p in r)if(x=r[p],x.name===n.name){if(x.state===Wi)return qd(s);x.state===ef?(x.state=Ui,x.timer.stop(),x.on.call("interrupt",e,e.__data__,x.index,x.group),delete r[p]):+pKa&&r.state=0&&(t=t.slice(0,n)),!t||t==="start"})}function $2(e,t,n){var r,o,i=A2(t)?lc:jt;return function(){var s=i(this,e),l=s.on;l!==r&&(o=(r=l).copy()).on(t,n),s.on=o}}function D2(e,t){var n=this._id;return arguments.length<2?gt(this.node(),n).on.on(e):this.each($2(n,e,t))}function O2(e){return function(){var t=this.parentNode;for(var n in this.__transition)if(+n!==e)return;t&&t.removeChild(this)}}function B2(){return this.on("end.remove",O2(this._id))}function F2(e){var t=this._name,n=this._id;typeof e!="function"&&(e=nc(e));for(var r=this._groups,o=r.length,i=new Array(o),s=0;s()=>e;function fS(e,{sourceEvent:t,target:n,transform:r,dispatch:o}){Object.defineProperties(this,{type:{value:e,enumerable:!0,configurable:!0},sourceEvent:{value:t,enumerable:!0,configurable:!0},target:{value:n,enumerable:!0,configurable:!0},transform:{value:r,enumerable:!0,configurable:!0},_:{value:o}})}function Rt(e,t,n){this.k=e,this.x=t,this.y=n}Rt.prototype={constructor:Rt,scale:function(e){return e===1?this:new Rt(this.k*e,this.x,this.y)},translate:function(e,t){return e===0&t===0?this:new Rt(this.k,this.x+this.k*e,this.y+this.k*t)},apply:function(e){return[e[0]*this.k+this.x,e[1]*this.k+this.y]},applyX:function(e){return e*this.k+this.x},applyY:function(e){return e*this.k+this.y},invert:function(e){return[(e[0]-this.x)/this.k,(e[1]-this.y)/this.k]},invertX:function(e){return(e-this.x)/this.k},invertY:function(e){return(e-this.y)/this.k},rescaleX:function(e){return e.copy().domain(e.range().map(this.invertX,this).map(e.invert,e))},rescaleY:function(e){return e.copy().domain(e.range().map(this.invertY,this).map(e.invert,e))},toString:function(){return"translate("+this.x+","+this.y+") scale("+this.k+")"}};var Qs=new Rt(1,0,0);Ug.prototype=Rt.prototype;function Ug(e){for(;!e.__zoom;)if(!(e=e.parentNode))return Qs;return e.__zoom}function Ll(e){e.stopImmediatePropagation()}function Vr(e){e.preventDefault(),e.stopImmediatePropagation()}function pS(e){return(!e.ctrlKey||e.type==="wheel")&&!e.button}function hS(){var e=this;return e instanceof SVGElement?(e=e.ownerSVGElement||e,e.hasAttribute("viewBox")?(e=e.viewBox.baseVal,[[e.x,e.y],[e.x+e.width,e.y+e.height]]):[[0,0],[e.width.baseVal.value,e.height.baseVal.value]]):[[0,0],[e.clientWidth,e.clientHeight]]}function tf(){return this.__zoom||Qs}function gS(e){return-e.deltaY*(e.deltaMode===1?.05:e.deltaMode?1:.002)*(e.ctrlKey?10:1)}function mS(){return navigator.maxTouchPoints||"ontouchstart"in this}function yS(e,t,n){var r=e.invertX(t[0][0])-n[0][0],o=e.invertX(t[1][0])-n[1][0],i=e.invertY(t[0][1])-n[0][1],s=e.invertY(t[1][1])-n[1][1];return e.translate(o>r?(r+o)/2:Math.min(0,r)||Math.max(0,o),s>i?(i+s)/2:Math.min(0,i)||Math.max(0,s))}function Yg(){var e=pS,t=hS,n=yS,r=gS,o=mS,i=[0,1/0],s=[[-1/0,-1/0],[1/0,1/0]],l=250,a=Vi,u=Ws("start","zoom","end"),p,c,f,x=500,y=150,v=0,k=10;function m(C){C.property("__zoom",tf).on("wheel.zoom",E,{passive:!1}).on("mousedown.zoom",A).on("dblclick.zoom",D).filter(o).on("touchstart.zoom",P).on("touchmove.zoom",I).on("touchend.zoom touchcancel.zoom",T).style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}m.transform=function(C,L,z,R){var j=C.selection?C.selection():C;j.property("__zoom",tf),C!==j?_(C,L,z,R):j.interrupt().each(function(){S(this,arguments).event(R).start().zoom(null,typeof L=="function"?L.apply(this,arguments):L).end()})},m.scaleBy=function(C,L,z,R){m.scaleTo(C,function(){var j=this.__zoom.k,N=typeof L=="function"?L.apply(this,arguments):L;return j*N},z,R)},m.scaleTo=function(C,L,z,R){m.transform(C,function(){var j=t.apply(this,arguments),N=this.__zoom,$=z==null?w(j):typeof z=="function"?z.apply(this,arguments):z,O=N.invert($),B=typeof L=="function"?L.apply(this,arguments):L;return n(h(g(N,B),$,O),j,s)},z,R)},m.translateBy=function(C,L,z,R){m.transform(C,function(){return n(this.__zoom.translate(typeof L=="function"?L.apply(this,arguments):L,typeof z=="function"?z.apply(this,arguments):z),t.apply(this,arguments),s)},null,R)},m.translateTo=function(C,L,z,R,j){m.transform(C,function(){var N=t.apply(this,arguments),$=this.__zoom,O=R==null?w(N):typeof R=="function"?R.apply(this,arguments):R;return n(Qs.translate(O[0],O[1]).scale($.k).translate(typeof L=="function"?-L.apply(this,arguments):-L,typeof z=="function"?-z.apply(this,arguments):-z),N,s)},R,j)};function g(C,L){return L=Math.max(i[0],Math.min(i[1],L)),L===C.k?C:new Rt(L,C.x,C.y)}function h(C,L,z){var R=L[0]-z[0]*C.k,j=L[1]-z[1]*C.k;return R===C.x&&j===C.y?C:new Rt(C.k,R,j)}function w(C){return[(+C[0][0]+ +C[1][0])/2,(+C[0][1]+ +C[1][1])/2]}function _(C,L,z,R){C.on("start.zoom",function(){S(this,arguments).event(R).start()}).on("interrupt.zoom end.zoom",function(){S(this,arguments).event(R).end()}).tween("zoom",function(){var j=this,N=arguments,$=S(j,N).event(R),O=t.apply(j,N),B=z==null?w(O):typeof z=="function"?z.apply(j,N):z,W=Math.max(O[1][0]-O[0][0],O[1][1]-O[0][1]),V=j.__zoom,Y=typeof L=="function"?L.apply(j,N):L,X=a(V.invert(B).concat(W/V.k),Y.invert(B).concat(W/Y.k));return function(Q){if(Q===1)Q=Y;else{var H=X(Q),K=W/H[2];Q=new Rt(K,B[0]-H[0]*K,B[1]-H[1]*K)}$.zoom(null,Q)}})}function S(C,L,z){return!z&&C.__zooming||new b(C,L)}function b(C,L){this.that=C,this.args=L,this.active=0,this.sourceEvent=null,this.extent=t.apply(C,L),this.taps=0}b.prototype={event:function(C){return C&&(this.sourceEvent=C),this},start:function(){return++this.active===1&&(this.that.__zooming=this,this.emit("start")),this},zoom:function(C,L){return this.mouse&&C!=="mouse"&&(this.mouse[1]=L.invert(this.mouse[0])),this.touch0&&C!=="touch"&&(this.touch0[1]=L.invert(this.touch0[0])),this.touch1&&C!=="touch"&&(this.touch1[1]=L.invert(this.touch1[0])),this.that.__zoom=L,this.emit("zoom"),this},end:function(){return--this.active===0&&(delete this.that.__zooming,this.emit("end")),this},emit:function(C){var L=Ue(this.that).datum();u.call(C,this.that,new fS(C,{sourceEvent:this.sourceEvent,target:m,transform:this.that.__zoom,dispatch:u}),L)}};function E(C,...L){if(!e.apply(this,arguments))return;var z=S(this,L).event(C),R=this.__zoom,j=Math.max(i[0],Math.min(i[1],R.k*Math.pow(2,r.apply(this,arguments)))),N=lt(C);if(z.wheel)(z.mouse[0][0]!==N[0]||z.mouse[0][1]!==N[1])&&(z.mouse[1]=R.invert(z.mouse[0]=N)),clearTimeout(z.wheel);else{if(R.k===j)return;z.mouse=[N,R.invert(N)],Yi(this),z.start()}Vr(C),z.wheel=setTimeout($,y),z.zoom("mouse",n(h(g(R,j),z.mouse[0],z.mouse[1]),z.extent,s));function $(){z.wheel=null,z.end()}}function A(C,...L){if(f||!e.apply(this,arguments))return;var z=C.currentTarget,R=S(this,L,!0).event(C),j=Ue(C.view).on("mousemove.zoom",B,!0).on("mouseup.zoom",W,!0),N=lt(C,z),$=C.clientX,O=C.clientY;Mg(C.view),Ll(C),R.mouse=[N,this.__zoom.invert(N)],Yi(this),R.start();function B(V){if(Vr(V),!R.moved){var Y=V.clientX-$,X=V.clientY-O;R.moved=Y*Y+X*X>v}R.event(V).zoom("mouse",n(h(R.that.__zoom,R.mouse[0]=lt(V,z),R.mouse[1]),R.extent,s))}function W(V){j.on("mousemove.zoom mouseup.zoom",null),zg(V.view,R.moved),Vr(V),R.event(V).end()}}function D(C,...L){if(e.apply(this,arguments)){var z=this.__zoom,R=lt(C.changedTouches?C.changedTouches[0]:C,this),j=z.invert(R),N=z.k*(C.shiftKey?.5:2),$=n(h(g(z,N),R,j),t.apply(this,L),s);Vr(C),l>0?Ue(this).transition().duration(l).call(_,$,R,C):Ue(this).call(m.transform,$,R,C)}}function P(C,...L){if(e.apply(this,arguments)){var z=C.touches,R=z.length,j=S(this,L,C.changedTouches.length===R).event(C),N,$,O,B;for(Ll(C),$=0;$"[React Flow]: Seems like you have not used zustand provider as an ancestor. Help: https://reactflow.dev/error#001",error002:()=>"It looks like you've created a new nodeTypes or edgeTypes object. If this wasn't on purpose please define the nodeTypes/edgeTypes outside of the component or memoize them.",error003:e=>`Node type "${e}" not found. Using fallback type "default".`,error004:()=>"The React Flow parent container needs a width and a height to render the graph.",error005:()=>"Only child nodes can use a parent extent.",error006:()=>"Can't create edge. An edge needs a source and a target.",error007:e=>`The old edge with id=${e} does not exist.`,error009:e=>`Marker type "${e}" doesn't exist.`,error008:(e,{id:t,sourceHandle:n,targetHandle:r})=>`Couldn't create edge for ${e} handle id: "${e==="source"?n:r}", edge id: ${t}.`,error010:()=>"Handle: No node id found. Make sure to only use a Handle inside a custom Node.",error011:e=>`Edge type "${e}" not found. Using fallback type "default".`,error012:e=>`Node with id "${e}" does not exist, it may have been removed. This can happen when a node is deleted before the "onNodeClick" handler is called.`,error013:(e="react")=>`It seems that you haven't loaded the styles. Please import '@xyflow/${e}/dist/style.css' or base.css to make sure everything is working properly.`,error014:()=>"useNodeConnections: No node ID found. Call useNodeConnections inside a custom Node or provide a node ID.",error015:()=>"It seems that you are trying to drag a node that is not initialized. Please use onNodesChange as explained in the docs."},Io=[[Number.NEGATIVE_INFINITY,Number.NEGATIVE_INFINITY],[Number.POSITIVE_INFINITY,Number.POSITIVE_INFINITY]],Xg=["Enter"," ","Escape"],Qg={"node.a11yDescription.default":"Press enter or space to select a node. Press delete to remove it and escape to cancel.","node.a11yDescription.keyboardDisabled":"Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.","node.a11yDescription.ariaLiveMessage":({direction:e,x:t,y:n})=>`Moved selected node ${e}. New position, x: ${t}, y: ${n}`,"edge.a11yDescription.default":"Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.","controls.ariaLabel":"Control Panel","controls.zoomIn.ariaLabel":"Zoom In","controls.zoomOut.ariaLabel":"Zoom Out","controls.fitView.ariaLabel":"Fit View","controls.interactive.ariaLabel":"Toggle Interactivity","minimap.ariaLabel":"Mini Map","handle.ariaLabel":"Handle"};var wr;(function(e){e.Strict="strict",e.Loose="loose"})(wr||(wr={}));var En;(function(e){e.Free="free",e.Vertical="vertical",e.Horizontal="horizontal"})(En||(En={}));var Ro;(function(e){e.Partial="partial",e.Full="full"})(Ro||(Ro={}));const Gg={inProgress:!1,isValid:null,from:null,fromHandle:null,fromPosition:null,fromNode:null,to:null,toHandle:null,toPosition:null,toNode:null,pointer:null};var Zt;(function(e){e.Bezier="default",e.Straight="straight",e.Step="step",e.SmoothStep="smoothstep",e.SimpleBezier="simplebezier"})(Zt||(Zt={}));var bs;(function(e){e.Arrow="arrow",e.ArrowClosed="arrowclosed"})(bs||(bs={}));var q;(function(e){e.Left="left",e.Top="top",e.Right="right",e.Bottom="bottom"})(q||(q={}));const nf={[q.Left]:q.Right,[q.Right]:q.Left,[q.Top]:q.Bottom,[q.Bottom]:q.Top};function Kg(e){return e===null?null:e?"valid":"invalid"}const Zg=e=>"id"in e&&"source"in e&&"target"in e,xS=e=>"id"in e&&"position"in e&&!("source"in e)&&!("target"in e),uc=e=>"id"in e&&"internals"in e&&!("source"in e)&&!("target"in e),Yo=(e,t=[0,0])=>{const{width:n,height:r}=Ht(e),o=e.origin??t,i=n*o[0],s=r*o[1];return{x:e.position.x-i,y:e.position.y-s}},vS=(e,t={nodeOrigin:[0,0]})=>{if(e.length===0)return{x:0,y:0,width:0,height:0};const n=e.reduce((r,o)=>{const i=typeof o=="string";let s=!t.nodeLookup&&!i?o:void 0;t.nodeLookup&&(s=i?t.nodeLookup.get(o):uc(o)?o:t.nodeLookup.get(o.id));const l=s?Cs(s,t.nodeOrigin):{x:0,y:0,x2:0,y2:0};return Gs(r,l)},{x:1/0,y:1/0,x2:-1/0,y2:-1/0});return Ks(n)},Xo=(e,t={})=>{let n={x:1/0,y:1/0,x2:-1/0,y2:-1/0},r=!1;return e.forEach(o=>{(t.filter===void 0||t.filter(o))&&(n=Gs(n,Cs(o)),r=!0)}),r?Ks(n):{x:0,y:0,width:0,height:0}},cc=(e,t,[n,r,o]=[0,0,1],i=!1,s=!1)=>{const l={...Go(t,[n,r,o]),width:t.width/o,height:t.height/o},a=[];for(const u of e.values()){const{measured:p,selectable:c=!0,hidden:f=!1}=u;if(s&&!c||f)continue;const x=p.width??u.width??u.initialWidth??null,y=p.height??u.height??u.initialHeight??null,v=Lo(l,kr(u)),k=(x??0)*(y??0),m=i&&v>0;(!u.internals.handleBounds||m||v>=k||u.dragging)&&a.push(u)}return a},wS=(e,t)=>{const n=new Set;return e.forEach(r=>{n.add(r.id)}),t.filter(r=>n.has(r.source)||n.has(r.target))};function SS(e,t){const n=new Map,r=t!=null&&t.nodes?new Set(t.nodes.map(o=>o.id)):null;return e.forEach(o=>{o.measured.width&&o.measured.height&&((t==null?void 0:t.includeHiddenNodes)||!o.hidden)&&(!r||r.has(o.id))&&n.set(o.id,o)}),n}async function kS({nodes:e,width:t,height:n,panZoom:r,minZoom:o,maxZoom:i},s){if(e.size===0)return Promise.resolve(!0);const l=SS(e,s),a=Xo(l),u=dc(a,t,n,(s==null?void 0:s.minZoom)??o,(s==null?void 0:s.maxZoom)??i,(s==null?void 0:s.padding)??.1);return await r.setViewport(u,{duration:s==null?void 0:s.duration,ease:s==null?void 0:s.ease,interpolate:s==null?void 0:s.interpolate}),Promise.resolve(!0)}function qg({nodeId:e,nextPosition:t,nodeLookup:n,nodeOrigin:r=[0,0],nodeExtent:o,onError:i}){const s=n.get(e),l=s.parentId?n.get(s.parentId):void 0,{x:a,y:u}=l?l.internals.positionAbsolute:{x:0,y:0},p=s.origin??r;let c=s.extent||o;if(s.extent==="parent"&&!s.expandParent)if(!l)i==null||i("005",Et.error005());else{const x=l.measured.width,y=l.measured.height;x&&y&&(c=[[a,u],[a+x,u+y]])}else l&&_r(s.extent)&&(c=[[s.extent[0][0]+a,s.extent[0][1]+u],[s.extent[1][0]+a,s.extent[1][1]+u]]);const f=_r(c)?Rn(t,c,s.measured):t;return(s.measured.width===void 0||s.measured.height===void 0)&&(i==null||i("015",Et.error015())),{position:{x:f.x-a+(s.measured.width??0)*p[0],y:f.y-u+(s.measured.height??0)*p[1]},positionAbsolute:f}}async function _S({nodesToRemove:e=[],edgesToRemove:t=[],nodes:n,edges:r,onBeforeDelete:o}){const i=new Set(e.map(f=>f.id)),s=[];for(const f of n){if(f.deletable===!1)continue;const x=i.has(f.id),y=!x&&f.parentId&&s.find(v=>v.id===f.parentId);(x||y)&&s.push(f)}const l=new Set(t.map(f=>f.id)),a=r.filter(f=>f.deletable!==!1),p=wS(s,a);for(const f of a)l.has(f.id)&&!p.find(y=>y.id===f.id)&&p.push(f);if(!o)return{edges:p,nodes:s};const c=await o({nodes:s,edges:p});return typeof c=="boolean"?c?{edges:p,nodes:s}:{edges:[],nodes:[]}:c}const Sr=(e,t=0,n=1)=>Math.min(Math.max(e,t),n),Rn=(e={x:0,y:0},t,n)=>({x:Sr(e.x,t[0][0],t[1][0]-((n==null?void 0:n.width)??0)),y:Sr(e.y,t[0][1],t[1][1]-((n==null?void 0:n.height)??0))});function Jg(e,t,n){const{width:r,height:o}=Ht(n),{x:i,y:s}=n.internals.positionAbsolute;return Rn(e,[[i,s],[i+r,s+o]],t)}const rf=(e,t,n)=>en?-Sr(Math.abs(e-n),1,t)/t:0,em=(e,t,n=15,r=40)=>{const o=rf(e.x,r,t.width-r)*n,i=rf(e.y,r,t.height-r)*n;return[o,i]},Gs=(e,t)=>({x:Math.min(e.x,t.x),y:Math.min(e.y,t.y),x2:Math.max(e.x2,t.x2),y2:Math.max(e.y2,t.y2)}),qa=({x:e,y:t,width:n,height:r})=>({x:e,y:t,x2:e+n,y2:t+r}),Ks=({x:e,y:t,x2:n,y2:r})=>({x:e,y:t,width:n-e,height:r-t}),kr=(e,t=[0,0])=>{var o,i;const{x:n,y:r}=uc(e)?e.internals.positionAbsolute:Yo(e,t);return{x:n,y:r,width:((o=e.measured)==null?void 0:o.width)??e.width??e.initialWidth??0,height:((i=e.measured)==null?void 0:i.height)??e.height??e.initialHeight??0}},Cs=(e,t=[0,0])=>{var o,i;const{x:n,y:r}=uc(e)?e.internals.positionAbsolute:Yo(e,t);return{x:n,y:r,x2:n+(((o=e.measured)==null?void 0:o.width)??e.width??e.initialWidth??0),y2:r+(((i=e.measured)==null?void 0:i.height)??e.height??e.initialHeight??0)}},tm=(e,t)=>Ks(Gs(qa(e),qa(t))),Lo=(e,t)=>{const n=Math.max(0,Math.min(e.x+e.width,t.x+t.width)-Math.max(e.x,t.x)),r=Math.max(0,Math.min(e.y+e.height,t.y+t.height)-Math.max(e.y,t.y));return Math.ceil(n*r)},of=e=>ct(e.width)&&ct(e.height)&&ct(e.x)&&ct(e.y),ct=e=>!isNaN(e)&&isFinite(e),bS=(e,t)=>{},Qo=(e,t=[1,1])=>({x:t[0]*Math.round(e.x/t[0]),y:t[1]*Math.round(e.y/t[1])}),Go=({x:e,y:t},[n,r,o],i=!1,s=[1,1])=>{const l={x:(e-n)/o,y:(t-r)/o};return i?Qo(l,s):l},Es=({x:e,y:t},[n,r,o])=>({x:e*o+n,y:t*o+r});function Fn(e,t){if(typeof e=="number")return Math.floor((t-t/(1+e))*.5);if(typeof e=="string"&&e.endsWith("px")){const n=parseFloat(e);if(!Number.isNaN(n))return Math.floor(n)}if(typeof e=="string"&&e.endsWith("%")){const n=parseFloat(e);if(!Number.isNaN(n))return Math.floor(t*n*.01)}return console.error(`[React Flow] The padding value "${e}" is invalid. Please provide a number or a string with a valid unit (px or %).`),0}function CS(e,t,n){if(typeof e=="string"||typeof e=="number"){const r=Fn(e,n),o=Fn(e,t);return{top:r,right:o,bottom:r,left:o,x:o*2,y:r*2}}if(typeof e=="object"){const r=Fn(e.top??e.y??0,n),o=Fn(e.bottom??e.y??0,n),i=Fn(e.left??e.x??0,t),s=Fn(e.right??e.x??0,t);return{top:r,right:s,bottom:o,left:i,x:i+s,y:r+o}}return{top:0,right:0,bottom:0,left:0,x:0,y:0}}function ES(e,t,n,r,o,i){const{x:s,y:l}=Es(e,[t,n,r]),{x:a,y:u}=Es({x:e.x+e.width,y:e.y+e.height},[t,n,r]),p=o-a,c=i-u;return{left:Math.floor(s),top:Math.floor(l),right:Math.floor(p),bottom:Math.floor(c)}}const dc=(e,t,n,r,o,i)=>{const s=CS(i,t,n),l=(t-s.x)/e.width,a=(n-s.y)/e.height,u=Math.min(l,a),p=Sr(u,r,o),c=e.x+e.width/2,f=e.y+e.height/2,x=t/2-c*p,y=n/2-f*p,v=ES(e,x,y,p,t,n),k={left:Math.min(v.left-s.left,0),top:Math.min(v.top-s.top,0),right:Math.min(v.right-s.right,0),bottom:Math.min(v.bottom-s.bottom,0)};return{x:x-k.left+k.right,y:y-k.top+k.bottom,zoom:p}},Ao=()=>{var e;return typeof navigator<"u"&&((e=navigator==null?void 0:navigator.userAgent)==null?void 0:e.indexOf("Mac"))>=0};function _r(e){return e!=null&&e!=="parent"}function Ht(e){var t,n;return{width:((t=e.measured)==null?void 0:t.width)??e.width??e.initialWidth??0,height:((n=e.measured)==null?void 0:n.height)??e.height??e.initialHeight??0}}function nm(e){var t,n;return(((t=e.measured)==null?void 0:t.width)??e.width??e.initialWidth)!==void 0&&(((n=e.measured)==null?void 0:n.height)??e.height??e.initialHeight)!==void 0}function rm(e,t={width:0,height:0},n,r,o){const i={...e},s=r.get(n);if(s){const l=s.origin||o;i.x+=s.internals.positionAbsolute.x-(t.width??0)*l[0],i.y+=s.internals.positionAbsolute.y-(t.height??0)*l[1]}return i}function sf(e,t){if(e.size!==t.size)return!1;for(const n of e)if(!t.has(n))return!1;return!0}function jS(){let e,t;return{promise:new Promise((r,o)=>{e=r,t=o}),resolve:e,reject:t}}function NS(e){return{...Qg,...e||{}}}function co(e,{snapGrid:t=[0,0],snapToGrid:n=!1,transform:r,containerBounds:o}){const{x:i,y:s}=dt(e),l=Go({x:i-((o==null?void 0:o.left)??0),y:s-((o==null?void 0:o.top)??0)},r),{x:a,y:u}=n?Qo(l,t):l;return{xSnapped:a,ySnapped:u,...l}}const fc=e=>({width:e.offsetWidth,height:e.offsetHeight}),om=e=>{var t;return((t=e==null?void 0:e.getRootNode)==null?void 0:t.call(e))||(window==null?void 0:window.document)},MS=["INPUT","SELECT","TEXTAREA"];function im(e){var r,o;const t=((o=(r=e.composedPath)==null?void 0:r.call(e))==null?void 0:o[0])||e.target;return(t==null?void 0:t.nodeType)!==1?!1:MS.includes(t.nodeName)||t.hasAttribute("contenteditable")||!!t.closest(".nokey")}const sm=e=>"clientX"in e,dt=(e,t)=>{var i,s;const n=sm(e),r=n?e.clientX:(i=e.touches)==null?void 0:i[0].clientX,o=n?e.clientY:(s=e.touches)==null?void 0:s[0].clientY;return{x:r-((t==null?void 0:t.left)??0),y:o-((t==null?void 0:t.top)??0)}},lf=(e,t,n,r,o)=>{const i=t.querySelectorAll(`.${e}`);return!i||!i.length?null:Array.from(i).map(s=>{const l=s.getBoundingClientRect();return{id:s.getAttribute("data-handleid"),type:e,nodeId:o,position:s.getAttribute("data-handlepos"),x:(l.left-n.left)/r,y:(l.top-n.top)/r,...fc(s)}})};function lm({sourceX:e,sourceY:t,targetX:n,targetY:r,sourceControlX:o,sourceControlY:i,targetControlX:s,targetControlY:l}){const a=e*.125+o*.375+s*.375+n*.125,u=t*.125+i*.375+l*.375+r*.125,p=Math.abs(a-e),c=Math.abs(u-t);return[a,u,p,c]}function wi(e,t){return e>=0?.5*e:t*25*Math.sqrt(-e)}function af({pos:e,x1:t,y1:n,x2:r,y2:o,c:i}){switch(e){case q.Left:return[t-wi(t-r,i),n];case q.Right:return[t+wi(r-t,i),n];case q.Top:return[t,n-wi(n-o,i)];case q.Bottom:return[t,n+wi(o-n,i)]}}function am({sourceX:e,sourceY:t,sourcePosition:n=q.Bottom,targetX:r,targetY:o,targetPosition:i=q.Top,curvature:s=.25}){const[l,a]=af({pos:n,x1:e,y1:t,x2:r,y2:o,c:s}),[u,p]=af({pos:i,x1:r,y1:o,x2:e,y2:t,c:s}),[c,f,x,y]=lm({sourceX:e,sourceY:t,targetX:r,targetY:o,sourceControlX:l,sourceControlY:a,targetControlX:u,targetControlY:p});return[`M${e},${t} C${l},${a} ${u},${p} ${r},${o}`,c,f,x,y]}function um({sourceX:e,sourceY:t,targetX:n,targetY:r}){const o=Math.abs(n-e)/2,i=n0}const PS=({source:e,sourceHandle:t,target:n,targetHandle:r})=>`xy-edge__${e}${t||""}-${n}${r||""}`,IS=(e,t)=>t.some(n=>n.source===e.source&&n.target===e.target&&(n.sourceHandle===e.sourceHandle||!n.sourceHandle&&!e.sourceHandle)&&(n.targetHandle===e.targetHandle||!n.targetHandle&&!e.targetHandle)),RS=(e,t,n={})=>{if(!e.source||!e.target)return t;const r=n.getEdgeId||PS;let o;return Zg(e)?o={...e}:o={...e,id:r(e)},IS(o,t)?t:(o.sourceHandle===null&&delete o.sourceHandle,o.targetHandle===null&&delete o.targetHandle,t.concat(o))};function cm({sourceX:e,sourceY:t,targetX:n,targetY:r}){const[o,i,s,l]=um({sourceX:e,sourceY:t,targetX:n,targetY:r});return[`M ${e},${t}L ${n},${r}`,o,i,s,l]}const uf={[q.Left]:{x:-1,y:0},[q.Right]:{x:1,y:0},[q.Top]:{x:0,y:-1},[q.Bottom]:{x:0,y:1}},LS=({source:e,sourcePosition:t=q.Bottom,target:n})=>t===q.Left||t===q.Right?e.xMath.sqrt(Math.pow(t.x-e.x,2)+Math.pow(t.y-e.y,2));function AS({source:e,sourcePosition:t=q.Bottom,target:n,targetPosition:r=q.Top,center:o,offset:i,stepPosition:s}){const l=uf[t],a=uf[r],u={x:e.x+l.x*i,y:e.y+l.y*i},p={x:n.x+a.x*i,y:n.y+a.y*i},c=LS({source:u,sourcePosition:t,target:p}),f=c.x!==0?"x":"y",x=c[f];let y=[],v,k;const m={x:0,y:0},g={x:0,y:0},[,,h,w]=um({sourceX:e.x,sourceY:e.y,targetX:n.x,targetY:n.y});if(l[f]*a[f]===-1){f==="x"?(v=o.x??u.x+(p.x-u.x)*s,k=o.y??(u.y+p.y)/2):(v=o.x??(u.x+p.x)/2,k=o.y??u.y+(p.y-u.y)*s);const S=[{x:v,y:u.y},{x:v,y:p.y}],b=[{x:u.x,y:k},{x:p.x,y:k}];l[f]===x?y=f==="x"?S:b:y=f==="x"?b:S}else{const S=[{x:u.x,y:p.y}],b=[{x:p.x,y:u.y}];if(f==="x"?y=l.x===x?b:S:y=l.y===x?S:b,t===r){const I=Math.abs(e[f]-n[f]);if(I<=i){const T=Math.min(i-1,i-I);l[f]===x?m[f]=(u[f]>e[f]?-1:1)*T:g[f]=(p[f]>n[f]?-1:1)*T}}if(t!==r){const I=f==="x"?"y":"x",T=l[f]===a[I],C=u[I]>p[I],L=u[I]=P?(v=(E.x+A.x)/2,k=y[0].y):(v=y[0].x,k=(E.y+A.y)/2)}return[[e,{x:u.x+m.x,y:u.y+m.y},...y,{x:p.x+g.x,y:p.y+g.y},n],v,k,h,w]}function $S(e,t,n,r){const o=Math.min(cf(e,t)/2,cf(t,n)/2,r),{x:i,y:s}=t;if(e.x===i&&i===n.x||e.y===s&&s===n.y)return`L${i} ${s}`;if(e.y===s){const u=e.x{let w="";return h>0&&hn.id===t):e[0])||null}function eu(e,t){return e?typeof e=="string"?e:`${t?`${t}__`:""}${Object.keys(e).sort().map(r=>`${r}=${e[r]}`).join("&")}`:""}function OS(e,{id:t,defaultColor:n,defaultMarkerStart:r,defaultMarkerEnd:o}){const i=new Set;return e.reduce((s,l)=>([l.markerStart||r,l.markerEnd||o].forEach(a=>{if(a&&typeof a=="object"){const u=eu(a,t);i.has(u)||(s.push({id:u,color:a.color||n,...a}),i.add(u))}}),s),[]).sort((s,l)=>s.id.localeCompare(l.id))}const dm=1e3,BS=10,pc={nodeOrigin:[0,0],nodeExtent:Io,elevateNodesOnSelect:!0,zIndexMode:"basic",defaults:{}},FS={...pc,checkEquality:!0};function hc(e,t){const n={...e};for(const r in t)t[r]!==void 0&&(n[r]=t[r]);return n}function HS(e,t,n){const r=hc(pc,n);for(const o of e.values())if(o.parentId)mc(o,e,t,r);else{const i=Yo(o,r.nodeOrigin),s=_r(o.extent)?o.extent:r.nodeExtent,l=Rn(i,s,Ht(o));o.internals.positionAbsolute=l}}function VS(e,t){if(!e.handles)return e.measured?t==null?void 0:t.internals.handleBounds:void 0;const n=[],r=[];for(const o of e.handles){const i={id:o.id,width:o.width??1,height:o.height??1,nodeId:e.id,x:o.x,y:o.y,position:o.position,type:o.type};o.type==="source"?n.push(i):o.type==="target"&&r.push(i)}return{source:n,target:r}}function gc(e){return e==="manual"}function tu(e,t,n,r={}){var u,p;const o=hc(FS,r),i={i:0},s=new Map(t),l=o!=null&&o.elevateNodesOnSelect&&!gc(o.zIndexMode)?dm:0;let a=e.length>0;t.clear(),n.clear();for(const c of e){let f=s.get(c.id);if(o.checkEquality&&c===(f==null?void 0:f.internals.userNode))t.set(c.id,f);else{const x=Yo(c,o.nodeOrigin),y=_r(c.extent)?c.extent:o.nodeExtent,v=Rn(x,y,Ht(c));f={...o.defaults,...c,measured:{width:(u=c.measured)==null?void 0:u.width,height:(p=c.measured)==null?void 0:p.height},internals:{positionAbsolute:v,handleBounds:VS(c,f),z:fm(c,l,o.zIndexMode),userNode:c}},t.set(c.id,f)}(f.measured===void 0||f.measured.width===void 0||f.measured.height===void 0)&&!f.hidden&&(a=!1),c.parentId&&mc(f,t,n,r,i)}return a}function WS(e,t){if(!e.parentId)return;const n=t.get(e.parentId);n?n.set(e.id,e):t.set(e.parentId,new Map([[e.id,e]]))}function mc(e,t,n,r,o){const{elevateNodesOnSelect:i,nodeOrigin:s,nodeExtent:l,zIndexMode:a}=hc(pc,r),u=e.parentId,p=t.get(u);if(!p){console.warn(`Parent node ${u} not found. Please make sure that parent nodes are in front of their child nodes in the nodes array.`);return}WS(e,n),o&&!p.parentId&&p.internals.rootParentIndex===void 0&&a==="auto"&&(p.internals.rootParentIndex=++o.i,p.internals.z=p.internals.z+o.i*BS),o&&p.internals.rootParentIndex!==void 0&&(o.i=p.internals.rootParentIndex);const c=i&&!gc(a)?dm:0,{x:f,y:x,z:y}=US(e,p,s,l,c,a),{positionAbsolute:v}=e.internals,k=f!==v.x||x!==v.y;(k||y!==e.internals.z)&&t.set(e.id,{...e,internals:{...e.internals,positionAbsolute:k?{x:f,y:x}:v,z:y}})}function fm(e,t,n){const r=ct(e.zIndex)?e.zIndex:0;return gc(n)?r:r+(e.selected?t:0)}function US(e,t,n,r,o,i){const{x:s,y:l}=t.internals.positionAbsolute,a=Ht(e),u=Yo(e,n),p=_r(e.extent)?Rn(u,e.extent,a):u;let c=Rn({x:s+p.x,y:l+p.y},r,a);e.extent==="parent"&&(c=Jg(c,a,t));const f=fm(e,o,i),x=t.internals.z??0;return{x:c.x,y:c.y,z:x>=f?x+1:f}}function yc(e,t,n,r=[0,0]){var s;const o=[],i=new Map;for(const l of e){const a=t.get(l.parentId);if(!a)continue;const u=((s=i.get(l.parentId))==null?void 0:s.expandedRect)??kr(a),p=tm(u,l.rect);i.set(l.parentId,{expandedRect:p,parent:a})}return i.size>0&&i.forEach(({expandedRect:l,parent:a},u)=>{var h;const p=a.internals.positionAbsolute,c=Ht(a),f=a.origin??r,x=l.x0||y>0||m||g)&&(o.push({id:u,type:"position",position:{x:a.position.x-x+m,y:a.position.y-y+g}}),(h=n.get(u))==null||h.forEach(w=>{e.some(_=>_.id===w.id)||o.push({id:w.id,type:"position",position:{x:w.position.x+x,y:w.position.y+y}})})),(c.width0){const x=yc(f,t,n,o);u.push(...x)}return{changes:u,updatedInternals:a}}async function XS({delta:e,panZoom:t,transform:n,translateExtent:r,width:o,height:i}){if(!t||!e.x&&!e.y)return Promise.resolve(!1);const s=await t.setViewportConstrained({x:n[0]+e.x,y:n[1]+e.y,zoom:n[2]},[[0,0],[o,i]],r),l=!!s&&(s.x!==n[0]||s.y!==n[1]||s.k!==n[2]);return Promise.resolve(l)}function hf(e,t,n,r,o,i){let s=o;const l=r.get(s)||new Map;r.set(s,l.set(n,t)),s=`${o}-${e}`;const a=r.get(s)||new Map;if(r.set(s,a.set(n,t)),i){s=`${o}-${e}-${i}`;const u=r.get(s)||new Map;r.set(s,u.set(n,t))}}function pm(e,t,n){e.clear(),t.clear();for(const r of n){const{source:o,target:i,sourceHandle:s=null,targetHandle:l=null}=r,a={edgeId:r.id,source:o,target:i,sourceHandle:s,targetHandle:l},u=`${o}-${s}--${i}-${l}`,p=`${i}-${l}--${o}-${s}`;hf("source",a,p,e,o,s),hf("target",a,u,e,i,l),t.set(r.id,r)}}function hm(e,t){if(!e.parentId)return!1;const n=t.get(e.parentId);return n?n.selected?!0:hm(n,t):!1}function gf(e,t,n){var o;let r=e;do{if((o=r==null?void 0:r.matches)!=null&&o.call(r,t))return!0;if(r===n)return!1;r=r==null?void 0:r.parentElement}while(r);return!1}function QS(e,t,n,r){const o=new Map;for(const[i,s]of e)if((s.selected||s.id===r)&&(!s.parentId||!hm(s,e))&&(s.draggable||t&&typeof s.draggable>"u")){const l=e.get(i);l&&o.set(i,{id:i,position:l.position||{x:0,y:0},distance:{x:n.x-l.internals.positionAbsolute.x,y:n.y-l.internals.positionAbsolute.y},extent:l.extent,parentId:l.parentId,origin:l.origin,expandParent:l.expandParent,internals:{positionAbsolute:l.internals.positionAbsolute||{x:0,y:0}},measured:{width:l.measured.width??0,height:l.measured.height??0}})}return o}function Al({nodeId:e,dragItems:t,nodeLookup:n,dragging:r=!0}){var s,l,a;const o=[];for(const[u,p]of t){const c=(s=n.get(u))==null?void 0:s.internals.userNode;c&&o.push({...c,position:p.position,dragging:r})}if(!e)return[o[0],o];const i=(l=n.get(e))==null?void 0:l.internals.userNode;return[i?{...i,position:((a=t.get(e))==null?void 0:a.position)||i.position,dragging:r}:o[0],o]}function GS({dragItems:e,snapGrid:t,x:n,y:r}){const o=e.values().next().value;if(!o)return null;const i={x:n-o.distance.x,y:r-o.distance.y},s=Qo(i,t);return{x:s.x-i.x,y:s.y-i.y}}function KS({onNodeMouseDown:e,getStoreItems:t,onDragStart:n,onDrag:r,onDragStop:o}){let i={x:null,y:null},s=0,l=new Map,a=!1,u={x:0,y:0},p=null,c=!1,f=null,x=!1,y=!1,v=null;function k({noDragClassName:g,handleSelector:h,domNode:w,isSelectable:_,nodeId:S,nodeClickDistance:b=0}){f=Ue(w);function E({x:I,y:T}){const{nodeLookup:C,nodeExtent:L,snapGrid:z,snapToGrid:R,nodeOrigin:j,onNodeDrag:N,onSelectionDrag:$,onError:O,updateNodePositions:B}=t();i={x:I,y:T};let W=!1;const V=l.size>1,Y=V&&L?qa(Xo(l)):null,X=V&&R?GS({dragItems:l,snapGrid:z,x:I,y:T}):null;for(const[Q,H]of l){if(!C.has(Q))continue;let K={x:I-H.distance.x,y:T-H.distance.y};R&&(K=X?{x:Math.round(K.x+X.x),y:Math.round(K.y+X.y)}:Qo(K,z));let ee=null;if(V&&L&&!H.extent&&Y){const{positionAbsolute:Z}=H.internals,re=Z.x-Y.x+L[0][0],le=Z.x+H.measured.width-Y.x2+L[1][0],ie=Z.y-Y.y+L[0][1],Ne=Z.y+H.measured.height-Y.y2+L[1][1];ee=[[re,ie],[le,Ne]]}const{position:G,positionAbsolute:J}=qg({nodeId:Q,nextPosition:K,nodeLookup:C,nodeExtent:ee||L,nodeOrigin:j,onError:O});W=W||H.position.x!==G.x||H.position.y!==G.y,H.position=G,H.internals.positionAbsolute=J}if(y=y||W,!!W&&(B(l,!0),v&&(r||N||!S&&$))){const[Q,H]=Al({nodeId:S,dragItems:l,nodeLookup:C});r==null||r(v,l,Q,H),N==null||N(v,Q,H),S||$==null||$(v,H)}}async function A(){if(!p)return;const{transform:I,panBy:T,autoPanSpeed:C,autoPanOnNodeDrag:L}=t();if(!L){a=!1,cancelAnimationFrame(s);return}const[z,R]=em(u,p,C);(z!==0||R!==0)&&(i.x=(i.x??0)-z/I[2],i.y=(i.y??0)-R/I[2],await T({x:z,y:R})&&E(i)),s=requestAnimationFrame(A)}function D(I){var V;const{nodeLookup:T,multiSelectionActive:C,nodesDraggable:L,transform:z,snapGrid:R,snapToGrid:j,selectNodesOnDrag:N,onNodeDragStart:$,onSelectionDragStart:O,unselectNodesAndEdges:B}=t();c=!0,(!N||!_)&&!C&&S&&((V=T.get(S))!=null&&V.selected||B()),_&&N&&S&&(e==null||e(S));const W=co(I.sourceEvent,{transform:z,snapGrid:R,snapToGrid:j,containerBounds:p});if(i=W,l=QS(T,L,W,S),l.size>0&&(n||$||!S&&O)){const[Y,X]=Al({nodeId:S,dragItems:l,nodeLookup:T});n==null||n(I.sourceEvent,l,Y,X),$==null||$(I.sourceEvent,Y,X),S||O==null||O(I.sourceEvent,X)}}const P=Tg().clickDistance(b).on("start",I=>{const{domNode:T,nodeDragThreshold:C,transform:L,snapGrid:z,snapToGrid:R}=t();p=(T==null?void 0:T.getBoundingClientRect())||null,x=!1,y=!1,v=I.sourceEvent,C===0&&D(I),i=co(I.sourceEvent,{transform:L,snapGrid:z,snapToGrid:R,containerBounds:p}),u=dt(I.sourceEvent,p)}).on("drag",I=>{const{autoPanOnNodeDrag:T,transform:C,snapGrid:L,snapToGrid:z,nodeDragThreshold:R,nodeLookup:j}=t(),N=co(I.sourceEvent,{transform:C,snapGrid:L,snapToGrid:z,containerBounds:p});if(v=I.sourceEvent,(I.sourceEvent.type==="touchmove"&&I.sourceEvent.touches.length>1||S&&!j.has(S))&&(x=!0),!x){if(!a&&T&&c&&(a=!0,A()),!c){const $=dt(I.sourceEvent,p),O=$.x-u.x,B=$.y-u.y;Math.sqrt(O*O+B*B)>R&&D(I)}(i.x!==N.xSnapped||i.y!==N.ySnapped)&&l&&c&&(u=dt(I.sourceEvent,p),E(N))}}).on("end",I=>{if(!(!c||x)&&(a=!1,c=!1,cancelAnimationFrame(s),l.size>0)){const{nodeLookup:T,updateNodePositions:C,onNodeDragStop:L,onSelectionDragStop:z}=t();if(y&&(C(l,!1),y=!1),o||L||!S&&z){const[R,j]=Al({nodeId:S,dragItems:l,nodeLookup:T,dragging:!1});o==null||o(I.sourceEvent,l,R,j),L==null||L(I.sourceEvent,R,j),S||z==null||z(I.sourceEvent,j)}}}).filter(I=>{const T=I.target;return!I.button&&(!g||!gf(T,`.${g}`,w))&&(!h||gf(T,h,w))});f.call(P)}function m(){f==null||f.on(".drag",null)}return{update:k,destroy:m}}function ZS(e,t,n){const r=[],o={x:e.x-n,y:e.y-n,width:n*2,height:n*2};for(const i of t.values())Lo(o,kr(i))>0&&r.push(i);return r}const qS=250;function JS(e,t,n,r){var l,a;let o=[],i=1/0;const s=ZS(e,n,t+qS);for(const u of s){const p=[...((l=u.internals.handleBounds)==null?void 0:l.source)??[],...((a=u.internals.handleBounds)==null?void 0:a.target)??[]];for(const c of p){if(r.nodeId===c.nodeId&&r.type===c.type&&r.id===c.id)continue;const{x:f,y:x}=Ln(u,c,c.position,!0),y=Math.sqrt(Math.pow(f-e.x,2)+Math.pow(x-e.y,2));y>t||(y1){const u=r.type==="source"?"target":"source";return o.find(p=>p.type===u)??o[0]}return o[0]}function gm(e,t,n,r,o,i=!1){var u,p,c;const s=r.get(e);if(!s)return null;const l=o==="strict"?(u=s.internals.handleBounds)==null?void 0:u[t]:[...((p=s.internals.handleBounds)==null?void 0:p.source)??[],...((c=s.internals.handleBounds)==null?void 0:c.target)??[]],a=(n?l==null?void 0:l.find(f=>f.id===n):l==null?void 0:l[0])??null;return a&&i?{...a,...Ln(s,a,a.position,!0)}:a}function mm(e,t){return e||(t!=null&&t.classList.contains("target")?"target":t!=null&&t.classList.contains("source")?"source":null)}function ek(e,t){let n=null;return t?n=!0:e&&!t&&(n=!1),n}const ym=()=>!0;function tk(e,{connectionMode:t,connectionRadius:n,handleId:r,nodeId:o,edgeUpdaterType:i,isTarget:s,domNode:l,nodeLookup:a,lib:u,autoPanOnConnect:p,flowId:c,panBy:f,cancelConnection:x,onConnectStart:y,onConnect:v,onConnectEnd:k,isValidConnection:m=ym,onReconnectEnd:g,updateConnection:h,getTransform:w,getFromHandle:_,autoPanSpeed:S,dragThreshold:b=1,handleDomNode:E}){const A=om(e.target);let D=0,P;const{x:I,y:T}=dt(e),C=mm(i,E),L=l==null?void 0:l.getBoundingClientRect();let z=!1;if(!L||!C)return;const R=gm(o,C,r,a,t);if(!R)return;let j=dt(e,L),N=!1,$=null,O=!1,B=null;function W(){if(!p||!L)return;const[G,J]=em(j,L,S);f({x:G,y:J}),D=requestAnimationFrame(W)}const V={...R,nodeId:o,type:C,position:R.position},Y=a.get(o);let Q={inProgress:!0,isValid:null,from:Ln(Y,V,q.Left,!0),fromHandle:V,fromPosition:V.position,fromNode:Y,to:j,toHandle:null,toPosition:nf[V.position],toNode:null,pointer:j};function H(){z=!0,h(Q),y==null||y(e,{nodeId:o,handleId:r,handleType:C})}b===0&&H();function K(G){if(!z){const{x:Ne,y:Vt}=dt(G),Nt=Ne-I,gn=Vt-T;if(!(Nt*Nt+gn*gn>b*b))return;H()}if(!_()||!V){ee(G);return}const J=w();j=dt(G,L),P=JS(Go(j,J,!1,[1,1]),n,a,V),N||(W(),N=!0);const Z=xm(G,{handle:P,connectionMode:t,fromNodeId:o,fromHandleId:r,fromType:s?"target":"source",isValidConnection:m,doc:A,lib:u,flowId:c,nodeLookup:a});B=Z.handleDomNode,$=Z.connection,O=ek(!!P,Z.isValid);const re=a.get(o),le=re?Ln(re,V,q.Left,!0):Q.from,ie={...Q,from:le,isValid:O,to:Z.toHandle&&O?Es({x:Z.toHandle.x,y:Z.toHandle.y},J):j,toHandle:Z.toHandle,toPosition:O&&Z.toHandle?Z.toHandle.position:nf[V.position],toNode:Z.toHandle?a.get(Z.toHandle.nodeId):null,pointer:j};h(ie),Q=ie}function ee(G){if(!("touches"in G&&G.touches.length>0)){if(z){(P||B)&&$&&O&&(v==null||v($));const{inProgress:J,...Z}=Q,re={...Z,toPosition:Q.toHandle?Q.toPosition:null};k==null||k(G,re),i&&(g==null||g(G,re))}x(),cancelAnimationFrame(D),N=!1,O=!1,$=null,B=null,A.removeEventListener("mousemove",K),A.removeEventListener("mouseup",ee),A.removeEventListener("touchmove",K),A.removeEventListener("touchend",ee)}}A.addEventListener("mousemove",K),A.addEventListener("mouseup",ee),A.addEventListener("touchmove",K),A.addEventListener("touchend",ee)}function xm(e,{handle:t,connectionMode:n,fromNodeId:r,fromHandleId:o,fromType:i,doc:s,lib:l,flowId:a,isValidConnection:u=ym,nodeLookup:p}){const c=i==="target",f=t?s.querySelector(`.${l}-flow__handle[data-id="${a}-${t==null?void 0:t.nodeId}-${t==null?void 0:t.id}-${t==null?void 0:t.type}"]`):null,{x,y}=dt(e),v=s.elementFromPoint(x,y),k=v!=null&&v.classList.contains(`${l}-flow__handle`)?v:f,m={handleDomNode:k,isValid:!1,connection:null,toHandle:null};if(k){const g=mm(void 0,k),h=k.getAttribute("data-nodeid"),w=k.getAttribute("data-handleid"),_=k.classList.contains("connectable"),S=k.classList.contains("connectableend");if(!h||!g)return m;const b={source:c?h:r,sourceHandle:c?w:o,target:c?r:h,targetHandle:c?o:w};m.connection=b;const A=_&&S&&(n===wr.Strict?c&&g==="source"||!c&&g==="target":h!==r||w!==o);m.isValid=A&&u(b),m.toHandle=gm(h,g,w,p,n,!0)}return m}const nu={onPointerDown:tk,isValid:xm};function nk({domNode:e,panZoom:t,getTransform:n,getViewScale:r}){const o=Ue(e);function i({translateExtent:l,width:a,height:u,zoomStep:p=1,pannable:c=!0,zoomable:f=!0,inversePan:x=!1}){const y=h=>{if(h.sourceEvent.type!=="wheel"||!t)return;const w=n(),_=h.sourceEvent.ctrlKey&&Ao()?10:1,S=-h.sourceEvent.deltaY*(h.sourceEvent.deltaMode===1?.05:h.sourceEvent.deltaMode?1:.002)*p,b=w[2]*Math.pow(2,S*_);t.scaleTo(b)};let v=[0,0];const k=h=>{(h.sourceEvent.type==="mousedown"||h.sourceEvent.type==="touchstart")&&(v=[h.sourceEvent.clientX??h.sourceEvent.touches[0].clientX,h.sourceEvent.clientY??h.sourceEvent.touches[0].clientY])},m=h=>{const w=n();if(h.sourceEvent.type!=="mousemove"&&h.sourceEvent.type!=="touchmove"||!t)return;const _=[h.sourceEvent.clientX??h.sourceEvent.touches[0].clientX,h.sourceEvent.clientY??h.sourceEvent.touches[0].clientY],S=[_[0]-v[0],_[1]-v[1]];v=_;const b=r()*Math.max(w[2],Math.log(w[2]))*(x?-1:1),E={x:w[0]-S[0]*b,y:w[1]-S[1]*b},A=[[0,0],[a,u]];t.setViewportConstrained({x:E.x,y:E.y,zoom:w[2]},A,l)},g=Yg().on("start",k).on("zoom",c?m:null).on("zoom.wheel",f?y:null);o.call(g,{})}function s(){o.on("zoom",null)}return{update:i,destroy:s,pointer:lt}}const Zs=e=>({x:e.x,y:e.y,zoom:e.k}),$l=({x:e,y:t,zoom:n})=>Qs.translate(e,t).scale(n),tr=(e,t)=>e.target.closest(`.${t}`),vm=(e,t)=>t===2&&Array.isArray(e)&&e.includes(2),rk=e=>((e*=2)<=1?e*e*e:(e-=2)*e*e+2)/2,Dl=(e,t=0,n=rk,r=()=>{})=>{const o=typeof t=="number"&&t>0;return o||r(),o?e.transition().duration(t).ease(n).on("end",r):e},wm=e=>{const t=e.ctrlKey&&Ao()?10:1;return-e.deltaY*(e.deltaMode===1?.05:e.deltaMode?1:.002)*t};function ok({zoomPanValues:e,noWheelClassName:t,d3Selection:n,d3Zoom:r,panOnScrollMode:o,panOnScrollSpeed:i,zoomOnPinch:s,onPanZoomStart:l,onPanZoom:a,onPanZoomEnd:u}){return p=>{if(tr(p,t))return p.ctrlKey&&p.preventDefault(),!1;p.preventDefault(),p.stopImmediatePropagation();const c=n.property("__zoom").k||1;if(p.ctrlKey&&s){const k=lt(p),m=wm(p),g=c*Math.pow(2,m);r.scaleTo(n,g,k,p);return}const f=p.deltaMode===1?20:1;let x=o===En.Vertical?0:p.deltaX*f,y=o===En.Horizontal?0:p.deltaY*f;!Ao()&&p.shiftKey&&o!==En.Vertical&&(x=p.deltaY*f,y=0),r.translateBy(n,-(x/c)*i,-(y/c)*i,{internal:!0});const v=Zs(n.property("__zoom"));clearTimeout(e.panScrollTimeout),e.isPanScrolling?(a==null||a(p,v),e.panScrollTimeout=setTimeout(()=>{u==null||u(p,v),e.isPanScrolling=!1},150)):(e.isPanScrolling=!0,l==null||l(p,v))}}function ik({noWheelClassName:e,preventScrolling:t,d3ZoomHandler:n}){return function(r,o){const i=r.type==="wheel",s=!t&&i&&!r.ctrlKey,l=tr(r,e);if(r.ctrlKey&&i&&l&&r.preventDefault(),s||l)return null;r.preventDefault(),n.call(this,r,o)}}function sk({zoomPanValues:e,onDraggingChange:t,onPanZoomStart:n}){return r=>{var i,s,l;if((i=r.sourceEvent)!=null&&i.internal)return;const o=Zs(r.transform);e.mouseButton=((s=r.sourceEvent)==null?void 0:s.button)||0,e.isZoomingOrPanning=!0,e.prevViewport=o,((l=r.sourceEvent)==null?void 0:l.type)==="mousedown"&&t(!0),n&&(n==null||n(r.sourceEvent,o))}}function lk({zoomPanValues:e,panOnDrag:t,onPaneContextMenu:n,onTransformChange:r,onPanZoom:o}){return i=>{var s,l;e.usedRightMouseButton=!!(n&&vm(t,e.mouseButton??0)),(s=i.sourceEvent)!=null&&s.sync||r([i.transform.x,i.transform.y,i.transform.k]),o&&!((l=i.sourceEvent)!=null&&l.internal)&&(o==null||o(i.sourceEvent,Zs(i.transform)))}}function ak({zoomPanValues:e,panOnDrag:t,panOnScroll:n,onDraggingChange:r,onPanZoomEnd:o,onPaneContextMenu:i}){return s=>{var l;if(!((l=s.sourceEvent)!=null&&l.internal)&&(e.isZoomingOrPanning=!1,i&&vm(t,e.mouseButton??0)&&!e.usedRightMouseButton&&s.sourceEvent&&i(s.sourceEvent),e.usedRightMouseButton=!1,r(!1),o)){const a=Zs(s.transform);e.prevViewport=a,clearTimeout(e.timerId),e.timerId=setTimeout(()=>{o==null||o(s.sourceEvent,a)},n?150:0)}}}function uk({zoomActivationKeyPressed:e,zoomOnScroll:t,zoomOnPinch:n,panOnDrag:r,panOnScroll:o,zoomOnDoubleClick:i,userSelectionActive:s,noWheelClassName:l,noPanClassName:a,lib:u,connectionInProgress:p}){return c=>{var k;const f=e||t,x=n&&c.ctrlKey,y=c.type==="wheel";if(c.button===1&&c.type==="mousedown"&&(tr(c,`${u}-flow__node`)||tr(c,`${u}-flow__edge`)))return!0;if(!r&&!f&&!o&&!i&&!n||s||p&&!y||tr(c,l)&&y||tr(c,a)&&(!y||o&&y&&!e)||!n&&c.ctrlKey&&y)return!1;if(!n&&c.type==="touchstart"&&((k=c.touches)==null?void 0:k.length)>1)return c.preventDefault(),!1;if(!f&&!o&&!x&&y||!r&&(c.type==="mousedown"||c.type==="touchstart")||Array.isArray(r)&&!r.includes(c.button)&&c.type==="mousedown")return!1;const v=Array.isArray(r)&&r.includes(c.button)||!c.button||c.button<=1;return(!c.ctrlKey||y)&&v}}function ck({domNode:e,minZoom:t,maxZoom:n,translateExtent:r,viewport:o,onPanZoom:i,onPanZoomStart:s,onPanZoomEnd:l,onDraggingChange:a}){const u={isZoomingOrPanning:!1,usedRightMouseButton:!1,prevViewport:{},mouseButton:0,timerId:void 0,panScrollTimeout:void 0,isPanScrolling:!1},p=e.getBoundingClientRect(),c=Yg().scaleExtent([t,n]).translateExtent(r),f=Ue(e).call(c);g({x:o.x,y:o.y,zoom:Sr(o.zoom,t,n)},[[0,0],[p.width,p.height]],r);const x=f.on("wheel.zoom"),y=f.on("dblclick.zoom");c.wheelDelta(wm);function v(P,I){return f?new Promise(T=>{c==null||c.interpolate((I==null?void 0:I.interpolate)==="linear"?uo:Vi).transform(Dl(f,I==null?void 0:I.duration,I==null?void 0:I.ease,()=>T(!0)),P)}):Promise.resolve(!1)}function k({noWheelClassName:P,noPanClassName:I,onPaneContextMenu:T,userSelectionActive:C,panOnScroll:L,panOnDrag:z,panOnScrollMode:R,panOnScrollSpeed:j,preventScrolling:N,zoomOnPinch:$,zoomOnScroll:O,zoomOnDoubleClick:B,zoomActivationKeyPressed:W,lib:V,onTransformChange:Y,connectionInProgress:X,paneClickDistance:Q,selectionOnDrag:H}){C&&!u.isZoomingOrPanning&&m();const K=L&&!W&&!C;c.clickDistance(H?1/0:!ct(Q)||Q<0?0:Q);const ee=K?ok({zoomPanValues:u,noWheelClassName:P,d3Selection:f,d3Zoom:c,panOnScrollMode:R,panOnScrollSpeed:j,zoomOnPinch:$,onPanZoomStart:s,onPanZoom:i,onPanZoomEnd:l}):ik({noWheelClassName:P,preventScrolling:N,d3ZoomHandler:x});if(f.on("wheel.zoom",ee,{passive:!1}),!C){const J=sk({zoomPanValues:u,onDraggingChange:a,onPanZoomStart:s});c.on("start",J);const Z=lk({zoomPanValues:u,panOnDrag:z,onPaneContextMenu:!!T,onPanZoom:i,onTransformChange:Y});c.on("zoom",Z);const re=ak({zoomPanValues:u,panOnDrag:z,panOnScroll:L,onPaneContextMenu:T,onPanZoomEnd:l,onDraggingChange:a});c.on("end",re)}const G=uk({zoomActivationKeyPressed:W,panOnDrag:z,zoomOnScroll:O,panOnScroll:L,zoomOnDoubleClick:B,zoomOnPinch:$,userSelectionActive:C,noPanClassName:I,noWheelClassName:P,lib:V,connectionInProgress:X});c.filter(G),B?f.on("dblclick.zoom",y):f.on("dblclick.zoom",null)}function m(){c.on("zoom",null)}async function g(P,I,T){const C=$l(P),L=c==null?void 0:c.constrain()(C,I,T);return L&&await v(L),new Promise(z=>z(L))}async function h(P,I){const T=$l(P);return await v(T,I),new Promise(C=>C(T))}function w(P){if(f){const I=$l(P),T=f.property("__zoom");(T.k!==P.zoom||T.x!==P.x||T.y!==P.y)&&(c==null||c.transform(f,I,null,{sync:!0}))}}function _(){const P=f?Ug(f.node()):{x:0,y:0,k:1};return{x:P.x,y:P.y,zoom:P.k}}function S(P,I){return f?new Promise(T=>{c==null||c.interpolate((I==null?void 0:I.interpolate)==="linear"?uo:Vi).scaleTo(Dl(f,I==null?void 0:I.duration,I==null?void 0:I.ease,()=>T(!0)),P)}):Promise.resolve(!1)}function b(P,I){return f?new Promise(T=>{c==null||c.interpolate((I==null?void 0:I.interpolate)==="linear"?uo:Vi).scaleBy(Dl(f,I==null?void 0:I.duration,I==null?void 0:I.ease,()=>T(!0)),P)}):Promise.resolve(!1)}function E(P){c==null||c.scaleExtent(P)}function A(P){c==null||c.translateExtent(P)}function D(P){const I=!ct(P)||P<0?0:P;c==null||c.clickDistance(I)}return{update:k,destroy:m,setViewport:h,setViewportConstrained:g,getViewport:_,scaleTo:S,scaleBy:b,setScaleExtent:E,setTranslateExtent:A,syncViewport:w,setClickDistance:D}}var An;(function(e){e.Line="line",e.Handle="handle"})(An||(An={}));const dk=["top-left","top-right","bottom-left","bottom-right"],fk=["top","right","bottom","left"];function pk({width:e,prevWidth:t,height:n,prevHeight:r,affectsX:o,affectsY:i}){const s=e-t,l=n-r,a=[s>0?1:s<0?-1:0,l>0?1:l<0?-1:0];return s&&o&&(a[0]=a[0]*-1),l&&i&&(a[1]=a[1]*-1),a}function mf(e){const t=e.includes("right")||e.includes("left"),n=e.includes("bottom")||e.includes("top"),r=e.includes("left"),o=e.includes("top");return{isHorizontal:t,isVertical:n,affectsX:r,affectsY:o}}function Ut(e,t){return Math.max(0,t-e)}function Yt(e,t){return Math.max(0,e-t)}function Si(e,t,n){return Math.max(0,t-e,e-n)}function yf(e,t){return e?!t:t}function hk(e,t,n,r,o,i,s,l){let{affectsX:a,affectsY:u}=t;const{isHorizontal:p,isVertical:c}=t,f=p&&c,{xSnapped:x,ySnapped:y}=n,{minWidth:v,maxWidth:k,minHeight:m,maxHeight:g}=r,{x:h,y:w,width:_,height:S,aspectRatio:b}=e;let E=Math.floor(p?x-e.pointerX:0),A=Math.floor(c?y-e.pointerY:0);const D=_+(a?-E:E),P=S+(u?-A:A),I=-i[0]*_,T=-i[1]*S;let C=Si(D,v,k),L=Si(P,m,g);if(s){let j=0,N=0;a&&E<0?j=Ut(h+E+I,s[0][0]):!a&&E>0&&(j=Yt(h+D+I,s[1][0])),u&&A<0?N=Ut(w+A+T,s[0][1]):!u&&A>0&&(N=Yt(w+P+T,s[1][1])),C=Math.max(C,j),L=Math.max(L,N)}if(l){let j=0,N=0;a&&E>0?j=Yt(h+E,l[0][0]):!a&&E<0&&(j=Ut(h+D,l[1][0])),u&&A>0?N=Yt(w+A,l[0][1]):!u&&A<0&&(N=Ut(w+P,l[1][1])),C=Math.max(C,j),L=Math.max(L,N)}if(o){if(p){const j=Si(D/b,m,g)*b;if(C=Math.max(C,j),s){let N=0;!a&&!u||a&&!u&&f?N=Yt(w+T+D/b,s[1][1])*b:N=Ut(w+T+(a?E:-E)/b,s[0][1])*b,C=Math.max(C,N)}if(l){let N=0;!a&&!u||a&&!u&&f?N=Ut(w+D/b,l[1][1])*b:N=Yt(w+(a?E:-E)/b,l[0][1])*b,C=Math.max(C,N)}}if(c){const j=Si(P*b,v,k)/b;if(L=Math.max(L,j),s){let N=0;!a&&!u||u&&!a&&f?N=Yt(h+P*b+I,s[1][0])/b:N=Ut(h+(u?A:-A)*b+I,s[0][0])/b,L=Math.max(L,N)}if(l){let N=0;!a&&!u||u&&!a&&f?N=Ut(h+P*b,l[1][0])/b:N=Yt(h+(u?A:-A)*b,l[0][0])/b,L=Math.max(L,N)}}}A=A+(A<0?L:-L),E=E+(E<0?C:-C),o&&(f?D>P*b?A=(yf(a,u)?-E:E)/b:E=(yf(a,u)?-A:A)*b:p?(A=E/b,u=a):(E=A*b,a=u));const z=a?h+E:h,R=u?w+A:w;return{width:_+(a?-E:E),height:S+(u?-A:A),x:i[0]*E*(a?-1:1)+z,y:i[1]*A*(u?-1:1)+R}}const Sm={width:0,height:0,x:0,y:0},gk={...Sm,pointerX:0,pointerY:0,aspectRatio:1};function mk(e){return[[0,0],[e.measured.width,e.measured.height]]}function yk(e,t,n){const r=t.position.x+e.position.x,o=t.position.y+e.position.y,i=e.measured.width??0,s=e.measured.height??0,l=n[0]*i,a=n[1]*s;return[[r-l,o-a],[r+i-l,o+s-a]]}function xk({domNode:e,nodeId:t,getStoreItems:n,onChange:r,onEnd:o}){const i=Ue(e);let s={controlDirection:mf("bottom-right"),boundaries:{minWidth:0,minHeight:0,maxWidth:Number.MAX_VALUE,maxHeight:Number.MAX_VALUE},resizeDirection:void 0,keepAspectRatio:!1};function l({controlPosition:u,boundaries:p,keepAspectRatio:c,resizeDirection:f,onResizeStart:x,onResize:y,onResizeEnd:v,shouldResize:k}){let m={...Sm},g={...gk};s={boundaries:p,resizeDirection:f,keepAspectRatio:c,controlDirection:mf(u)};let h,w=null,_=[],S,b,E,A=!1;const D=Tg().on("start",P=>{const{nodeLookup:I,transform:T,snapGrid:C,snapToGrid:L,nodeOrigin:z,paneDomNode:R}=n();if(h=I.get(t),!h)return;w=(R==null?void 0:R.getBoundingClientRect())??null;const{xSnapped:j,ySnapped:N}=co(P.sourceEvent,{transform:T,snapGrid:C,snapToGrid:L,containerBounds:w});m={width:h.measured.width??0,height:h.measured.height??0,x:h.position.x??0,y:h.position.y??0},g={...m,pointerX:j,pointerY:N,aspectRatio:m.width/m.height},S=void 0,h.parentId&&(h.extent==="parent"||h.expandParent)&&(S=I.get(h.parentId),b=S&&h.extent==="parent"?mk(S):void 0),_=[],E=void 0;for(const[$,O]of I)if(O.parentId===t&&(_.push({id:$,position:{...O.position},extent:O.extent}),O.extent==="parent"||O.expandParent)){const B=yk(O,h,O.origin??z);E?E=[[Math.min(B[0][0],E[0][0]),Math.min(B[0][1],E[0][1])],[Math.max(B[1][0],E[1][0]),Math.max(B[1][1],E[1][1])]]:E=B}x==null||x(P,{...m})}).on("drag",P=>{const{transform:I,snapGrid:T,snapToGrid:C,nodeOrigin:L}=n(),z=co(P.sourceEvent,{transform:I,snapGrid:T,snapToGrid:C,containerBounds:w}),R=[];if(!h)return;const{x:j,y:N,width:$,height:O}=m,B={},W=h.origin??L,{width:V,height:Y,x:X,y:Q}=hk(g,s.controlDirection,z,s.boundaries,s.keepAspectRatio,W,b,E),H=V!==$,K=Y!==O,ee=X!==j&&H,G=Q!==N&&K;if(!ee&&!G&&!H&&!K)return;if((ee||G||W[0]===1||W[1]===1)&&(B.x=ee?X:m.x,B.y=G?Q:m.y,m.x=B.x,m.y=B.y,_.length>0)){const le=X-j,ie=Q-N;for(const Ne of _)Ne.position={x:Ne.position.x-le+W[0]*(V-$),y:Ne.position.y-ie+W[1]*(Y-O)},R.push(Ne)}if((H||K)&&(B.width=H&&(!s.resizeDirection||s.resizeDirection==="horizontal")?V:m.width,B.height=K&&(!s.resizeDirection||s.resizeDirection==="vertical")?Y:m.height,m.width=B.width,m.height=B.height),S&&h.expandParent){const le=W[0]*(B.width??0);B.x&&B.x{A&&(v==null||v(P,{...m}),o==null||o({...m}),A=!1)});i.call(D)}function a(){i.on(".drag",null)}return{update:l,destroy:a}}var km={exports:{}},_m={},bm={exports:{}},Cm={};/** + * @license React + * use-sync-external-store-shim.production.js + * + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var br=M;function vk(e,t){return e===t&&(e!==0||1/e===1/t)||e!==e&&t!==t}var wk=typeof Object.is=="function"?Object.is:vk,Sk=br.useState,kk=br.useEffect,_k=br.useLayoutEffect,bk=br.useDebugValue;function Ck(e,t){var n=t(),r=Sk({inst:{value:n,getSnapshot:t}}),o=r[0].inst,i=r[1];return _k(function(){o.value=n,o.getSnapshot=t,Ol(o)&&i({inst:o})},[e,n,t]),kk(function(){return Ol(o)&&i({inst:o}),e(function(){Ol(o)&&i({inst:o})})},[e]),bk(n),n}function Ol(e){var t=e.getSnapshot;e=e.value;try{var n=t();return!wk(e,n)}catch{return!0}}function Ek(e,t){return t()}var jk=typeof window>"u"||typeof window.document>"u"||typeof window.document.createElement>"u"?Ek:Ck;Cm.useSyncExternalStore=br.useSyncExternalStore!==void 0?br.useSyncExternalStore:jk;bm.exports=Cm;var Nk=bm.exports;/** + * @license React + * use-sync-external-store-shim/with-selector.production.js + * + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var qs=M,Mk=Nk;function zk(e,t){return e===t&&(e!==0||1/e===1/t)||e!==e&&t!==t}var Tk=typeof Object.is=="function"?Object.is:zk,Pk=Mk.useSyncExternalStore,Ik=qs.useRef,Rk=qs.useEffect,Lk=qs.useMemo,Ak=qs.useDebugValue;_m.useSyncExternalStoreWithSelector=function(e,t,n,r,o){var i=Ik(null);if(i.current===null){var s={hasValue:!1,value:null};i.current=s}else s=i.current;i=Lk(function(){function a(x){if(!u){if(u=!0,p=x,x=r(x),o!==void 0&&s.hasValue){var y=s.value;if(o(y,x))return c=y}return c=x}if(y=c,Tk(p,x))return y;var v=r(x);return o!==void 0&&o(y,v)?(p=x,y):(p=x,c=v)}var u=!1,p,c,f=n===void 0?null:n;return[function(){return a(t())},f===null?void 0:function(){return a(f())}]},[t,n,r,o]);var l=Pk(e,i[0],i[1]);return Rk(function(){s.hasValue=!0,s.value=l},[l]),Ak(l),l};km.exports=_m;var $k=km.exports;const Dk=rp($k),Ok={},xf=e=>{let t;const n=new Set,r=(p,c)=>{const f=typeof p=="function"?p(t):p;if(!Object.is(f,t)){const x=t;t=c??(typeof f!="object"||f===null)?f:Object.assign({},t,f),n.forEach(y=>y(t,x))}},o=()=>t,a={setState:r,getState:o,getInitialState:()=>u,subscribe:p=>(n.add(p),()=>n.delete(p)),destroy:()=>{(Ok?"production":void 0)!=="production"&&console.warn("[DEPRECATED] The `destroy` method will be unsupported in a future version. Instead use unsubscribe function returned by subscribe. Everything will be garbage-collected if store is garbage-collected."),n.clear()}},u=t=e(r,o,a);return a},Bk=e=>e?xf(e):xf,{useDebugValue:Fk}=hp,{useSyncExternalStoreWithSelector:Hk}=Dk,Vk=e=>e;function Em(e,t=Vk,n){const r=Hk(e.subscribe,e.getState,e.getServerState||e.getInitialState,t,n);return Fk(r),r}const vf=(e,t)=>{const n=Bk(e),r=(o,i=t)=>Em(n,o,i);return Object.assign(r,n),r},Wk=(e,t)=>e?vf(e,t):vf;function fe(e,t){if(Object.is(e,t))return!0;if(typeof e!="object"||e===null||typeof t!="object"||t===null)return!1;if(e instanceof Map&&t instanceof Map){if(e.size!==t.size)return!1;for(const[r,o]of e)if(!Object.is(o,t.get(r)))return!1;return!0}if(e instanceof Set&&t instanceof Set){if(e.size!==t.size)return!1;for(const r of e)if(!t.has(r))return!1;return!0}const n=Object.keys(e);if(n.length!==Object.keys(t).length)return!1;for(const r of n)if(!Object.prototype.hasOwnProperty.call(t,r)||!Object.is(e[r],t[r]))return!1;return!0}const Js=M.createContext(null),Uk=Js.Provider,jm=Et.error001();function ne(e,t){const n=M.useContext(Js);if(n===null)throw new Error(jm);return Em(n,e,t)}function pe(){const e=M.useContext(Js);if(e===null)throw new Error(jm);return M.useMemo(()=>({getState:e.getState,setState:e.setState,subscribe:e.subscribe}),[e])}const wf={display:"none"},Yk={position:"absolute",width:1,height:1,margin:-1,border:0,padding:0,overflow:"hidden",clip:"rect(0px, 0px, 0px, 0px)",clipPath:"inset(100%)"},Nm="react-flow__node-desc",Mm="react-flow__edge-desc",Xk="react-flow__aria-live",Qk=e=>e.ariaLiveMessage,Gk=e=>e.ariaLabelConfig;function Kk({rfId:e}){const t=ne(Qk);return d.jsx("div",{id:`${Xk}-${e}`,"aria-live":"assertive","aria-atomic":"true",style:Yk,children:t})}function Zk({rfId:e,disableKeyboardA11y:t}){const n=ne(Gk);return d.jsxs(d.Fragment,{children:[d.jsx("div",{id:`${Nm}-${e}`,style:wf,children:t?n["node.a11yDescription.default"]:n["node.a11yDescription.keyboardDisabled"]}),d.jsx("div",{id:`${Mm}-${e}`,style:wf,children:n["edge.a11yDescription.default"]}),!t&&d.jsx(Kk,{rfId:e})]})}const el=M.forwardRef(({position:e="top-left",children:t,className:n,style:r,...o},i)=>{const s=`${e}`.split("-");return d.jsx("div",{className:we(["react-flow__panel",n,...s]),style:r,ref:i,...o,children:t})});el.displayName="Panel";function qk({proOptions:e,position:t="bottom-right"}){return e!=null&&e.hideAttribution?null:d.jsx(el,{position:t,className:"react-flow__attribution","data-message":"Please only hide this attribution when you are subscribed to React Flow Pro: https://pro.reactflow.dev",children:d.jsx("a",{href:"https://reactflow.dev",target:"_blank",rel:"noopener noreferrer","aria-label":"React Flow attribution",children:"React Flow"})})}const Jk=e=>{const t=[],n=[];for(const[,r]of e.nodeLookup)r.selected&&t.push(r.internals.userNode);for(const[,r]of e.edgeLookup)r.selected&&n.push(r);return{selectedNodes:t,selectedEdges:n}},ki=e=>e.id;function e_(e,t){return fe(e.selectedNodes.map(ki),t.selectedNodes.map(ki))&&fe(e.selectedEdges.map(ki),t.selectedEdges.map(ki))}function t_({onSelectionChange:e}){const t=pe(),{selectedNodes:n,selectedEdges:r}=ne(Jk,e_);return M.useEffect(()=>{const o={nodes:n,edges:r};e==null||e(o),t.getState().onSelectionChangeHandlers.forEach(i=>i(o))},[n,r,e]),null}const n_=e=>!!e.onSelectionChangeHandlers;function r_({onSelectionChange:e}){const t=ne(n_);return e||t?d.jsx(t_,{onSelectionChange:e}):null}const zm=[0,0],o_={x:0,y:0,zoom:1},i_=["nodes","edges","defaultNodes","defaultEdges","onConnect","onConnectStart","onConnectEnd","onClickConnectStart","onClickConnectEnd","nodesDraggable","autoPanOnNodeFocus","nodesConnectable","nodesFocusable","edgesFocusable","edgesReconnectable","elevateNodesOnSelect","elevateEdgesOnSelect","minZoom","maxZoom","nodeExtent","onNodesChange","onEdgesChange","elementsSelectable","connectionMode","snapGrid","snapToGrid","translateExtent","connectOnClick","defaultEdgeOptions","fitView","fitViewOptions","onNodesDelete","onEdgesDelete","onDelete","onNodeDrag","onNodeDragStart","onNodeDragStop","onSelectionDrag","onSelectionDragStart","onSelectionDragStop","onMoveStart","onMove","onMoveEnd","noPanClassName","nodeOrigin","autoPanOnConnect","autoPanOnNodeDrag","onError","connectionRadius","isValidConnection","selectNodesOnDrag","nodeDragThreshold","connectionDragThreshold","onBeforeDelete","debug","autoPanSpeed","ariaLabelConfig","zIndexMode"],Sf=[...i_,"rfId"],s_=e=>({setNodes:e.setNodes,setEdges:e.setEdges,setMinZoom:e.setMinZoom,setMaxZoom:e.setMaxZoom,setTranslateExtent:e.setTranslateExtent,setNodeExtent:e.setNodeExtent,reset:e.reset,setDefaultNodesAndEdges:e.setDefaultNodesAndEdges}),kf={translateExtent:Io,nodeOrigin:zm,minZoom:.5,maxZoom:2,elementsSelectable:!0,noPanClassName:"nopan",rfId:"1"};function l_(e){const{setNodes:t,setEdges:n,setMinZoom:r,setMaxZoom:o,setTranslateExtent:i,setNodeExtent:s,reset:l,setDefaultNodesAndEdges:a}=ne(s_,fe),u=pe();M.useEffect(()=>(a(e.defaultNodes,e.defaultEdges),()=>{p.current=kf,l()}),[]);const p=M.useRef(kf);return M.useEffect(()=>{for(const c of Sf){const f=e[c],x=p.current[c];f!==x&&(typeof e[c]>"u"||(c==="nodes"?t(f):c==="edges"?n(f):c==="minZoom"?r(f):c==="maxZoom"?o(f):c==="translateExtent"?i(f):c==="nodeExtent"?s(f):c==="ariaLabelConfig"?u.setState({ariaLabelConfig:NS(f)}):c==="fitView"?u.setState({fitViewQueued:f}):c==="fitViewOptions"?u.setState({fitViewOptions:f}):u.setState({[c]:f})))}p.current=e},Sf.map(c=>e[c])),null}function _f(){return typeof window>"u"||!window.matchMedia?null:window.matchMedia("(prefers-color-scheme: dark)")}function a_(e){var r;const[t,n]=M.useState(e==="system"?null:e);return M.useEffect(()=>{if(e!=="system"){n(e);return}const o=_f(),i=()=>n(o!=null&&o.matches?"dark":"light");return i(),o==null||o.addEventListener("change",i),()=>{o==null||o.removeEventListener("change",i)}},[e]),t!==null?t:(r=_f())!=null&&r.matches?"dark":"light"}const bf=typeof document<"u"?document:null;function $o(e=null,t={target:bf,actInsideInputWithModifier:!0}){const[n,r]=M.useState(!1),o=M.useRef(!1),i=M.useRef(new Set([])),[s,l]=M.useMemo(()=>{if(e!==null){const u=(Array.isArray(e)?e:[e]).filter(c=>typeof c=="string").map(c=>c.replace("+",` +`).replace(` + +`,` ++`).split(` +`)),p=u.reduce((c,f)=>c.concat(...f),[]);return[u,p]}return[[],[]]},[e]);return M.useEffect(()=>{const a=(t==null?void 0:t.target)??bf,u=(t==null?void 0:t.actInsideInputWithModifier)??!0;if(e!==null){const p=x=>{var k,m;if(o.current=x.ctrlKey||x.metaKey||x.shiftKey||x.altKey,(!o.current||o.current&&!u)&&im(x))return!1;const v=Ef(x.code,l);if(i.current.add(x[v]),Cf(s,i.current,!1)){const g=((m=(k=x.composedPath)==null?void 0:k.call(x))==null?void 0:m[0])||x.target,h=(g==null?void 0:g.nodeName)==="BUTTON"||(g==null?void 0:g.nodeName)==="A";t.preventDefault!==!1&&(o.current||!h)&&x.preventDefault(),r(!0)}},c=x=>{const y=Ef(x.code,l);Cf(s,i.current,!0)?(r(!1),i.current.clear()):i.current.delete(x[y]),x.key==="Meta"&&i.current.clear(),o.current=!1},f=()=>{i.current.clear(),r(!1)};return a==null||a.addEventListener("keydown",p),a==null||a.addEventListener("keyup",c),window.addEventListener("blur",f),window.addEventListener("contextmenu",f),()=>{a==null||a.removeEventListener("keydown",p),a==null||a.removeEventListener("keyup",c),window.removeEventListener("blur",f),window.removeEventListener("contextmenu",f)}}},[e,r]),n}function Cf(e,t,n){return e.filter(r=>n||r.length===t.size).some(r=>r.every(o=>t.has(o)))}function Ef(e,t){return t.includes(e)?"code":"key"}const u_=()=>{const e=pe();return M.useMemo(()=>({zoomIn:t=>{const{panZoom:n}=e.getState();return n?n.scaleBy(1.2,{duration:t==null?void 0:t.duration}):Promise.resolve(!1)},zoomOut:t=>{const{panZoom:n}=e.getState();return n?n.scaleBy(1/1.2,{duration:t==null?void 0:t.duration}):Promise.resolve(!1)},zoomTo:(t,n)=>{const{panZoom:r}=e.getState();return r?r.scaleTo(t,{duration:n==null?void 0:n.duration}):Promise.resolve(!1)},getZoom:()=>e.getState().transform[2],setViewport:async(t,n)=>{const{transform:[r,o,i],panZoom:s}=e.getState();return s?(await s.setViewport({x:t.x??r,y:t.y??o,zoom:t.zoom??i},n),Promise.resolve(!0)):Promise.resolve(!1)},getViewport:()=>{const[t,n,r]=e.getState().transform;return{x:t,y:n,zoom:r}},setCenter:async(t,n,r)=>e.getState().setCenter(t,n,r),fitBounds:async(t,n)=>{const{width:r,height:o,minZoom:i,maxZoom:s,panZoom:l}=e.getState(),a=dc(t,r,o,i,s,(n==null?void 0:n.padding)??.1);return l?(await l.setViewport(a,{duration:n==null?void 0:n.duration,ease:n==null?void 0:n.ease,interpolate:n==null?void 0:n.interpolate}),Promise.resolve(!0)):Promise.resolve(!1)},screenToFlowPosition:(t,n={})=>{const{transform:r,snapGrid:o,snapToGrid:i,domNode:s}=e.getState();if(!s)return t;const{x:l,y:a}=s.getBoundingClientRect(),u={x:t.x-l,y:t.y-a},p=n.snapGrid??o,c=n.snapToGrid??i;return Go(u,r,c,p)},flowToScreenPosition:t=>{const{transform:n,domNode:r}=e.getState();if(!r)return t;const{x:o,y:i}=r.getBoundingClientRect(),s=Es(t,n);return{x:s.x+o,y:s.y+i}}}),[])};function Tm(e,t){const n=[],r=new Map,o=[];for(const i of e)if(i.type==="add"){o.push(i);continue}else if(i.type==="remove"||i.type==="replace")r.set(i.id,[i]);else{const s=r.get(i.id);s?s.push(i):r.set(i.id,[i])}for(const i of t){const s=r.get(i.id);if(!s){n.push(i);continue}if(s[0].type==="remove")continue;if(s[0].type==="replace"){n.push({...s[0].item});continue}const l={...i};for(const a of s)c_(a,l);n.push(l)}return o.length&&o.forEach(i=>{i.index!==void 0?n.splice(i.index,0,{...i.item}):n.push({...i.item})}),n}function c_(e,t){switch(e.type){case"select":{t.selected=e.selected;break}case"position":{typeof e.position<"u"&&(t.position=e.position),typeof e.dragging<"u"&&(t.dragging=e.dragging);break}case"dimensions":{typeof e.dimensions<"u"&&(t.measured={...e.dimensions},e.setAttributes&&((e.setAttributes===!0||e.setAttributes==="width")&&(t.width=e.dimensions.width),(e.setAttributes===!0||e.setAttributes==="height")&&(t.height=e.dimensions.height))),typeof e.resizing=="boolean"&&(t.resizing=e.resizing);break}}}function Pm(e,t){return Tm(e,t)}function Im(e,t){return Tm(e,t)}function xn(e,t){return{id:e,type:"select",selected:t}}function nr(e,t=new Set,n=!1){const r=[];for(const[o,i]of e){const s=t.has(o);!(i.selected===void 0&&!s)&&i.selected!==s&&(n&&(i.selected=s),r.push(xn(i.id,s)))}return r}function jf({items:e=[],lookup:t}){var o;const n=[],r=new Map(e.map(i=>[i.id,i]));for(const[i,s]of e.entries()){const l=t.get(s.id),a=((o=l==null?void 0:l.internals)==null?void 0:o.userNode)??l;a!==void 0&&a!==s&&n.push({id:s.id,item:s,type:"replace"}),a===void 0&&n.push({item:s,type:"add",index:i})}for(const[i]of t)r.get(i)===void 0&&n.push({id:i,type:"remove"});return n}function Nf(e){return{id:e.id,type:"remove"}}const Mf=e=>xS(e),d_=e=>Zg(e);function Rm(e){return M.forwardRef(e)}const f_=typeof window<"u"?M.useLayoutEffect:M.useEffect;function zf(e){const[t,n]=M.useState(BigInt(0)),[r]=M.useState(()=>p_(()=>n(o=>o+BigInt(1))));return f_(()=>{const o=r.get();o.length&&(e(o),r.reset())},[t]),r}function p_(e){let t=[];return{get:()=>t,reset:()=>{t=[]},push:n=>{t.push(n),e()}}}const Lm=M.createContext(null);function h_({children:e}){const t=pe(),n=M.useCallback(l=>{const{nodes:a=[],setNodes:u,hasDefaultNodes:p,onNodesChange:c,nodeLookup:f,fitViewQueued:x,onNodesChangeMiddlewareMap:y}=t.getState();let v=a;for(const m of l)v=typeof m=="function"?m(v):m;let k=jf({items:v,lookup:f});for(const m of y.values())k=m(k);p&&u(v),k.length>0?c==null||c(k):x&&window.requestAnimationFrame(()=>{const{fitViewQueued:m,nodes:g,setNodes:h}=t.getState();m&&h(g)})},[]),r=zf(n),o=M.useCallback(l=>{const{edges:a=[],setEdges:u,hasDefaultEdges:p,onEdgesChange:c,edgeLookup:f}=t.getState();let x=a;for(const y of l)x=typeof y=="function"?y(x):y;p?u(x):c&&c(jf({items:x,lookup:f}))},[]),i=zf(o),s=M.useMemo(()=>({nodeQueue:r,edgeQueue:i}),[]);return d.jsx(Lm.Provider,{value:s,children:e})}function g_(){const e=M.useContext(Lm);if(!e)throw new Error("useBatchContext must be used within a BatchProvider");return e}const m_=e=>!!e.panZoom;function xc(){const e=u_(),t=pe(),n=g_(),r=ne(m_),o=M.useMemo(()=>{const i=c=>t.getState().nodeLookup.get(c),s=c=>{n.nodeQueue.push(c)},l=c=>{n.edgeQueue.push(c)},a=c=>{var m,g;const{nodeLookup:f,nodeOrigin:x}=t.getState(),y=Mf(c)?c:f.get(c.id),v=y.parentId?rm(y.position,y.measured,y.parentId,f,x):y.position,k={...y,position:v,width:((m=y.measured)==null?void 0:m.width)??y.width,height:((g=y.measured)==null?void 0:g.height)??y.height};return kr(k)},u=(c,f,x={replace:!1})=>{s(y=>y.map(v=>{if(v.id===c){const k=typeof f=="function"?f(v):f;return x.replace&&Mf(k)?k:{...v,...k}}return v}))},p=(c,f,x={replace:!1})=>{l(y=>y.map(v=>{if(v.id===c){const k=typeof f=="function"?f(v):f;return x.replace&&d_(k)?k:{...v,...k}}return v}))};return{getNodes:()=>t.getState().nodes.map(c=>({...c})),getNode:c=>{var f;return(f=i(c))==null?void 0:f.internals.userNode},getInternalNode:i,getEdges:()=>{const{edges:c=[]}=t.getState();return c.map(f=>({...f}))},getEdge:c=>t.getState().edgeLookup.get(c),setNodes:s,setEdges:l,addNodes:c=>{const f=Array.isArray(c)?c:[c];n.nodeQueue.push(x=>[...x,...f])},addEdges:c=>{const f=Array.isArray(c)?c:[c];n.edgeQueue.push(x=>[...x,...f])},toObject:()=>{const{nodes:c=[],edges:f=[],transform:x}=t.getState(),[y,v,k]=x;return{nodes:c.map(m=>({...m})),edges:f.map(m=>({...m})),viewport:{x:y,y:v,zoom:k}}},deleteElements:async({nodes:c=[],edges:f=[]})=>{const{nodes:x,edges:y,onNodesDelete:v,onEdgesDelete:k,triggerNodeChanges:m,triggerEdgeChanges:g,onDelete:h,onBeforeDelete:w}=t.getState(),{nodes:_,edges:S}=await _S({nodesToRemove:c,edgesToRemove:f,nodes:x,edges:y,onBeforeDelete:w}),b=S.length>0,E=_.length>0;if(b){const A=S.map(Nf);k==null||k(S),g(A)}if(E){const A=_.map(Nf);v==null||v(_),m(A)}return(E||b)&&(h==null||h({nodes:_,edges:S})),{deletedNodes:_,deletedEdges:S}},getIntersectingNodes:(c,f=!0,x)=>{const y=of(c),v=y?c:a(c),k=x!==void 0;return v?(x||t.getState().nodes).filter(m=>{const g=t.getState().nodeLookup.get(m.id);if(g&&!y&&(m.id===c.id||!g.internals.positionAbsolute))return!1;const h=kr(k?m:g),w=Lo(h,v);return f&&w>0||w>=h.width*h.height||w>=v.width*v.height}):[]},isNodeIntersecting:(c,f,x=!0)=>{const v=of(c)?c:a(c);if(!v)return!1;const k=Lo(v,f);return x&&k>0||k>=f.width*f.height||k>=v.width*v.height},updateNode:u,updateNodeData:(c,f,x={replace:!1})=>{u(c,y=>{const v=typeof f=="function"?f(y):f;return x.replace?{...y,data:v}:{...y,data:{...y.data,...v}}},x)},updateEdge:p,updateEdgeData:(c,f,x={replace:!1})=>{p(c,y=>{const v=typeof f=="function"?f(y):f;return x.replace?{...y,data:v}:{...y,data:{...y.data,...v}}},x)},getNodesBounds:c=>{const{nodeLookup:f,nodeOrigin:x}=t.getState();return vS(c,{nodeLookup:f,nodeOrigin:x})},getHandleConnections:({type:c,id:f,nodeId:x})=>{var y;return Array.from(((y=t.getState().connectionLookup.get(`${x}-${c}${f?`-${f}`:""}`))==null?void 0:y.values())??[])},getNodeConnections:({type:c,handleId:f,nodeId:x})=>{var y;return Array.from(((y=t.getState().connectionLookup.get(`${x}${c?f?`-${c}-${f}`:`-${c}`:""}`))==null?void 0:y.values())??[])},fitView:async c=>{const f=t.getState().fitViewResolver??jS();return t.setState({fitViewQueued:!0,fitViewOptions:c,fitViewResolver:f}),n.nodeQueue.push(x=>[...x]),f.promise}}},[]);return M.useMemo(()=>({...o,...e,viewportInitialized:r}),[r])}const Tf=e=>e.selected,y_=typeof window<"u"?window:void 0;function x_({deleteKeyCode:e,multiSelectionKeyCode:t}){const n=pe(),{deleteElements:r}=xc(),o=$o(e,{actInsideInputWithModifier:!1}),i=$o(t,{target:y_});M.useEffect(()=>{if(o){const{edges:s,nodes:l}=n.getState();r({nodes:l.filter(Tf),edges:s.filter(Tf)}),n.setState({nodesSelectionActive:!1})}},[o]),M.useEffect(()=>{n.setState({multiSelectionActive:i})},[i])}function v_(e){const t=pe();M.useEffect(()=>{const n=()=>{var o,i,s,l;if(!e.current||!(((i=(o=e.current).checkVisibility)==null?void 0:i.call(o))??!0))return!1;const r=fc(e.current);(r.height===0||r.width===0)&&((l=(s=t.getState()).onError)==null||l.call(s,"004",Et.error004())),t.setState({width:r.width||500,height:r.height||500})};if(e.current){n(),window.addEventListener("resize",n);const r=new ResizeObserver(()=>n());return r.observe(e.current),()=>{window.removeEventListener("resize",n),r&&e.current&&r.unobserve(e.current)}}},[])}const tl={position:"absolute",width:"100%",height:"100%",top:0,left:0},w_=e=>({userSelectionActive:e.userSelectionActive,lib:e.lib,connectionInProgress:e.connection.inProgress});function S_({onPaneContextMenu:e,zoomOnScroll:t=!0,zoomOnPinch:n=!0,panOnScroll:r=!1,panOnScrollSpeed:o=.5,panOnScrollMode:i=En.Free,zoomOnDoubleClick:s=!0,panOnDrag:l=!0,defaultViewport:a,translateExtent:u,minZoom:p,maxZoom:c,zoomActivationKeyCode:f,preventScrolling:x=!0,children:y,noWheelClassName:v,noPanClassName:k,onViewportChange:m,isControlledViewport:g,paneClickDistance:h,selectionOnDrag:w}){const _=pe(),S=M.useRef(null),{userSelectionActive:b,lib:E,connectionInProgress:A}=ne(w_,fe),D=$o(f),P=M.useRef();v_(S);const I=M.useCallback(T=>{m==null||m({x:T[0],y:T[1],zoom:T[2]}),g||_.setState({transform:T})},[m,g]);return M.useEffect(()=>{if(S.current){P.current=ck({domNode:S.current,minZoom:p,maxZoom:c,translateExtent:u,viewport:a,onDraggingChange:z=>_.setState(R=>R.paneDragging===z?R:{paneDragging:z}),onPanZoomStart:(z,R)=>{const{onViewportChangeStart:j,onMoveStart:N}=_.getState();N==null||N(z,R),j==null||j(R)},onPanZoom:(z,R)=>{const{onViewportChange:j,onMove:N}=_.getState();N==null||N(z,R),j==null||j(R)},onPanZoomEnd:(z,R)=>{const{onViewportChangeEnd:j,onMoveEnd:N}=_.getState();N==null||N(z,R),j==null||j(R)}});const{x:T,y:C,zoom:L}=P.current.getViewport();return _.setState({panZoom:P.current,transform:[T,C,L],domNode:S.current.closest(".react-flow")}),()=>{var z;(z=P.current)==null||z.destroy()}}},[]),M.useEffect(()=>{var T;(T=P.current)==null||T.update({onPaneContextMenu:e,zoomOnScroll:t,zoomOnPinch:n,panOnScroll:r,panOnScrollSpeed:o,panOnScrollMode:i,zoomOnDoubleClick:s,panOnDrag:l,zoomActivationKeyPressed:D,preventScrolling:x,noPanClassName:k,userSelectionActive:b,noWheelClassName:v,lib:E,onTransformChange:I,connectionInProgress:A,selectionOnDrag:w,paneClickDistance:h})},[e,t,n,r,o,i,s,l,D,x,k,b,v,E,I,A,w,h]),d.jsx("div",{className:"react-flow__renderer",ref:S,style:tl,children:y})}const k_=e=>({userSelectionActive:e.userSelectionActive,userSelectionRect:e.userSelectionRect});function __(){const{userSelectionActive:e,userSelectionRect:t}=ne(k_,fe);return e&&t?d.jsx("div",{className:"react-flow__selection react-flow__container",style:{width:t.width,height:t.height,transform:`translate(${t.x}px, ${t.y}px)`}}):null}const Bl=(e,t)=>n=>{n.target===t.current&&(e==null||e(n))},b_=e=>({userSelectionActive:e.userSelectionActive,elementsSelectable:e.elementsSelectable,connectionInProgress:e.connection.inProgress,dragging:e.paneDragging});function C_({isSelecting:e,selectionKeyPressed:t,selectionMode:n=Ro.Full,panOnDrag:r,paneClickDistance:o,selectionOnDrag:i,onSelectionStart:s,onSelectionEnd:l,onPaneClick:a,onPaneContextMenu:u,onPaneScroll:p,onPaneMouseEnter:c,onPaneMouseMove:f,onPaneMouseLeave:x,children:y}){const v=pe(),{userSelectionActive:k,elementsSelectable:m,dragging:g,connectionInProgress:h}=ne(b_,fe),w=m&&(e||k),_=M.useRef(null),S=M.useRef(),b=M.useRef(new Set),E=M.useRef(new Set),A=M.useRef(!1),D=j=>{if(A.current||h){A.current=!1;return}a==null||a(j),v.getState().resetSelectedElements(),v.setState({nodesSelectionActive:!1})},P=j=>{if(Array.isArray(r)&&(r!=null&&r.includes(2))){j.preventDefault();return}u==null||u(j)},I=p?j=>p(j):void 0,T=j=>{A.current&&(j.stopPropagation(),A.current=!1)},C=j=>{var Y,X;const{domNode:N}=v.getState();if(S.current=N==null?void 0:N.getBoundingClientRect(),!S.current)return;const $=j.target===_.current;if(!$&&!!j.target.closest(".nokey")||!e||!(i&&$||t)||j.button!==0||!j.isPrimary)return;(X=(Y=j.target)==null?void 0:Y.setPointerCapture)==null||X.call(Y,j.pointerId),A.current=!1;const{x:W,y:V}=dt(j.nativeEvent,S.current);v.setState({userSelectionRect:{width:0,height:0,startX:W,startY:V,x:W,y:V}}),$||(j.stopPropagation(),j.preventDefault())},L=j=>{const{userSelectionRect:N,transform:$,nodeLookup:O,edgeLookup:B,connectionLookup:W,triggerNodeChanges:V,triggerEdgeChanges:Y,defaultEdgeOptions:X,resetSelectedElements:Q}=v.getState();if(!S.current||!N)return;const{x:H,y:K}=dt(j.nativeEvent,S.current),{startX:ee,startY:G}=N;if(!A.current){const ie=t?0:o;if(Math.hypot(H-ee,K-G)<=ie)return;Q(),s==null||s(j)}A.current=!0;const J={startX:ee,startY:G,x:Hie.id)),E.current=new Set;const le=(X==null?void 0:X.selectable)??!0;for(const ie of b.current){const Ne=W.get(ie);if(Ne)for(const{edgeId:Vt}of Ne.values()){const Nt=B.get(Vt);Nt&&(Nt.selectable??le)&&E.current.add(Vt)}}if(!sf(Z,b.current)){const ie=nr(O,b.current,!0);V(ie)}if(!sf(re,E.current)){const ie=nr(B,E.current);Y(ie)}v.setState({userSelectionRect:J,userSelectionActive:!0,nodesSelectionActive:!1})},z=j=>{var N,$;j.button===0&&(($=(N=j.target)==null?void 0:N.releasePointerCapture)==null||$.call(N,j.pointerId),!k&&j.target===_.current&&v.getState().userSelectionRect&&(D==null||D(j)),v.setState({userSelectionActive:!1,userSelectionRect:null}),A.current&&(l==null||l(j),v.setState({nodesSelectionActive:b.current.size>0})))},R=r===!0||Array.isArray(r)&&r.includes(0);return d.jsxs("div",{className:we(["react-flow__pane",{draggable:R,dragging:g,selection:e}]),onClick:w?void 0:Bl(D,_),onContextMenu:Bl(P,_),onWheel:Bl(I,_),onPointerEnter:w?void 0:c,onPointerMove:w?L:f,onPointerUp:w?z:void 0,onPointerDownCapture:w?C:void 0,onClickCapture:w?T:void 0,onPointerLeave:x,ref:_,style:tl,children:[y,d.jsx(__,{})]})}function ru({id:e,store:t,unselect:n=!1,nodeRef:r}){const{addSelectedNodes:o,unselectNodesAndEdges:i,multiSelectionActive:s,nodeLookup:l,onError:a}=t.getState(),u=l.get(e);if(!u){a==null||a("012",Et.error012(e));return}t.setState({nodesSelectionActive:!1}),u.selected?(n||u.selected&&s)&&(i({nodes:[u],edges:[]}),requestAnimationFrame(()=>{var p;return(p=r==null?void 0:r.current)==null?void 0:p.blur()})):o([e])}function Am({nodeRef:e,disabled:t=!1,noDragClassName:n,handleSelector:r,nodeId:o,isSelectable:i,nodeClickDistance:s}){const l=pe(),[a,u]=M.useState(!1),p=M.useRef();return M.useEffect(()=>{p.current=KS({getStoreItems:()=>l.getState(),onNodeMouseDown:c=>{ru({id:c,store:l,nodeRef:e})},onDragStart:()=>{u(!0)},onDragStop:()=>{u(!1)}})},[]),M.useEffect(()=>{if(!(t||!e.current||!p.current))return p.current.update({noDragClassName:n,handleSelector:r,domNode:e.current,isSelectable:i,nodeId:o,nodeClickDistance:s}),()=>{var c;(c=p.current)==null||c.destroy()}},[n,r,t,i,e,o,s]),a}const E_=e=>t=>t.selected&&(t.draggable||e&&typeof t.draggable>"u");function $m(){const e=pe();return M.useCallback(n=>{const{nodeExtent:r,snapToGrid:o,snapGrid:i,nodesDraggable:s,onError:l,updateNodePositions:a,nodeLookup:u,nodeOrigin:p}=e.getState(),c=new Map,f=E_(s),x=o?i[0]:5,y=o?i[1]:5,v=n.direction.x*x*n.factor,k=n.direction.y*y*n.factor;for(const[,m]of u){if(!f(m))continue;let g={x:m.internals.positionAbsolute.x+v,y:m.internals.positionAbsolute.y+k};o&&(g=Qo(g,i));const{position:h,positionAbsolute:w}=qg({nodeId:m.id,nextPosition:g,nodeLookup:u,nodeExtent:r,nodeOrigin:p,onError:l});m.position=h,m.internals.positionAbsolute=w,c.set(m.id,m)}a(c)},[])}const vc=M.createContext(null),j_=vc.Provider;vc.Consumer;const Dm=()=>M.useContext(vc),N_=e=>({connectOnClick:e.connectOnClick,noPanClassName:e.noPanClassName,rfId:e.rfId}),M_=(e,t,n)=>r=>{const{connectionClickStartHandle:o,connectionMode:i,connection:s}=r,{fromHandle:l,toHandle:a,isValid:u}=s,p=(a==null?void 0:a.nodeId)===e&&(a==null?void 0:a.id)===t&&(a==null?void 0:a.type)===n;return{connectingFrom:(l==null?void 0:l.nodeId)===e&&(l==null?void 0:l.id)===t&&(l==null?void 0:l.type)===n,connectingTo:p,clickConnecting:(o==null?void 0:o.nodeId)===e&&(o==null?void 0:o.id)===t&&(o==null?void 0:o.type)===n,isPossibleEndHandle:i===wr.Strict?(l==null?void 0:l.type)!==n:e!==(l==null?void 0:l.nodeId)||t!==(l==null?void 0:l.id),connectionInProcess:!!l,clickConnectionInProcess:!!o,valid:p&&u}};function z_({type:e="source",position:t=q.Top,isValidConnection:n,isConnectable:r=!0,isConnectableStart:o=!0,isConnectableEnd:i=!0,id:s,onConnect:l,children:a,className:u,onMouseDown:p,onTouchStart:c,...f},x){var L,z;const y=s||null,v=e==="target",k=pe(),m=Dm(),{connectOnClick:g,noPanClassName:h,rfId:w}=ne(N_,fe),{connectingFrom:_,connectingTo:S,clickConnecting:b,isPossibleEndHandle:E,connectionInProcess:A,clickConnectionInProcess:D,valid:P}=ne(M_(m,y,e),fe);m||(z=(L=k.getState()).onError)==null||z.call(L,"010",Et.error010());const I=R=>{const{defaultEdgeOptions:j,onConnect:N,hasDefaultEdges:$}=k.getState(),O={...j,...R};if($){const{edges:B,setEdges:W}=k.getState();W(RS(O,B))}N==null||N(O),l==null||l(O)},T=R=>{if(!m)return;const j=sm(R.nativeEvent);if(o&&(j&&R.button===0||!j)){const N=k.getState();nu.onPointerDown(R.nativeEvent,{handleDomNode:R.currentTarget,autoPanOnConnect:N.autoPanOnConnect,connectionMode:N.connectionMode,connectionRadius:N.connectionRadius,domNode:N.domNode,nodeLookup:N.nodeLookup,lib:N.lib,isTarget:v,handleId:y,nodeId:m,flowId:N.rfId,panBy:N.panBy,cancelConnection:N.cancelConnection,onConnectStart:N.onConnectStart,onConnectEnd:(...$)=>{var O,B;return(B=(O=k.getState()).onConnectEnd)==null?void 0:B.call(O,...$)},updateConnection:N.updateConnection,onConnect:I,isValidConnection:n||((...$)=>{var O,B;return((B=(O=k.getState()).isValidConnection)==null?void 0:B.call(O,...$))??!0}),getTransform:()=>k.getState().transform,getFromHandle:()=>k.getState().connection.fromHandle,autoPanSpeed:N.autoPanSpeed,dragThreshold:N.connectionDragThreshold})}j?p==null||p(R):c==null||c(R)},C=R=>{const{onClickConnectStart:j,onClickConnectEnd:N,connectionClickStartHandle:$,connectionMode:O,isValidConnection:B,lib:W,rfId:V,nodeLookup:Y,connection:X}=k.getState();if(!m||!$&&!o)return;if(!$){j==null||j(R.nativeEvent,{nodeId:m,handleId:y,handleType:e}),k.setState({connectionClickStartHandle:{nodeId:m,type:e,id:y}});return}const Q=om(R.target),H=n||B,{connection:K,isValid:ee}=nu.isValid(R.nativeEvent,{handle:{nodeId:m,id:y,type:e},connectionMode:O,fromNodeId:$.nodeId,fromHandleId:$.id||null,fromType:$.type,isValidConnection:H,flowId:V,doc:Q,lib:W,nodeLookup:Y});ee&&K&&I(K);const G=structuredClone(X);delete G.inProgress,G.toPosition=G.toHandle?G.toHandle.position:null,N==null||N(R,G),k.setState({connectionClickStartHandle:null})};return d.jsx("div",{"data-handleid":y,"data-nodeid":m,"data-handlepos":t,"data-id":`${w}-${m}-${y}-${e}`,className:we(["react-flow__handle",`react-flow__handle-${t}`,"nodrag",h,u,{source:!v,target:v,connectable:r,connectablestart:o,connectableend:i,clickconnecting:b,connectingfrom:_,connectingto:S,valid:P,connectionindicator:r&&(!A||E)&&(A||D?i:o)}]),onMouseDown:T,onTouchStart:T,onClick:g?C:void 0,ref:x,...f,children:a})}const Cr=M.memo(Rm(z_));function T_({data:e,isConnectable:t,sourcePosition:n=q.Bottom}){return d.jsxs(d.Fragment,{children:[e==null?void 0:e.label,d.jsx(Cr,{type:"source",position:n,isConnectable:t})]})}function P_({data:e,isConnectable:t,targetPosition:n=q.Top,sourcePosition:r=q.Bottom}){return d.jsxs(d.Fragment,{children:[d.jsx(Cr,{type:"target",position:n,isConnectable:t}),e==null?void 0:e.label,d.jsx(Cr,{type:"source",position:r,isConnectable:t})]})}function I_(){return null}function R_({data:e,isConnectable:t,targetPosition:n=q.Top}){return d.jsxs(d.Fragment,{children:[d.jsx(Cr,{type:"target",position:n,isConnectable:t}),e==null?void 0:e.label]})}const js={ArrowUp:{x:0,y:-1},ArrowDown:{x:0,y:1},ArrowLeft:{x:-1,y:0},ArrowRight:{x:1,y:0}},Pf={input:T_,default:P_,output:R_,group:I_};function L_(e){var t,n,r,o;return e.internals.handleBounds===void 0?{width:e.width??e.initialWidth??((t=e.style)==null?void 0:t.width),height:e.height??e.initialHeight??((n=e.style)==null?void 0:n.height)}:{width:e.width??((r=e.style)==null?void 0:r.width),height:e.height??((o=e.style)==null?void 0:o.height)}}const A_=e=>{const{width:t,height:n,x:r,y:o}=Xo(e.nodeLookup,{filter:i=>!!i.selected});return{width:ct(t)?t:null,height:ct(n)?n:null,userSelectionActive:e.userSelectionActive,transformString:`translate(${e.transform[0]}px,${e.transform[1]}px) scale(${e.transform[2]}) translate(${r}px,${o}px)`}};function $_({onSelectionContextMenu:e,noPanClassName:t,disableKeyboardA11y:n}){const r=pe(),{width:o,height:i,transformString:s,userSelectionActive:l}=ne(A_,fe),a=$m(),u=M.useRef(null);M.useEffect(()=>{var x;n||(x=u.current)==null||x.focus({preventScroll:!0})},[n]);const p=!l&&o!==null&&i!==null;if(Am({nodeRef:u,disabled:!p}),!p)return null;const c=e?x=>{const y=r.getState().nodes.filter(v=>v.selected);e(x,y)}:void 0,f=x=>{Object.prototype.hasOwnProperty.call(js,x.key)&&(x.preventDefault(),a({direction:js[x.key],factor:x.shiftKey?4:1}))};return d.jsx("div",{className:we(["react-flow__nodesselection","react-flow__container",t]),style:{transform:s},children:d.jsx("div",{ref:u,className:"react-flow__nodesselection-rect",onContextMenu:c,tabIndex:n?void 0:-1,onKeyDown:n?void 0:f,style:{width:o,height:i}})})}const If=typeof window<"u"?window:void 0,D_=e=>({nodesSelectionActive:e.nodesSelectionActive,userSelectionActive:e.userSelectionActive});function Om({children:e,onPaneClick:t,onPaneMouseEnter:n,onPaneMouseMove:r,onPaneMouseLeave:o,onPaneContextMenu:i,onPaneScroll:s,paneClickDistance:l,deleteKeyCode:a,selectionKeyCode:u,selectionOnDrag:p,selectionMode:c,onSelectionStart:f,onSelectionEnd:x,multiSelectionKeyCode:y,panActivationKeyCode:v,zoomActivationKeyCode:k,elementsSelectable:m,zoomOnScroll:g,zoomOnPinch:h,panOnScroll:w,panOnScrollSpeed:_,panOnScrollMode:S,zoomOnDoubleClick:b,panOnDrag:E,defaultViewport:A,translateExtent:D,minZoom:P,maxZoom:I,preventScrolling:T,onSelectionContextMenu:C,noWheelClassName:L,noPanClassName:z,disableKeyboardA11y:R,onViewportChange:j,isControlledViewport:N}){const{nodesSelectionActive:$,userSelectionActive:O}=ne(D_,fe),B=$o(u,{target:If}),W=$o(v,{target:If}),V=W||E,Y=W||w,X=p&&V!==!0,Q=B||O||X;return x_({deleteKeyCode:a,multiSelectionKeyCode:y}),d.jsx(S_,{onPaneContextMenu:i,elementsSelectable:m,zoomOnScroll:g,zoomOnPinch:h,panOnScroll:Y,panOnScrollSpeed:_,panOnScrollMode:S,zoomOnDoubleClick:b,panOnDrag:!B&&V,defaultViewport:A,translateExtent:D,minZoom:P,maxZoom:I,zoomActivationKeyCode:k,preventScrolling:T,noWheelClassName:L,noPanClassName:z,onViewportChange:j,isControlledViewport:N,paneClickDistance:l,selectionOnDrag:X,children:d.jsxs(C_,{onSelectionStart:f,onSelectionEnd:x,onPaneClick:t,onPaneMouseEnter:n,onPaneMouseMove:r,onPaneMouseLeave:o,onPaneContextMenu:i,onPaneScroll:s,panOnDrag:V,isSelecting:!!Q,selectionMode:c,selectionKeyPressed:B,paneClickDistance:l,selectionOnDrag:X,children:[e,$&&d.jsx($_,{onSelectionContextMenu:C,noPanClassName:z,disableKeyboardA11y:R})]})})}Om.displayName="FlowRenderer";const O_=M.memo(Om),B_=e=>t=>e?cc(t.nodeLookup,{x:0,y:0,width:t.width,height:t.height},t.transform,!0).map(n=>n.id):Array.from(t.nodeLookup.keys());function F_(e){return ne(M.useCallback(B_(e),[e]),fe)}const H_=e=>e.updateNodeInternals;function V_(){const e=ne(H_),[t]=M.useState(()=>typeof ResizeObserver>"u"?null:new ResizeObserver(n=>{const r=new Map;n.forEach(o=>{const i=o.target.getAttribute("data-id");r.set(i,{id:i,nodeElement:o.target,force:!0})}),e(r)}));return M.useEffect(()=>()=>{t==null||t.disconnect()},[t]),t}function W_({node:e,nodeType:t,hasDimensions:n,resizeObserver:r}){const o=pe(),i=M.useRef(null),s=M.useRef(null),l=M.useRef(e.sourcePosition),a=M.useRef(e.targetPosition),u=M.useRef(t),p=n&&!!e.internals.handleBounds;return M.useEffect(()=>{i.current&&!e.hidden&&(!p||s.current!==i.current)&&(s.current&&(r==null||r.unobserve(s.current)),r==null||r.observe(i.current),s.current=i.current)},[p,e.hidden]),M.useEffect(()=>()=>{s.current&&(r==null||r.unobserve(s.current),s.current=null)},[]),M.useEffect(()=>{if(i.current){const c=u.current!==t,f=l.current!==e.sourcePosition,x=a.current!==e.targetPosition;(c||f||x)&&(u.current=t,l.current=e.sourcePosition,a.current=e.targetPosition,o.getState().updateNodeInternals(new Map([[e.id,{id:e.id,nodeElement:i.current,force:!0}]])))}},[e.id,t,e.sourcePosition,e.targetPosition]),i}function U_({id:e,onClick:t,onMouseEnter:n,onMouseMove:r,onMouseLeave:o,onContextMenu:i,onDoubleClick:s,nodesDraggable:l,elementsSelectable:a,nodesConnectable:u,nodesFocusable:p,resizeObserver:c,noDragClassName:f,noPanClassName:x,disableKeyboardA11y:y,rfId:v,nodeTypes:k,nodeClickDistance:m,onError:g}){const{node:h,internals:w,isParent:_}=ne(H=>{const K=H.nodeLookup.get(e),ee=H.parentLookup.has(e);return{node:K,internals:K.internals,isParent:ee}},fe);let S=h.type||"default",b=(k==null?void 0:k[S])||Pf[S];b===void 0&&(g==null||g("003",Et.error003(S)),S="default",b=(k==null?void 0:k.default)||Pf.default);const E=!!(h.draggable||l&&typeof h.draggable>"u"),A=!!(h.selectable||a&&typeof h.selectable>"u"),D=!!(h.connectable||u&&typeof h.connectable>"u"),P=!!(h.focusable||p&&typeof h.focusable>"u"),I=pe(),T=nm(h),C=W_({node:h,nodeType:S,hasDimensions:T,resizeObserver:c}),L=Am({nodeRef:C,disabled:h.hidden||!E,noDragClassName:f,handleSelector:h.dragHandle,nodeId:e,isSelectable:A,nodeClickDistance:m}),z=$m();if(h.hidden)return null;const R=Ht(h),j=L_(h),N=A||E||t||n||r||o,$=n?H=>n(H,{...w.userNode}):void 0,O=r?H=>r(H,{...w.userNode}):void 0,B=o?H=>o(H,{...w.userNode}):void 0,W=i?H=>i(H,{...w.userNode}):void 0,V=s?H=>s(H,{...w.userNode}):void 0,Y=H=>{const{selectNodesOnDrag:K,nodeDragThreshold:ee}=I.getState();A&&(!K||!E||ee>0)&&ru({id:e,store:I,nodeRef:C}),t&&t(H,{...w.userNode})},X=H=>{if(!(im(H.nativeEvent)||y)){if(Xg.includes(H.key)&&A){const K=H.key==="Escape";ru({id:e,store:I,unselect:K,nodeRef:C})}else if(E&&h.selected&&Object.prototype.hasOwnProperty.call(js,H.key)){H.preventDefault();const{ariaLabelConfig:K}=I.getState();I.setState({ariaLiveMessage:K["node.a11yDescription.ariaLiveMessage"]({direction:H.key.replace("Arrow","").toLowerCase(),x:~~w.positionAbsolute.x,y:~~w.positionAbsolute.y})}),z({direction:js[H.key],factor:H.shiftKey?4:1})}}},Q=()=>{var re;if(y||!((re=C.current)!=null&&re.matches(":focus-visible")))return;const{transform:H,width:K,height:ee,autoPanOnNodeFocus:G,setCenter:J}=I.getState();if(!G)return;cc(new Map([[e,h]]),{x:0,y:0,width:K,height:ee},H,!0).length>0||J(h.position.x+R.width/2,h.position.y+R.height/2,{zoom:H[2]})};return d.jsx("div",{className:we(["react-flow__node",`react-flow__node-${S}`,{[x]:E},h.className,{selected:h.selected,selectable:A,parent:_,draggable:E,dragging:L}]),ref:C,style:{zIndex:w.z,transform:`translate(${w.positionAbsolute.x}px,${w.positionAbsolute.y}px)`,pointerEvents:N?"all":"none",visibility:T?"visible":"hidden",...h.style,...j},"data-id":e,"data-testid":`rf__node-${e}`,onMouseEnter:$,onMouseMove:O,onMouseLeave:B,onContextMenu:W,onClick:Y,onDoubleClick:V,onKeyDown:P?X:void 0,tabIndex:P?0:void 0,onFocus:P?Q:void 0,role:h.ariaRole??(P?"group":void 0),"aria-roledescription":"node","aria-describedby":y?void 0:`${Nm}-${v}`,"aria-label":h.ariaLabel,...h.domAttributes,children:d.jsx(j_,{value:e,children:d.jsx(b,{id:e,data:h.data,type:S,positionAbsoluteX:w.positionAbsolute.x,positionAbsoluteY:w.positionAbsolute.y,selected:h.selected??!1,selectable:A,draggable:E,deletable:h.deletable??!0,isConnectable:D,sourcePosition:h.sourcePosition,targetPosition:h.targetPosition,dragging:L,dragHandle:h.dragHandle,zIndex:w.z,parentId:h.parentId,...R})})})}var Y_=M.memo(U_);const X_=e=>({nodesDraggable:e.nodesDraggable,nodesConnectable:e.nodesConnectable,nodesFocusable:e.nodesFocusable,elementsSelectable:e.elementsSelectable,onError:e.onError});function Bm(e){const{nodesDraggable:t,nodesConnectable:n,nodesFocusable:r,elementsSelectable:o,onError:i}=ne(X_,fe),s=F_(e.onlyRenderVisibleElements),l=V_();return d.jsx("div",{className:"react-flow__nodes",style:tl,children:s.map(a=>d.jsx(Y_,{id:a,nodeTypes:e.nodeTypes,nodeExtent:e.nodeExtent,onClick:e.onNodeClick,onMouseEnter:e.onNodeMouseEnter,onMouseMove:e.onNodeMouseMove,onMouseLeave:e.onNodeMouseLeave,onContextMenu:e.onNodeContextMenu,onDoubleClick:e.onNodeDoubleClick,noDragClassName:e.noDragClassName,noPanClassName:e.noPanClassName,rfId:e.rfId,disableKeyboardA11y:e.disableKeyboardA11y,resizeObserver:l,nodesDraggable:t,nodesConnectable:n,nodesFocusable:r,elementsSelectable:o,nodeClickDistance:e.nodeClickDistance,onError:i},a))})}Bm.displayName="NodeRenderer";const Q_=M.memo(Bm);function G_(e){return ne(M.useCallback(n=>{if(!e)return n.edges.map(o=>o.id);const r=[];if(n.width&&n.height)for(const o of n.edges){const i=n.nodeLookup.get(o.source),s=n.nodeLookup.get(o.target);i&&s&&TS({sourceNode:i,targetNode:s,width:n.width,height:n.height,transform:n.transform})&&r.push(o.id)}return r},[e]),fe)}const K_=({color:e="none",strokeWidth:t=1})=>{const n={strokeWidth:t,...e&&{stroke:e}};return d.jsx("polyline",{className:"arrow",style:n,strokeLinecap:"round",fill:"none",strokeLinejoin:"round",points:"-5,-4 0,0 -5,4"})},Z_=({color:e="none",strokeWidth:t=1})=>{const n={strokeWidth:t,...e&&{stroke:e,fill:e}};return d.jsx("polyline",{className:"arrowclosed",style:n,strokeLinecap:"round",strokeLinejoin:"round",points:"-5,-4 0,0 -5,4 -5,-4"})},Rf={[bs.Arrow]:K_,[bs.ArrowClosed]:Z_};function q_(e){const t=pe();return M.useMemo(()=>{var o,i;return Object.prototype.hasOwnProperty.call(Rf,e)?Rf[e]:((i=(o=t.getState()).onError)==null||i.call(o,"009",Et.error009(e)),null)},[e])}const J_=({id:e,type:t,color:n,width:r=12.5,height:o=12.5,markerUnits:i="strokeWidth",strokeWidth:s,orient:l="auto-start-reverse"})=>{const a=q_(t);return a?d.jsx("marker",{className:"react-flow__arrowhead",id:e,markerWidth:`${r}`,markerHeight:`${o}`,viewBox:"-10 -10 20 20",markerUnits:i,orient:l,refX:"0",refY:"0",children:d.jsx(a,{color:n,strokeWidth:s})}):null},Fm=({defaultColor:e,rfId:t})=>{const n=ne(i=>i.edges),r=ne(i=>i.defaultEdgeOptions),o=M.useMemo(()=>OS(n,{id:t,defaultColor:e,defaultMarkerStart:r==null?void 0:r.markerStart,defaultMarkerEnd:r==null?void 0:r.markerEnd}),[n,r,t,e]);return o.length?d.jsx("svg",{className:"react-flow__marker","aria-hidden":"true",children:d.jsx("defs",{children:o.map(i=>d.jsx(J_,{id:i.id,type:i.type,color:i.color,width:i.width,height:i.height,markerUnits:i.markerUnits,strokeWidth:i.strokeWidth,orient:i.orient},i.id))})}):null};Fm.displayName="MarkerDefinitions";var eb=M.memo(Fm);function Hm({x:e,y:t,label:n,labelStyle:r,labelShowBg:o=!0,labelBgStyle:i,labelBgPadding:s=[2,4],labelBgBorderRadius:l=2,children:a,className:u,...p}){const[c,f]=M.useState({x:1,y:0,width:0,height:0}),x=we(["react-flow__edge-textwrapper",u]),y=M.useRef(null);return M.useEffect(()=>{if(y.current){const v=y.current.getBBox();f({x:v.x,y:v.y,width:v.width,height:v.height})}},[n]),n?d.jsxs("g",{transform:`translate(${e-c.width/2} ${t-c.height/2})`,className:x,visibility:c.width?"visible":"hidden",...p,children:[o&&d.jsx("rect",{width:c.width+2*s[0],x:-s[0],y:-s[1],height:c.height+2*s[1],className:"react-flow__edge-textbg",style:i,rx:l,ry:l}),d.jsx("text",{className:"react-flow__edge-text",y:c.height/2,dy:"0.3em",ref:y,style:r,children:n}),a]}):null}Hm.displayName="EdgeText";const tb=M.memo(Hm);function nl({path:e,labelX:t,labelY:n,label:r,labelStyle:o,labelShowBg:i,labelBgStyle:s,labelBgPadding:l,labelBgBorderRadius:a,interactionWidth:u=20,...p}){return d.jsxs(d.Fragment,{children:[d.jsx("path",{...p,d:e,fill:"none",className:we(["react-flow__edge-path",p.className])}),u?d.jsx("path",{d:e,fill:"none",strokeOpacity:0,strokeWidth:u,className:"react-flow__edge-interaction"}):null,r&&ct(t)&&ct(n)?d.jsx(tb,{x:t,y:n,label:r,labelStyle:o,labelShowBg:i,labelBgStyle:s,labelBgPadding:l,labelBgBorderRadius:a}):null]})}function Lf({pos:e,x1:t,y1:n,x2:r,y2:o}){return e===q.Left||e===q.Right?[.5*(t+r),n]:[t,.5*(n+o)]}function Vm({sourceX:e,sourceY:t,sourcePosition:n=q.Bottom,targetX:r,targetY:o,targetPosition:i=q.Top}){const[s,l]=Lf({pos:n,x1:e,y1:t,x2:r,y2:o}),[a,u]=Lf({pos:i,x1:r,y1:o,x2:e,y2:t}),[p,c,f,x]=lm({sourceX:e,sourceY:t,targetX:r,targetY:o,sourceControlX:s,sourceControlY:l,targetControlX:a,targetControlY:u});return[`M${e},${t} C${s},${l} ${a},${u} ${r},${o}`,p,c,f,x]}function Wm(e){return M.memo(({id:t,sourceX:n,sourceY:r,targetX:o,targetY:i,sourcePosition:s,targetPosition:l,label:a,labelStyle:u,labelShowBg:p,labelBgStyle:c,labelBgPadding:f,labelBgBorderRadius:x,style:y,markerEnd:v,markerStart:k,interactionWidth:m})=>{const[g,h,w]=Vm({sourceX:n,sourceY:r,sourcePosition:s,targetX:o,targetY:i,targetPosition:l}),_=e.isInternal?void 0:t;return d.jsx(nl,{id:_,path:g,labelX:h,labelY:w,label:a,labelStyle:u,labelShowBg:p,labelBgStyle:c,labelBgPadding:f,labelBgBorderRadius:x,style:y,markerEnd:v,markerStart:k,interactionWidth:m})})}const nb=Wm({isInternal:!1}),Um=Wm({isInternal:!0});nb.displayName="SimpleBezierEdge";Um.displayName="SimpleBezierEdgeInternal";function Ym(e){return M.memo(({id:t,sourceX:n,sourceY:r,targetX:o,targetY:i,label:s,labelStyle:l,labelShowBg:a,labelBgStyle:u,labelBgPadding:p,labelBgBorderRadius:c,style:f,sourcePosition:x=q.Bottom,targetPosition:y=q.Top,markerEnd:v,markerStart:k,pathOptions:m,interactionWidth:g})=>{const[h,w,_]=Ja({sourceX:n,sourceY:r,sourcePosition:x,targetX:o,targetY:i,targetPosition:y,borderRadius:m==null?void 0:m.borderRadius,offset:m==null?void 0:m.offset,stepPosition:m==null?void 0:m.stepPosition}),S=e.isInternal?void 0:t;return d.jsx(nl,{id:S,path:h,labelX:w,labelY:_,label:s,labelStyle:l,labelShowBg:a,labelBgStyle:u,labelBgPadding:p,labelBgBorderRadius:c,style:f,markerEnd:v,markerStart:k,interactionWidth:g})})}const Xm=Ym({isInternal:!1}),Qm=Ym({isInternal:!0});Xm.displayName="SmoothStepEdge";Qm.displayName="SmoothStepEdgeInternal";function Gm(e){return M.memo(({id:t,...n})=>{var o;const r=e.isInternal?void 0:t;return d.jsx(Xm,{...n,id:r,pathOptions:M.useMemo(()=>{var i;return{borderRadius:0,offset:(i=n.pathOptions)==null?void 0:i.offset}},[(o=n.pathOptions)==null?void 0:o.offset])})})}const rb=Gm({isInternal:!1}),Km=Gm({isInternal:!0});rb.displayName="StepEdge";Km.displayName="StepEdgeInternal";function Zm(e){return M.memo(({id:t,sourceX:n,sourceY:r,targetX:o,targetY:i,label:s,labelStyle:l,labelShowBg:a,labelBgStyle:u,labelBgPadding:p,labelBgBorderRadius:c,style:f,markerEnd:x,markerStart:y,interactionWidth:v})=>{const[k,m,g]=cm({sourceX:n,sourceY:r,targetX:o,targetY:i}),h=e.isInternal?void 0:t;return d.jsx(nl,{id:h,path:k,labelX:m,labelY:g,label:s,labelStyle:l,labelShowBg:a,labelBgStyle:u,labelBgPadding:p,labelBgBorderRadius:c,style:f,markerEnd:x,markerStart:y,interactionWidth:v})})}const ob=Zm({isInternal:!1}),qm=Zm({isInternal:!0});ob.displayName="StraightEdge";qm.displayName="StraightEdgeInternal";function Jm(e){return M.memo(({id:t,sourceX:n,sourceY:r,targetX:o,targetY:i,sourcePosition:s=q.Bottom,targetPosition:l=q.Top,label:a,labelStyle:u,labelShowBg:p,labelBgStyle:c,labelBgPadding:f,labelBgBorderRadius:x,style:y,markerEnd:v,markerStart:k,pathOptions:m,interactionWidth:g})=>{const[h,w,_]=am({sourceX:n,sourceY:r,sourcePosition:s,targetX:o,targetY:i,targetPosition:l,curvature:m==null?void 0:m.curvature}),S=e.isInternal?void 0:t;return d.jsx(nl,{id:S,path:h,labelX:w,labelY:_,label:a,labelStyle:u,labelShowBg:p,labelBgStyle:c,labelBgPadding:f,labelBgBorderRadius:x,style:y,markerEnd:v,markerStart:k,interactionWidth:g})})}const ib=Jm({isInternal:!1}),e0=Jm({isInternal:!0});ib.displayName="BezierEdge";e0.displayName="BezierEdgeInternal";const Af={default:e0,straight:qm,step:Km,smoothstep:Qm,simplebezier:Um},$f={sourceX:null,sourceY:null,targetX:null,targetY:null,sourcePosition:null,targetPosition:null},sb=(e,t,n)=>n===q.Left?e-t:n===q.Right?e+t:e,lb=(e,t,n)=>n===q.Top?e-t:n===q.Bottom?e+t:e,Df="react-flow__edgeupdater";function Of({position:e,centerX:t,centerY:n,radius:r=10,onMouseDown:o,onMouseEnter:i,onMouseOut:s,type:l}){return d.jsx("circle",{onMouseDown:o,onMouseEnter:i,onMouseOut:s,className:we([Df,`${Df}-${l}`]),cx:sb(t,r,e),cy:lb(n,r,e),r,stroke:"transparent",fill:"transparent"})}function ab({isReconnectable:e,reconnectRadius:t,edge:n,sourceX:r,sourceY:o,targetX:i,targetY:s,sourcePosition:l,targetPosition:a,onReconnect:u,onReconnectStart:p,onReconnectEnd:c,setReconnecting:f,setUpdateHover:x}){const y=pe(),v=(w,_)=>{if(w.button!==0)return;const{autoPanOnConnect:S,domNode:b,connectionMode:E,connectionRadius:A,lib:D,onConnectStart:P,cancelConnection:I,nodeLookup:T,rfId:C,panBy:L,updateConnection:z}=y.getState(),R=_.type==="target",j=(O,B)=>{f(!1),c==null||c(O,n,_.type,B)},N=O=>u==null?void 0:u(n,O),$=(O,B)=>{f(!0),p==null||p(w,n,_.type),P==null||P(O,B)};nu.onPointerDown(w.nativeEvent,{autoPanOnConnect:S,connectionMode:E,connectionRadius:A,domNode:b,handleId:_.id,nodeId:_.nodeId,nodeLookup:T,isTarget:R,edgeUpdaterType:_.type,lib:D,flowId:C,cancelConnection:I,panBy:L,isValidConnection:(...O)=>{var B,W;return((W=(B=y.getState()).isValidConnection)==null?void 0:W.call(B,...O))??!0},onConnect:N,onConnectStart:$,onConnectEnd:(...O)=>{var B,W;return(W=(B=y.getState()).onConnectEnd)==null?void 0:W.call(B,...O)},onReconnectEnd:j,updateConnection:z,getTransform:()=>y.getState().transform,getFromHandle:()=>y.getState().connection.fromHandle,dragThreshold:y.getState().connectionDragThreshold,handleDomNode:w.currentTarget})},k=w=>v(w,{nodeId:n.target,id:n.targetHandle??null,type:"target"}),m=w=>v(w,{nodeId:n.source,id:n.sourceHandle??null,type:"source"}),g=()=>x(!0),h=()=>x(!1);return d.jsxs(d.Fragment,{children:[(e===!0||e==="source")&&d.jsx(Of,{position:l,centerX:r,centerY:o,radius:t,onMouseDown:k,onMouseEnter:g,onMouseOut:h,type:"source"}),(e===!0||e==="target")&&d.jsx(Of,{position:a,centerX:i,centerY:s,radius:t,onMouseDown:m,onMouseEnter:g,onMouseOut:h,type:"target"})]})}function ub({id:e,edgesFocusable:t,edgesReconnectable:n,elementsSelectable:r,onClick:o,onDoubleClick:i,onContextMenu:s,onMouseEnter:l,onMouseMove:a,onMouseLeave:u,reconnectRadius:p,onReconnect:c,onReconnectStart:f,onReconnectEnd:x,rfId:y,edgeTypes:v,noPanClassName:k,onError:m,disableKeyboardA11y:g}){let h=ne(J=>J.edgeLookup.get(e));const w=ne(J=>J.defaultEdgeOptions);h=w?{...w,...h}:h;let _=h.type||"default",S=(v==null?void 0:v[_])||Af[_];S===void 0&&(m==null||m("011",Et.error011(_)),_="default",S=(v==null?void 0:v.default)||Af.default);const b=!!(h.focusable||t&&typeof h.focusable>"u"),E=typeof c<"u"&&(h.reconnectable||n&&typeof h.reconnectable>"u"),A=!!(h.selectable||r&&typeof h.selectable>"u"),D=M.useRef(null),[P,I]=M.useState(!1),[T,C]=M.useState(!1),L=pe(),{zIndex:z,sourceX:R,sourceY:j,targetX:N,targetY:$,sourcePosition:O,targetPosition:B}=ne(M.useCallback(J=>{const Z=J.nodeLookup.get(h.source),re=J.nodeLookup.get(h.target);if(!Z||!re)return{zIndex:h.zIndex,...$f};const le=DS({id:e,sourceNode:Z,targetNode:re,sourceHandle:h.sourceHandle||null,targetHandle:h.targetHandle||null,connectionMode:J.connectionMode,onError:m});return{zIndex:zS({selected:h.selected,zIndex:h.zIndex,sourceNode:Z,targetNode:re,elevateOnSelect:J.elevateEdgesOnSelect,zIndexMode:J.zIndexMode}),...le||$f}},[h.source,h.target,h.sourceHandle,h.targetHandle,h.selected,h.zIndex]),fe),W=M.useMemo(()=>h.markerStart?`url('#${eu(h.markerStart,y)}')`:void 0,[h.markerStart,y]),V=M.useMemo(()=>h.markerEnd?`url('#${eu(h.markerEnd,y)}')`:void 0,[h.markerEnd,y]);if(h.hidden||R===null||j===null||N===null||$===null)return null;const Y=J=>{var ie;const{addSelectedEdges:Z,unselectNodesAndEdges:re,multiSelectionActive:le}=L.getState();A&&(L.setState({nodesSelectionActive:!1}),h.selected&&le?(re({nodes:[],edges:[h]}),(ie=D.current)==null||ie.blur()):Z([e])),o&&o(J,h)},X=i?J=>{i(J,{...h})}:void 0,Q=s?J=>{s(J,{...h})}:void 0,H=l?J=>{l(J,{...h})}:void 0,K=a?J=>{a(J,{...h})}:void 0,ee=u?J=>{u(J,{...h})}:void 0,G=J=>{var Z;if(!g&&Xg.includes(J.key)&&A){const{unselectNodesAndEdges:re,addSelectedEdges:le}=L.getState();J.key==="Escape"?((Z=D.current)==null||Z.blur(),re({edges:[h]})):le([e])}};return d.jsx("svg",{style:{zIndex:z},children:d.jsxs("g",{className:we(["react-flow__edge",`react-flow__edge-${_}`,h.className,k,{selected:h.selected,animated:h.animated,inactive:!A&&!o,updating:P,selectable:A}]),onClick:Y,onDoubleClick:X,onContextMenu:Q,onMouseEnter:H,onMouseMove:K,onMouseLeave:ee,onKeyDown:b?G:void 0,tabIndex:b?0:void 0,role:h.ariaRole??(b?"group":"img"),"aria-roledescription":"edge","data-id":e,"data-testid":`rf__edge-${e}`,"aria-label":h.ariaLabel===null?void 0:h.ariaLabel||`Edge from ${h.source} to ${h.target}`,"aria-describedby":b?`${Mm}-${y}`:void 0,ref:D,...h.domAttributes,children:[!T&&d.jsx(S,{id:e,source:h.source,target:h.target,type:h.type,selected:h.selected,animated:h.animated,selectable:A,deletable:h.deletable??!0,label:h.label,labelStyle:h.labelStyle,labelShowBg:h.labelShowBg,labelBgStyle:h.labelBgStyle,labelBgPadding:h.labelBgPadding,labelBgBorderRadius:h.labelBgBorderRadius,sourceX:R,sourceY:j,targetX:N,targetY:$,sourcePosition:O,targetPosition:B,data:h.data,style:h.style,sourceHandleId:h.sourceHandle,targetHandleId:h.targetHandle,markerStart:W,markerEnd:V,pathOptions:"pathOptions"in h?h.pathOptions:void 0,interactionWidth:h.interactionWidth}),E&&d.jsx(ab,{edge:h,isReconnectable:E,reconnectRadius:p,onReconnect:c,onReconnectStart:f,onReconnectEnd:x,sourceX:R,sourceY:j,targetX:N,targetY:$,sourcePosition:O,targetPosition:B,setUpdateHover:I,setReconnecting:C})]})})}var cb=M.memo(ub);const db=e=>({edgesFocusable:e.edgesFocusable,edgesReconnectable:e.edgesReconnectable,elementsSelectable:e.elementsSelectable,connectionMode:e.connectionMode,onError:e.onError});function t0({defaultMarkerColor:e,onlyRenderVisibleElements:t,rfId:n,edgeTypes:r,noPanClassName:o,onReconnect:i,onEdgeContextMenu:s,onEdgeMouseEnter:l,onEdgeMouseMove:a,onEdgeMouseLeave:u,onEdgeClick:p,reconnectRadius:c,onEdgeDoubleClick:f,onReconnectStart:x,onReconnectEnd:y,disableKeyboardA11y:v}){const{edgesFocusable:k,edgesReconnectable:m,elementsSelectable:g,onError:h}=ne(db,fe),w=G_(t);return d.jsxs("div",{className:"react-flow__edges",children:[d.jsx(eb,{defaultColor:e,rfId:n}),w.map(_=>d.jsx(cb,{id:_,edgesFocusable:k,edgesReconnectable:m,elementsSelectable:g,noPanClassName:o,onReconnect:i,onContextMenu:s,onMouseEnter:l,onMouseMove:a,onMouseLeave:u,onClick:p,reconnectRadius:c,onDoubleClick:f,onReconnectStart:x,onReconnectEnd:y,rfId:n,onError:h,edgeTypes:r,disableKeyboardA11y:v},_))]})}t0.displayName="EdgeRenderer";const fb=M.memo(t0),pb=e=>`translate(${e.transform[0]}px,${e.transform[1]}px) scale(${e.transform[2]})`;function hb({children:e}){const t=ne(pb);return d.jsx("div",{className:"react-flow__viewport xyflow__viewport react-flow__container",style:{transform:t},children:e})}function gb(e){const t=xc(),n=M.useRef(!1);M.useEffect(()=>{!n.current&&t.viewportInitialized&&e&&(setTimeout(()=>e(t),1),n.current=!0)},[e,t.viewportInitialized])}const mb=e=>{var t;return(t=e.panZoom)==null?void 0:t.syncViewport};function yb(e){const t=ne(mb),n=pe();return M.useEffect(()=>{e&&(t==null||t(e),n.setState({transform:[e.x,e.y,e.zoom]}))},[e,t]),null}function xb(e){return e.connection.inProgress?{...e.connection,to:Go(e.connection.to,e.transform)}:{...e.connection}}function vb(e){return xb}function wb(e){const t=vb();return ne(t,fe)}const Sb=e=>({nodesConnectable:e.nodesConnectable,isValid:e.connection.isValid,inProgress:e.connection.inProgress,width:e.width,height:e.height});function kb({containerStyle:e,style:t,type:n,component:r}){const{nodesConnectable:o,width:i,height:s,isValid:l,inProgress:a}=ne(Sb,fe);return!(i&&o&&a)?null:d.jsx("svg",{style:e,width:i,height:s,className:"react-flow__connectionline react-flow__container",children:d.jsx("g",{className:we(["react-flow__connection",Kg(l)]),children:d.jsx(n0,{style:t,type:n,CustomComponent:r,isValid:l})})})}const n0=({style:e,type:t=Zt.Bezier,CustomComponent:n,isValid:r})=>{const{inProgress:o,from:i,fromNode:s,fromHandle:l,fromPosition:a,to:u,toNode:p,toHandle:c,toPosition:f,pointer:x}=wb();if(!o)return;if(n)return d.jsx(n,{connectionLineType:t,connectionLineStyle:e,fromNode:s,fromHandle:l,fromX:i.x,fromY:i.y,toX:u.x,toY:u.y,fromPosition:a,toPosition:f,connectionStatus:Kg(r),toNode:p,toHandle:c,pointer:x});let y="";const v={sourceX:i.x,sourceY:i.y,sourcePosition:a,targetX:u.x,targetY:u.y,targetPosition:f};switch(t){case Zt.Bezier:[y]=am(v);break;case Zt.SimpleBezier:[y]=Vm(v);break;case Zt.Step:[y]=Ja({...v,borderRadius:0});break;case Zt.SmoothStep:[y]=Ja(v);break;default:[y]=cm(v)}return d.jsx("path",{d:y,fill:"none",className:"react-flow__connection-path",style:e})};n0.displayName="ConnectionLine";const _b={};function Bf(e=_b){M.useRef(e),pe(),M.useEffect(()=>{},[e])}function bb(){pe(),M.useRef(!1),M.useEffect(()=>{},[])}function r0({nodeTypes:e,edgeTypes:t,onInit:n,onNodeClick:r,onEdgeClick:o,onNodeDoubleClick:i,onEdgeDoubleClick:s,onNodeMouseEnter:l,onNodeMouseMove:a,onNodeMouseLeave:u,onNodeContextMenu:p,onSelectionContextMenu:c,onSelectionStart:f,onSelectionEnd:x,connectionLineType:y,connectionLineStyle:v,connectionLineComponent:k,connectionLineContainerStyle:m,selectionKeyCode:g,selectionOnDrag:h,selectionMode:w,multiSelectionKeyCode:_,panActivationKeyCode:S,zoomActivationKeyCode:b,deleteKeyCode:E,onlyRenderVisibleElements:A,elementsSelectable:D,defaultViewport:P,translateExtent:I,minZoom:T,maxZoom:C,preventScrolling:L,defaultMarkerColor:z,zoomOnScroll:R,zoomOnPinch:j,panOnScroll:N,panOnScrollSpeed:$,panOnScrollMode:O,zoomOnDoubleClick:B,panOnDrag:W,onPaneClick:V,onPaneMouseEnter:Y,onPaneMouseMove:X,onPaneMouseLeave:Q,onPaneScroll:H,onPaneContextMenu:K,paneClickDistance:ee,nodeClickDistance:G,onEdgeContextMenu:J,onEdgeMouseEnter:Z,onEdgeMouseMove:re,onEdgeMouseLeave:le,reconnectRadius:ie,onReconnect:Ne,onReconnectStart:Vt,onReconnectEnd:Nt,noDragClassName:gn,noWheelClassName:zr,noPanClassName:Tr,disableKeyboardA11y:Pr,nodeExtent:rl,rfId:Ko,viewport:On,onViewportChange:Ir}){return Bf(e),Bf(t),bb(),gb(n),yb(On),d.jsx(O_,{onPaneClick:V,onPaneMouseEnter:Y,onPaneMouseMove:X,onPaneMouseLeave:Q,onPaneContextMenu:K,onPaneScroll:H,paneClickDistance:ee,deleteKeyCode:E,selectionKeyCode:g,selectionOnDrag:h,selectionMode:w,onSelectionStart:f,onSelectionEnd:x,multiSelectionKeyCode:_,panActivationKeyCode:S,zoomActivationKeyCode:b,elementsSelectable:D,zoomOnScroll:R,zoomOnPinch:j,zoomOnDoubleClick:B,panOnScroll:N,panOnScrollSpeed:$,panOnScrollMode:O,panOnDrag:W,defaultViewport:P,translateExtent:I,minZoom:T,maxZoom:C,onSelectionContextMenu:c,preventScrolling:L,noDragClassName:gn,noWheelClassName:zr,noPanClassName:Tr,disableKeyboardA11y:Pr,onViewportChange:Ir,isControlledViewport:!!On,children:d.jsxs(hb,{children:[d.jsx(fb,{edgeTypes:t,onEdgeClick:o,onEdgeDoubleClick:s,onReconnect:Ne,onReconnectStart:Vt,onReconnectEnd:Nt,onlyRenderVisibleElements:A,onEdgeContextMenu:J,onEdgeMouseEnter:Z,onEdgeMouseMove:re,onEdgeMouseLeave:le,reconnectRadius:ie,defaultMarkerColor:z,noPanClassName:Tr,disableKeyboardA11y:Pr,rfId:Ko}),d.jsx(kb,{style:v,type:y,component:k,containerStyle:m}),d.jsx("div",{className:"react-flow__edgelabel-renderer"}),d.jsx(Q_,{nodeTypes:e,onNodeClick:r,onNodeDoubleClick:i,onNodeMouseEnter:l,onNodeMouseMove:a,onNodeMouseLeave:u,onNodeContextMenu:p,nodeClickDistance:G,onlyRenderVisibleElements:A,noPanClassName:Tr,noDragClassName:gn,disableKeyboardA11y:Pr,nodeExtent:rl,rfId:Ko}),d.jsx("div",{className:"react-flow__viewport-portal"})]})})}r0.displayName="GraphView";const Cb=M.memo(r0),Ff=({nodes:e,edges:t,defaultNodes:n,defaultEdges:r,width:o,height:i,fitView:s,fitViewOptions:l,minZoom:a=.5,maxZoom:u=2,nodeOrigin:p,nodeExtent:c,zIndexMode:f="basic"}={})=>{const x=new Map,y=new Map,v=new Map,k=new Map,m=r??t??[],g=n??e??[],h=p??[0,0],w=c??Io;pm(v,k,m);const _=tu(g,x,y,{nodeOrigin:h,nodeExtent:w,zIndexMode:f});let S=[0,0,1];if(s&&o&&i){const b=Xo(x,{filter:P=>!!((P.width||P.initialWidth)&&(P.height||P.initialHeight))}),{x:E,y:A,zoom:D}=dc(b,o,i,a,u,(l==null?void 0:l.padding)??.1);S=[E,A,D]}return{rfId:"1",width:o??0,height:i??0,transform:S,nodes:g,nodesInitialized:_,nodeLookup:x,parentLookup:y,edges:m,edgeLookup:k,connectionLookup:v,onNodesChange:null,onEdgesChange:null,hasDefaultNodes:n!==void 0,hasDefaultEdges:r!==void 0,panZoom:null,minZoom:a,maxZoom:u,translateExtent:Io,nodeExtent:w,nodesSelectionActive:!1,userSelectionActive:!1,userSelectionRect:null,connectionMode:wr.Strict,domNode:null,paneDragging:!1,noPanClassName:"nopan",nodeOrigin:h,nodeDragThreshold:1,connectionDragThreshold:1,snapGrid:[15,15],snapToGrid:!1,nodesDraggable:!0,nodesConnectable:!0,nodesFocusable:!0,edgesFocusable:!0,edgesReconnectable:!0,elementsSelectable:!0,elevateNodesOnSelect:!0,elevateEdgesOnSelect:!0,selectNodesOnDrag:!0,multiSelectionActive:!1,fitViewQueued:s??!1,fitViewOptions:l,fitViewResolver:null,connection:{...Gg},connectionClickStartHandle:null,connectOnClick:!0,ariaLiveMessage:"",autoPanOnConnect:!0,autoPanOnNodeDrag:!0,autoPanOnNodeFocus:!0,autoPanSpeed:15,connectionRadius:20,onError:bS,isValidConnection:void 0,onSelectionChangeHandlers:[],lib:"react",debug:!1,ariaLabelConfig:Qg,zIndexMode:f,onNodesChangeMiddlewareMap:new Map,onEdgesChangeMiddlewareMap:new Map}},Eb=({nodes:e,edges:t,defaultNodes:n,defaultEdges:r,width:o,height:i,fitView:s,fitViewOptions:l,minZoom:a,maxZoom:u,nodeOrigin:p,nodeExtent:c,zIndexMode:f})=>Wk((x,y)=>{async function v(){const{nodeLookup:k,panZoom:m,fitViewOptions:g,fitViewResolver:h,width:w,height:_,minZoom:S,maxZoom:b}=y();m&&(await kS({nodes:k,width:w,height:_,panZoom:m,minZoom:S,maxZoom:b},g),h==null||h.resolve(!0),x({fitViewResolver:null}))}return{...Ff({nodes:e,edges:t,width:o,height:i,fitView:s,fitViewOptions:l,minZoom:a,maxZoom:u,nodeOrigin:p,nodeExtent:c,defaultNodes:n,defaultEdges:r,zIndexMode:f}),setNodes:k=>{const{nodeLookup:m,parentLookup:g,nodeOrigin:h,elevateNodesOnSelect:w,fitViewQueued:_,zIndexMode:S}=y(),b=tu(k,m,g,{nodeOrigin:h,nodeExtent:c,elevateNodesOnSelect:w,checkEquality:!0,zIndexMode:S});_&&b?(v(),x({nodes:k,nodesInitialized:b,fitViewQueued:!1,fitViewOptions:void 0})):x({nodes:k,nodesInitialized:b})},setEdges:k=>{const{connectionLookup:m,edgeLookup:g}=y();pm(m,g,k),x({edges:k})},setDefaultNodesAndEdges:(k,m)=>{if(k){const{setNodes:g}=y();g(k),x({hasDefaultNodes:!0})}if(m){const{setEdges:g}=y();g(m),x({hasDefaultEdges:!0})}},updateNodeInternals:k=>{const{triggerNodeChanges:m,nodeLookup:g,parentLookup:h,domNode:w,nodeOrigin:_,nodeExtent:S,debug:b,fitViewQueued:E,zIndexMode:A}=y(),{changes:D,updatedInternals:P}=YS(k,g,h,w,_,S,A);P&&(HS(g,h,{nodeOrigin:_,nodeExtent:S,zIndexMode:A}),E?(v(),x({fitViewQueued:!1,fitViewOptions:void 0})):x({}),(D==null?void 0:D.length)>0&&(b&&console.log("React Flow: trigger node changes",D),m==null||m(D)))},updateNodePositions:(k,m=!1)=>{const g=[];let h=[];const{nodeLookup:w,triggerNodeChanges:_,connection:S,updateConnection:b,onNodesChangeMiddlewareMap:E}=y();for(const[A,D]of k){const P=w.get(A),I=!!(P!=null&&P.expandParent&&(P!=null&&P.parentId)&&(D!=null&&D.position)),T={id:A,type:"position",position:I?{x:Math.max(0,D.position.x),y:Math.max(0,D.position.y)}:D.position,dragging:m};if(P&&S.inProgress&&S.fromNode.id===P.id){const C=Ln(P,S.fromHandle,q.Left,!0);b({...S,from:C})}I&&P.parentId&&g.push({id:A,parentId:P.parentId,rect:{...D.internals.positionAbsolute,width:D.measured.width??0,height:D.measured.height??0}}),h.push(T)}if(g.length>0){const{parentLookup:A,nodeOrigin:D}=y(),P=yc(g,w,A,D);h.push(...P)}for(const A of E.values())h=A(h);_(h)},triggerNodeChanges:k=>{const{onNodesChange:m,setNodes:g,nodes:h,hasDefaultNodes:w,debug:_}=y();if(k!=null&&k.length){if(w){const S=Pm(k,h);g(S)}_&&console.log("React Flow: trigger node changes",k),m==null||m(k)}},triggerEdgeChanges:k=>{const{onEdgesChange:m,setEdges:g,edges:h,hasDefaultEdges:w,debug:_}=y();if(k!=null&&k.length){if(w){const S=Im(k,h);g(S)}_&&console.log("React Flow: trigger edge changes",k),m==null||m(k)}},addSelectedNodes:k=>{const{multiSelectionActive:m,edgeLookup:g,nodeLookup:h,triggerNodeChanges:w,triggerEdgeChanges:_}=y();if(m){const S=k.map(b=>xn(b,!0));w(S);return}w(nr(h,new Set([...k]),!0)),_(nr(g))},addSelectedEdges:k=>{const{multiSelectionActive:m,edgeLookup:g,nodeLookup:h,triggerNodeChanges:w,triggerEdgeChanges:_}=y();if(m){const S=k.map(b=>xn(b,!0));_(S);return}_(nr(g,new Set([...k]))),w(nr(h,new Set,!0))},unselectNodesAndEdges:({nodes:k,edges:m}={})=>{const{edges:g,nodes:h,nodeLookup:w,triggerNodeChanges:_,triggerEdgeChanges:S}=y(),b=k||h,E=m||g,A=[];for(const P of b){if(!P.selected)continue;const I=w.get(P.id);I&&(I.selected=!1),A.push(xn(P.id,!1))}const D=[];for(const P of E)P.selected&&D.push(xn(P.id,!1));_(A),S(D)},setMinZoom:k=>{const{panZoom:m,maxZoom:g}=y();m==null||m.setScaleExtent([k,g]),x({minZoom:k})},setMaxZoom:k=>{const{panZoom:m,minZoom:g}=y();m==null||m.setScaleExtent([g,k]),x({maxZoom:k})},setTranslateExtent:k=>{var m;(m=y().panZoom)==null||m.setTranslateExtent(k),x({translateExtent:k})},resetSelectedElements:()=>{const{edges:k,nodes:m,triggerNodeChanges:g,triggerEdgeChanges:h,elementsSelectable:w}=y();if(!w)return;const _=m.reduce((b,E)=>E.selected?[...b,xn(E.id,!1)]:b,[]),S=k.reduce((b,E)=>E.selected?[...b,xn(E.id,!1)]:b,[]);g(_),h(S)},setNodeExtent:k=>{const{nodes:m,nodeLookup:g,parentLookup:h,nodeOrigin:w,elevateNodesOnSelect:_,nodeExtent:S,zIndexMode:b}=y();k[0][0]===S[0][0]&&k[0][1]===S[0][1]&&k[1][0]===S[1][0]&&k[1][1]===S[1][1]||(tu(m,g,h,{nodeOrigin:w,nodeExtent:k,elevateNodesOnSelect:_,checkEquality:!1,zIndexMode:b}),x({nodeExtent:k}))},panBy:k=>{const{transform:m,width:g,height:h,panZoom:w,translateExtent:_}=y();return XS({delta:k,panZoom:w,transform:m,translateExtent:_,width:g,height:h})},setCenter:async(k,m,g)=>{const{width:h,height:w,maxZoom:_,panZoom:S}=y();if(!S)return Promise.resolve(!1);const b=typeof(g==null?void 0:g.zoom)<"u"?g.zoom:_;return await S.setViewport({x:h/2-k*b,y:w/2-m*b,zoom:b},{duration:g==null?void 0:g.duration,ease:g==null?void 0:g.ease,interpolate:g==null?void 0:g.interpolate}),Promise.resolve(!0)},cancelConnection:()=>{x({connection:{...Gg}})},updateConnection:k=>{x({connection:k})},reset:()=>x({...Ff()})}},Object.is);function jb({initialNodes:e,initialEdges:t,defaultNodes:n,defaultEdges:r,initialWidth:o,initialHeight:i,initialMinZoom:s,initialMaxZoom:l,initialFitViewOptions:a,fitView:u,nodeOrigin:p,nodeExtent:c,zIndexMode:f,children:x}){const[y]=M.useState(()=>Eb({nodes:e,edges:t,defaultNodes:n,defaultEdges:r,width:o,height:i,fitView:u,minZoom:s,maxZoom:l,fitViewOptions:a,nodeOrigin:p,nodeExtent:c,zIndexMode:f}));return d.jsx(Uk,{value:y,children:d.jsx(h_,{children:x})})}function Nb({children:e,nodes:t,edges:n,defaultNodes:r,defaultEdges:o,width:i,height:s,fitView:l,fitViewOptions:a,minZoom:u,maxZoom:p,nodeOrigin:c,nodeExtent:f,zIndexMode:x}){return M.useContext(Js)?d.jsx(d.Fragment,{children:e}):d.jsx(jb,{initialNodes:t,initialEdges:n,defaultNodes:r,defaultEdges:o,initialWidth:i,initialHeight:s,fitView:l,initialFitViewOptions:a,initialMinZoom:u,initialMaxZoom:p,nodeOrigin:c,nodeExtent:f,zIndexMode:x,children:e})}const Mb={width:"100%",height:"100%",overflow:"hidden",position:"relative",zIndex:0};function zb({nodes:e,edges:t,defaultNodes:n,defaultEdges:r,className:o,nodeTypes:i,edgeTypes:s,onNodeClick:l,onEdgeClick:a,onInit:u,onMove:p,onMoveStart:c,onMoveEnd:f,onConnect:x,onConnectStart:y,onConnectEnd:v,onClickConnectStart:k,onClickConnectEnd:m,onNodeMouseEnter:g,onNodeMouseMove:h,onNodeMouseLeave:w,onNodeContextMenu:_,onNodeDoubleClick:S,onNodeDragStart:b,onNodeDrag:E,onNodeDragStop:A,onNodesDelete:D,onEdgesDelete:P,onDelete:I,onSelectionChange:T,onSelectionDragStart:C,onSelectionDrag:L,onSelectionDragStop:z,onSelectionContextMenu:R,onSelectionStart:j,onSelectionEnd:N,onBeforeDelete:$,connectionMode:O,connectionLineType:B=Zt.Bezier,connectionLineStyle:W,connectionLineComponent:V,connectionLineContainerStyle:Y,deleteKeyCode:X="Backspace",selectionKeyCode:Q="Shift",selectionOnDrag:H=!1,selectionMode:K=Ro.Full,panActivationKeyCode:ee="Space",multiSelectionKeyCode:G=Ao()?"Meta":"Control",zoomActivationKeyCode:J=Ao()?"Meta":"Control",snapToGrid:Z,snapGrid:re,onlyRenderVisibleElements:le=!1,selectNodesOnDrag:ie,nodesDraggable:Ne,autoPanOnNodeFocus:Vt,nodesConnectable:Nt,nodesFocusable:gn,nodeOrigin:zr=zm,edgesFocusable:Tr,edgesReconnectable:Pr,elementsSelectable:rl=!0,defaultViewport:Ko=o_,minZoom:On=.5,maxZoom:Ir=2,translateExtent:kc=Io,preventScrolling:c0=!0,nodeExtent:ol,defaultMarkerColor:d0="#b1b1b7",zoomOnScroll:f0=!0,zoomOnPinch:p0=!0,panOnScroll:h0=!1,panOnScrollSpeed:g0=.5,panOnScrollMode:m0=En.Free,zoomOnDoubleClick:y0=!0,panOnDrag:x0=!0,onPaneClick:v0,onPaneMouseEnter:w0,onPaneMouseMove:S0,onPaneMouseLeave:k0,onPaneScroll:_0,onPaneContextMenu:b0,paneClickDistance:C0=1,nodeClickDistance:E0=0,children:j0,onReconnect:N0,onReconnectStart:M0,onReconnectEnd:z0,onEdgeContextMenu:T0,onEdgeDoubleClick:P0,onEdgeMouseEnter:I0,onEdgeMouseMove:R0,onEdgeMouseLeave:L0,reconnectRadius:A0=10,onNodesChange:$0,onEdgesChange:D0,noDragClassName:O0="nodrag",noWheelClassName:B0="nowheel",noPanClassName:_c="nopan",fitView:bc,fitViewOptions:Cc,connectOnClick:F0,attributionPosition:H0,proOptions:V0,defaultEdgeOptions:W0,elevateNodesOnSelect:U0=!0,elevateEdgesOnSelect:Y0=!1,disableKeyboardA11y:Ec=!1,autoPanOnConnect:X0,autoPanOnNodeDrag:Q0,autoPanSpeed:G0,connectionRadius:K0,isValidConnection:Z0,onError:q0,style:J0,id:jc,nodeDragThreshold:ey,connectionDragThreshold:ty,viewport:ny,onViewportChange:ry,width:oy,height:iy,colorMode:sy="light",debug:ly,onScroll:Zo,ariaLabelConfig:ay,zIndexMode:Nc="basic",...uy},cy){const il=jc||"1",dy=a_(sy),fy=M.useCallback(Mc=>{Mc.currentTarget.scrollTo({top:0,left:0,behavior:"instant"}),Zo==null||Zo(Mc)},[Zo]);return d.jsx("div",{"data-testid":"rf__wrapper",...uy,onScroll:fy,style:{...J0,...Mb},ref:cy,className:we(["react-flow",o,dy]),id:jc,role:"application",children:d.jsxs(Nb,{nodes:e,edges:t,width:oy,height:iy,fitView:bc,fitViewOptions:Cc,minZoom:On,maxZoom:Ir,nodeOrigin:zr,nodeExtent:ol,zIndexMode:Nc,children:[d.jsx(Cb,{onInit:u,onNodeClick:l,onEdgeClick:a,onNodeMouseEnter:g,onNodeMouseMove:h,onNodeMouseLeave:w,onNodeContextMenu:_,onNodeDoubleClick:S,nodeTypes:i,edgeTypes:s,connectionLineType:B,connectionLineStyle:W,connectionLineComponent:V,connectionLineContainerStyle:Y,selectionKeyCode:Q,selectionOnDrag:H,selectionMode:K,deleteKeyCode:X,multiSelectionKeyCode:G,panActivationKeyCode:ee,zoomActivationKeyCode:J,onlyRenderVisibleElements:le,defaultViewport:Ko,translateExtent:kc,minZoom:On,maxZoom:Ir,preventScrolling:c0,zoomOnScroll:f0,zoomOnPinch:p0,zoomOnDoubleClick:y0,panOnScroll:h0,panOnScrollSpeed:g0,panOnScrollMode:m0,panOnDrag:x0,onPaneClick:v0,onPaneMouseEnter:w0,onPaneMouseMove:S0,onPaneMouseLeave:k0,onPaneScroll:_0,onPaneContextMenu:b0,paneClickDistance:C0,nodeClickDistance:E0,onSelectionContextMenu:R,onSelectionStart:j,onSelectionEnd:N,onReconnect:N0,onReconnectStart:M0,onReconnectEnd:z0,onEdgeContextMenu:T0,onEdgeDoubleClick:P0,onEdgeMouseEnter:I0,onEdgeMouseMove:R0,onEdgeMouseLeave:L0,reconnectRadius:A0,defaultMarkerColor:d0,noDragClassName:O0,noWheelClassName:B0,noPanClassName:_c,rfId:il,disableKeyboardA11y:Ec,nodeExtent:ol,viewport:ny,onViewportChange:ry}),d.jsx(l_,{nodes:e,edges:t,defaultNodes:n,defaultEdges:r,onConnect:x,onConnectStart:y,onConnectEnd:v,onClickConnectStart:k,onClickConnectEnd:m,nodesDraggable:Ne,autoPanOnNodeFocus:Vt,nodesConnectable:Nt,nodesFocusable:gn,edgesFocusable:Tr,edgesReconnectable:Pr,elementsSelectable:rl,elevateNodesOnSelect:U0,elevateEdgesOnSelect:Y0,minZoom:On,maxZoom:Ir,nodeExtent:ol,onNodesChange:$0,onEdgesChange:D0,snapToGrid:Z,snapGrid:re,connectionMode:O,translateExtent:kc,connectOnClick:F0,defaultEdgeOptions:W0,fitView:bc,fitViewOptions:Cc,onNodesDelete:D,onEdgesDelete:P,onDelete:I,onNodeDragStart:b,onNodeDrag:E,onNodeDragStop:A,onSelectionDrag:L,onSelectionDragStart:C,onSelectionDragStop:z,onMove:p,onMoveStart:c,onMoveEnd:f,noPanClassName:_c,nodeOrigin:zr,rfId:il,autoPanOnConnect:X0,autoPanOnNodeDrag:Q0,autoPanSpeed:G0,onError:q0,connectionRadius:K0,isValidConnection:Z0,selectNodesOnDrag:ie,nodeDragThreshold:ey,connectionDragThreshold:ty,onBeforeDelete:$,debug:ly,ariaLabelConfig:ay,zIndexMode:Nc}),d.jsx(r_,{onSelectionChange:T}),j0,d.jsx(qk,{proOptions:V0,position:H0}),d.jsx(Zk,{rfId:il,disableKeyboardA11y:Ec})]})})}var Tb=Rm(zb);function Pb(e){const[t,n]=M.useState(e),r=M.useCallback(o=>n(i=>Pm(o,i)),[]);return[t,n,r]}function Ib(e){const[t,n]=M.useState(e),r=M.useCallback(o=>n(i=>Im(o,i)),[]);return[t,n,r]}function Rb({dimensions:e,lineWidth:t,variant:n,className:r}){return d.jsx("path",{strokeWidth:t,d:`M${e[0]/2} 0 V${e[1]} M0 ${e[1]/2} H${e[0]}`,className:we(["react-flow__background-pattern",n,r])})}function Lb({radius:e,className:t}){return d.jsx("circle",{cx:e,cy:e,r:e,className:we(["react-flow__background-pattern","dots",t])})}var un;(function(e){e.Lines="lines",e.Dots="dots",e.Cross="cross"})(un||(un={}));const Ab={[un.Dots]:1,[un.Lines]:1,[un.Cross]:6},$b=e=>({transform:e.transform,patternId:`pattern-${e.rfId}`});function o0({id:e,variant:t=un.Dots,gap:n=20,size:r,lineWidth:o=1,offset:i=0,color:s,bgColor:l,style:a,className:u,patternClassName:p}){const c=M.useRef(null),{transform:f,patternId:x}=ne($b,fe),y=r||Ab[t],v=t===un.Dots,k=t===un.Cross,m=Array.isArray(n)?n:[n,n],g=[m[0]*f[2]||1,m[1]*f[2]||1],h=y*f[2],w=Array.isArray(i)?i:[i,i],_=k?[h,h]:g,S=[w[0]*f[2]||1+_[0]/2,w[1]*f[2]||1+_[1]/2],b=`${x}${e||""}`;return d.jsxs("svg",{className:we(["react-flow__background",u]),style:{...a,...tl,"--xy-background-color-props":l,"--xy-background-pattern-color-props":s},ref:c,"data-testid":"rf__background",children:[d.jsx("pattern",{id:b,x:f[0]%g[0],y:f[1]%g[1],width:g[0],height:g[1],patternUnits:"userSpaceOnUse",patternTransform:`translate(-${S[0]},-${S[1]})`,children:v?d.jsx(Lb,{radius:h/2,className:p}):d.jsx(Rb,{dimensions:_,lineWidth:o,variant:t,className:p})}),d.jsx("rect",{x:"0",y:"0",width:"100%",height:"100%",fill:`url(#${b})`})]})}o0.displayName="Background";const Db=M.memo(o0);function Ob(){return d.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 32",children:d.jsx("path",{d:"M32 18.133H18.133V32h-4.266V18.133H0v-4.266h13.867V0h4.266v13.867H32z"})})}function Bb(){return d.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 5",children:d.jsx("path",{d:"M0 0h32v4.2H0z"})})}function Fb(){return d.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 30",children:d.jsx("path",{d:"M3.692 4.63c0-.53.4-.938.939-.938h5.215V0H4.708C2.13 0 0 2.054 0 4.63v5.216h3.692V4.631zM27.354 0h-5.2v3.692h5.17c.53 0 .984.4.984.939v5.215H32V4.631A4.624 4.624 0 0027.354 0zm.954 24.83c0 .532-.4.94-.939.94h-5.215v3.768h5.215c2.577 0 4.631-2.13 4.631-4.707v-5.139h-3.692v5.139zm-23.677.94c-.531 0-.939-.4-.939-.94v-5.138H0v5.139c0 2.577 2.13 4.707 4.708 4.707h5.138V25.77H4.631z"})})}function Hb(){return d.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 25 32",children:d.jsx("path",{d:"M21.333 10.667H19.81V7.619C19.81 3.429 16.38 0 12.19 0 8 0 4.571 3.429 4.571 7.619v3.048H3.048A3.056 3.056 0 000 13.714v15.238A3.056 3.056 0 003.048 32h18.285a3.056 3.056 0 003.048-3.048V13.714a3.056 3.056 0 00-3.048-3.047zM12.19 24.533a3.056 3.056 0 01-3.047-3.047 3.056 3.056 0 013.047-3.048 3.056 3.056 0 013.048 3.048 3.056 3.056 0 01-3.048 3.047zm4.724-13.866H7.467V7.619c0-2.59 2.133-4.724 4.723-4.724 2.591 0 4.724 2.133 4.724 4.724v3.048z"})})}function Vb(){return d.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 25 32",children:d.jsx("path",{d:"M21.333 10.667H19.81V7.619C19.81 3.429 16.38 0 12.19 0c-4.114 1.828-1.37 2.133.305 2.438 1.676.305 4.42 2.59 4.42 5.181v3.048H3.047A3.056 3.056 0 000 13.714v15.238A3.056 3.056 0 003.048 32h18.285a3.056 3.056 0 003.048-3.048V13.714a3.056 3.056 0 00-3.048-3.047zM12.19 24.533a3.056 3.056 0 01-3.047-3.047 3.056 3.056 0 013.047-3.048 3.056 3.056 0 013.048 3.048 3.056 3.056 0 01-3.048 3.047z"})})}function _i({children:e,className:t,...n}){return d.jsx("button",{type:"button",className:we(["react-flow__controls-button",t]),...n,children:e})}const Wb=e=>({isInteractive:e.nodesDraggable||e.nodesConnectable||e.elementsSelectable,minZoomReached:e.transform[2]<=e.minZoom,maxZoomReached:e.transform[2]>=e.maxZoom,ariaLabelConfig:e.ariaLabelConfig});function i0({style:e,showZoom:t=!0,showFitView:n=!0,showInteractive:r=!0,fitViewOptions:o,onZoomIn:i,onZoomOut:s,onFitView:l,onInteractiveChange:a,className:u,children:p,position:c="bottom-left",orientation:f="vertical","aria-label":x}){const y=pe(),{isInteractive:v,minZoomReached:k,maxZoomReached:m,ariaLabelConfig:g}=ne(Wb,fe),{zoomIn:h,zoomOut:w,fitView:_}=xc(),S=()=>{h(),i==null||i()},b=()=>{w(),s==null||s()},E=()=>{_(o),l==null||l()},A=()=>{y.setState({nodesDraggable:!v,nodesConnectable:!v,elementsSelectable:!v}),a==null||a(!v)},D=f==="horizontal"?"horizontal":"vertical";return d.jsxs(el,{className:we(["react-flow__controls",D,u]),position:c,style:e,"data-testid":"rf__controls","aria-label":x??g["controls.ariaLabel"],children:[t&&d.jsxs(d.Fragment,{children:[d.jsx(_i,{onClick:S,className:"react-flow__controls-zoomin",title:g["controls.zoomIn.ariaLabel"],"aria-label":g["controls.zoomIn.ariaLabel"],disabled:m,children:d.jsx(Ob,{})}),d.jsx(_i,{onClick:b,className:"react-flow__controls-zoomout",title:g["controls.zoomOut.ariaLabel"],"aria-label":g["controls.zoomOut.ariaLabel"],disabled:k,children:d.jsx(Bb,{})})]}),n&&d.jsx(_i,{className:"react-flow__controls-fitview",onClick:E,title:g["controls.fitView.ariaLabel"],"aria-label":g["controls.fitView.ariaLabel"],children:d.jsx(Fb,{})}),r&&d.jsx(_i,{className:"react-flow__controls-interactive",onClick:A,title:g["controls.interactive.ariaLabel"],"aria-label":g["controls.interactive.ariaLabel"],children:v?d.jsx(Vb,{}):d.jsx(Hb,{})}),p]})}i0.displayName="Controls";const Ub=M.memo(i0);function Yb({id:e,x:t,y:n,width:r,height:o,style:i,color:s,strokeColor:l,strokeWidth:a,className:u,borderRadius:p,shapeRendering:c,selected:f,onClick:x}){const{background:y,backgroundColor:v}=i||{},k=s||y||v;return d.jsx("rect",{className:we(["react-flow__minimap-node",{selected:f},u]),x:t,y:n,rx:p,ry:p,width:r,height:o,style:{fill:k,stroke:l,strokeWidth:a},shapeRendering:c,onClick:x?m=>x(m,e):void 0})}const Xb=M.memo(Yb),Qb=e=>e.nodes.map(t=>t.id),Fl=e=>e instanceof Function?e:()=>e;function Gb({nodeStrokeColor:e,nodeColor:t,nodeClassName:n="",nodeBorderRadius:r=5,nodeStrokeWidth:o,nodeComponent:i=Xb,onClick:s}){const l=ne(Qb,fe),a=Fl(t),u=Fl(e),p=Fl(n),c=typeof window>"u"||window.chrome?"crispEdges":"geometricPrecision";return d.jsx(d.Fragment,{children:l.map(f=>d.jsx(Zb,{id:f,nodeColorFunc:a,nodeStrokeColorFunc:u,nodeClassNameFunc:p,nodeBorderRadius:r,nodeStrokeWidth:o,NodeComponent:i,onClick:s,shapeRendering:c},f))})}function Kb({id:e,nodeColorFunc:t,nodeStrokeColorFunc:n,nodeClassNameFunc:r,nodeBorderRadius:o,nodeStrokeWidth:i,shapeRendering:s,NodeComponent:l,onClick:a}){const{node:u,x:p,y:c,width:f,height:x}=ne(y=>{const v=y.nodeLookup.get(e);if(!v)return{node:void 0,x:0,y:0,width:0,height:0};const k=v.internals.userNode,{x:m,y:g}=v.internals.positionAbsolute,{width:h,height:w}=Ht(k);return{node:k,x:m,y:g,width:h,height:w}},fe);return!u||u.hidden||!nm(u)?null:d.jsx(l,{x:p,y:c,width:f,height:x,style:u.style,selected:!!u.selected,className:r(u),color:t(u),borderRadius:o,strokeColor:n(u),strokeWidth:i,shapeRendering:s,onClick:a,id:u.id})}const Zb=M.memo(Kb);var qb=M.memo(Gb);const Jb=200,eC=150,tC=e=>!e.hidden,nC=e=>{const t={x:-e.transform[0]/e.transform[2],y:-e.transform[1]/e.transform[2],width:e.width/e.transform[2],height:e.height/e.transform[2]};return{viewBB:t,boundingRect:e.nodeLookup.size>0?tm(Xo(e.nodeLookup,{filter:tC}),t):t,rfId:e.rfId,panZoom:e.panZoom,translateExtent:e.translateExtent,flowWidth:e.width,flowHeight:e.height,ariaLabelConfig:e.ariaLabelConfig}},rC="react-flow__minimap-desc";function s0({style:e,className:t,nodeStrokeColor:n,nodeColor:r,nodeClassName:o="",nodeBorderRadius:i=5,nodeStrokeWidth:s,nodeComponent:l,bgColor:a,maskColor:u,maskStrokeColor:p,maskStrokeWidth:c,position:f="bottom-right",onClick:x,onNodeClick:y,pannable:v=!1,zoomable:k=!1,ariaLabel:m,inversePan:g,zoomStep:h=1,offsetScale:w=5}){const _=pe(),S=M.useRef(null),{boundingRect:b,viewBB:E,rfId:A,panZoom:D,translateExtent:P,flowWidth:I,flowHeight:T,ariaLabelConfig:C}=ne(nC,fe),L=(e==null?void 0:e.width)??Jb,z=(e==null?void 0:e.height)??eC,R=b.width/L,j=b.height/z,N=Math.max(R,j),$=N*L,O=N*z,B=w*N,W=b.x-($-b.width)/2-B,V=b.y-(O-b.height)/2-B,Y=$+B*2,X=O+B*2,Q=`${rC}-${A}`,H=M.useRef(0),K=M.useRef();H.current=N,M.useEffect(()=>{if(S.current&&D)return K.current=nk({domNode:S.current,panZoom:D,getTransform:()=>_.getState().transform,getViewScale:()=>H.current}),()=>{var Z;(Z=K.current)==null||Z.destroy()}},[D]),M.useEffect(()=>{var Z;(Z=K.current)==null||Z.update({translateExtent:P,width:I,height:T,inversePan:g,pannable:v,zoomStep:h,zoomable:k})},[v,k,g,h,P,I,T]);const ee=x?Z=>{var ie;const[re,le]=((ie=K.current)==null?void 0:ie.pointer(Z))||[0,0];x(Z,{x:re,y:le})}:void 0,G=y?M.useCallback((Z,re)=>{const le=_.getState().nodeLookup.get(re).internals.userNode;y(Z,le)},[]):void 0,J=m??C["minimap.ariaLabel"];return d.jsx(el,{position:f,style:{...e,"--xy-minimap-background-color-props":typeof a=="string"?a:void 0,"--xy-minimap-mask-background-color-props":typeof u=="string"?u:void 0,"--xy-minimap-mask-stroke-color-props":typeof p=="string"?p:void 0,"--xy-minimap-mask-stroke-width-props":typeof c=="number"?c*N:void 0,"--xy-minimap-node-background-color-props":typeof r=="string"?r:void 0,"--xy-minimap-node-stroke-color-props":typeof n=="string"?n:void 0,"--xy-minimap-node-stroke-width-props":typeof s=="number"?s:void 0},className:we(["react-flow__minimap",t]),"data-testid":"rf__minimap",children:d.jsxs("svg",{width:L,height:z,viewBox:`${W} ${V} ${Y} ${X}`,className:"react-flow__minimap-svg",role:"img","aria-labelledby":Q,ref:S,onClick:ee,children:[J&&d.jsx("title",{id:Q,children:J}),d.jsx(qb,{onClick:G,nodeColor:r,nodeStrokeColor:n,nodeBorderRadius:i,nodeClassName:o,nodeStrokeWidth:s,nodeComponent:l}),d.jsx("path",{className:"react-flow__minimap-mask",d:`M${W-B},${V-B}h${Y+B*2}v${X+B*2}h${-Y-B*2}z + M${E.x},${E.y}h${E.width}v${E.height}h${-E.width}z`,fillRule:"evenodd",pointerEvents:"none"})]})})}s0.displayName="MiniMap";M.memo(s0);const oC=e=>t=>e?`${Math.max(1/t.transform[2],1)}`:void 0,iC={[An.Line]:"right",[An.Handle]:"bottom-right"};function sC({nodeId:e,position:t,variant:n=An.Handle,className:r,style:o=void 0,children:i,color:s,minWidth:l=10,minHeight:a=10,maxWidth:u=Number.MAX_VALUE,maxHeight:p=Number.MAX_VALUE,keepAspectRatio:c=!1,resizeDirection:f,autoScale:x=!0,shouldResize:y,onResizeStart:v,onResize:k,onResizeEnd:m}){const g=Dm(),h=typeof e=="string"?e:g,w=pe(),_=M.useRef(null),S=n===An.Handle,b=ne(M.useCallback(oC(S&&x),[S,x]),fe),E=M.useRef(null),A=t??iC[n];M.useEffect(()=>{if(!(!_.current||!h))return E.current||(E.current=xk({domNode:_.current,nodeId:h,getStoreItems:()=>{const{nodeLookup:P,transform:I,snapGrid:T,snapToGrid:C,nodeOrigin:L,domNode:z}=w.getState();return{nodeLookup:P,transform:I,snapGrid:T,snapToGrid:C,nodeOrigin:L,paneDomNode:z}},onChange:(P,I)=>{const{triggerNodeChanges:T,nodeLookup:C,parentLookup:L,nodeOrigin:z}=w.getState(),R=[],j={x:P.x,y:P.y},N=C.get(h);if(N&&N.expandParent&&N.parentId){const $=N.origin??z,O=P.width??N.measured.width??0,B=P.height??N.measured.height??0,W={id:N.id,parentId:N.parentId,rect:{width:O,height:B,...rm({x:P.x??N.position.x,y:P.y??N.position.y},{width:O,height:B},N.parentId,C,$)}},V=yc([W],C,L,z);R.push(...V),j.x=P.x?Math.max($[0]*O,P.x):void 0,j.y=P.y?Math.max($[1]*B,P.y):void 0}if(j.x!==void 0&&j.y!==void 0){const $={id:h,type:"position",position:{...j}};R.push($)}if(P.width!==void 0&&P.height!==void 0){const O={id:h,type:"dimensions",resizing:!0,setAttributes:f?f==="horizontal"?"width":"height":!0,dimensions:{width:P.width,height:P.height}};R.push(O)}for(const $ of I){const O={...$,type:"position"};R.push(O)}T(R)},onEnd:({width:P,height:I})=>{const T={id:h,type:"dimensions",resizing:!1,dimensions:{width:P,height:I}};w.getState().triggerNodeChanges([T])}})),E.current.update({controlPosition:A,boundaries:{minWidth:l,minHeight:a,maxWidth:u,maxHeight:p},keepAspectRatio:c,resizeDirection:f,onResizeStart:v,onResize:k,onResizeEnd:m,shouldResize:y}),()=>{var P;(P=E.current)==null||P.destroy()}},[A,l,a,u,p,c,v,k,m,y]);const D=A.split("-");return d.jsx("div",{className:we(["react-flow__resize-control","nodrag",...D,n,r]),ref:_,style:{...o,scale:b,...s&&{[S?"backgroundColor":"borderColor"]:s}},children:i})}const Hf=M.memo(sC);function lC({nodeId:e,isVisible:t=!0,handleClassName:n,handleStyle:r,lineClassName:o,lineStyle:i,color:s,minWidth:l=10,minHeight:a=10,maxWidth:u=Number.MAX_VALUE,maxHeight:p=Number.MAX_VALUE,keepAspectRatio:c=!1,autoScale:f=!0,shouldResize:x,onResizeStart:y,onResize:v,onResizeEnd:k}){return t?d.jsxs(d.Fragment,{children:[fk.map(m=>d.jsx(Hf,{className:o,style:i,nodeId:e,position:m,variant:An.Line,color:s,minWidth:l,minHeight:a,maxWidth:u,maxHeight:p,onResizeStart:y,keepAspectRatio:c,autoScale:f,shouldResize:x,onResize:v,onResizeEnd:k},m)),dk.map(m=>d.jsx(Hf,{className:n,style:r,nodeId:e,position:m,color:s,minWidth:l,minHeight:a,maxWidth:u,maxHeight:p,onResizeStart:y,keepAspectRatio:c,autoScale:f,shouldResize:x,onResize:v,onResizeEnd:k},m))]}):null}const ou={compute:"#10b981",database:"#8b5cf6",storage:"#6366f1",network:"#3b82f6",security:"#ef4444",serverless:"#f59e0b",cache:"#8b5cf6",queue:"#f97316",cdn:"#3b82f6",monitoring:"#06b6d4",ml:"#ec4899",analytics:"#a855f7",containers:"#14b8a6",streaming:"#f97316",orchestration:"#a78bfa"},aC={ec2:"compute",ecs:"compute",eks:"compute",emr:"compute",fargate:"compute",codepipeline:"compute",codecommit:"storage",codebuild:"compute",dms:"compute",migration_hub:"compute",compute_engine:"compute",gke:"containers",app_engine:"serverless",cloud_build:"compute",virtual_machines:"compute",aks:"containers",container_apps:"containers",azure_devops:"compute",azure_migrate:"compute",rds:"database",aurora:"database",dynamodb:"database",cloud_sql:"database",azure_sql:"database",cosmos_db:"database",redshift:"database",bigquery:"database",firestore:"database",spanner:"database",alloydb:"database",s3:"storage",cloud_storage:"storage",blob_storage:"storage",ebs:"storage",ecr:"storage",fsx:"storage",efs:"storage",artifact_registry:"storage",alb:"network",nlb:"network",route53:"network",cloud_load_balancing:"network",app_gateway:"network",cloud_dns:"network",direct_connect:"network",vpn:"network",azure_lb:"network",azure_dns:"network",cloud_interconnect:"network",api_management:"network",cloudfront:"cdn",cloud_cdn:"cdn",azure_cdn:"cdn",waf:"security",cognito:"security",kms:"security",cloudtrail:"security",guardduty:"security",shield:"security",security_hub:"security",config:"security",inspector:"security",cloud_armor:"security",firebase_auth:"security",azure_waf:"security",azure_ad:"security",azure_firewall:"security",azure_sentinel:"security",azure_policy:"security",lambda:"serverless",api_gateway:"serverless",cloud_functions:"serverless",cloud_run:"serverless",azure_functions:"serverless",step_functions:"serverless",glue:"serverless",app_service:"serverless",elasticache:"cache",memorystore:"cache",azure_cache:"cache",sqs:"queue",sns:"queue",pub_sub:"queue",service_bus:"queue",kinesis:"queue",eventbridge:"queue",cloudwatch:"monitoring",cloud_logging:"monitoring",azure_monitor:"monitoring",sagemaker:"ml",vertex_ai:"ml",azure_ml:"ml",athena:"analytics",dataproc:"analytics",data_factory:"analytics",synapse:"analytics",dataflow:"streaming",event_hubs:"streaming",cloud_composer:"orchestration",logic_apps:"orchestration",databricks_sql_warehouse:"analytics",databricks_cluster:"compute",databricks_job:"orchestration",databricks_pipeline:"streaming",databricks_model_serving:"ml",databricks_unity_catalog:"security",databricks_vector_search:"database",databricks_genie:"analytics",databricks_notebook:"compute",databricks_secret_scope:"security",databricks_dashboard:"analytics",databricks_volume:"storage"},Vf={compute:"M5 12H3l9-9 9 9h-2M5 12v7a2 2 0 002 2h10a2 2 0 002-2v-7",database:"M12 2C6.48 2 2 4.24 2 7v10c0 2.76 4.48 5 10 5s10-2.24 10-5V7c0-2.76-4.48-5-10-5zM2 12c0 2.76 4.48 5 10 5s10-2.24 10-5",storage:"M20 7H4a1 1 0 00-1 1v8a1 1 0 001 1h16a1 1 0 001-1V8a1 1 0 00-1-1zM4 12h16",network:"M12 2a10 10 0 100 20 10 10 0 000-20zm0 0a14.5 14.5 0 014 10 14.5 14.5 0 01-4 10 14.5 14.5 0 01-4-10A14.5 14.5 0 0112 2zM2 12h20",security:"M12 2l7 4v5c0 5.25-3.5 10.74-7 12-3.5-1.26-7-6.75-7-12V6l7-4z",serverless:"M13 2L3 14h9l-1 8 10-12h-9l1-8z",cache:"M4 4h16v4H4zM4 10h16v4H4zM4 16h16v4H4z",queue:"M4 6h16M4 12h16M4 18h16",cdn:"M12 2a10 10 0 100 20 10 10 0 000-20zm-1 17.93A8 8 0 013 12a8 8 0 018-7.93M12 2v20M2 12h20M4.22 7h15.56M4.22 17h15.56",monitoring:"M3 3v18h18M7 16l4-8 4 4 4-6",ml:"M12 2a4 4 0 014 4c0 1.95-1.4 3.57-3.24 3.9L12 14l-.76-4.1A4 4 0 018 6a4 4 0 014-4zM8 14h8M6 18h12M9 22h6",analytics:"M18 20V10M12 20V4M6 20v-6",containers:"M21 16V8a2 2 0 00-1-1.73l-7-4a2 2 0 00-2 0l-7 4A2 2 0 003 8v8a2 2 0 001 1.73l7 4a2 2 0 002 0l7-4A2 2 0 0021 16zM3.27 6.96L12 12l8.73-5.04M12 22.08V12",streaming:"M2 12c2-3 4-3 6 0s4 3 6 0 4-3 6 0 4 3 6 0",orchestration:"M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83"};function wc(e){return aC[e]||"compute"}function l0(e){return ou[e]||"#94a3b8"}function Sc(e){return Vf[e]||Vf.compute}function uC({data:e}){const t=e,n=wc(t.service),r=l0(n),o=Sc(n);return d.jsxs("div",{style:{background:"#ffffff",border:`2px solid ${r}`,borderRadius:10,padding:"8px 12px",color:"#0f172a",minWidth:160,position:"relative",boxShadow:"0 1px 3px rgba(0,0,0,0.08)"},children:[d.jsx(Cr,{type:"target",position:q.Top,style:{background:r}}),d.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6,marginBottom:4},children:[d.jsx("svg",{width:16,height:16,viewBox:"0 0 24 24",fill:"none",stroke:r,strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round",style:{display:"block",width:28,height:28,padding:5,borderRadius:6,background:`${r}22`},children:d.jsx("path",{d:o})}),d.jsx("span",{style:{fontSize:9,color:"#64748b",textTransform:"uppercase",letterSpacing:1},children:n})]}),d.jsx("div",{style:{fontWeight:600,fontSize:13,marginBottom:2,color:"#0f172a"},children:t.label}),d.jsxs("div",{style:{fontSize:11,color:"#64748b"},children:[t.service,d.jsx("span",{style:{marginLeft:6,padding:"1px 4px",borderRadius:3,background:"#e2e8f0",color:"#475569",fontSize:9,textTransform:"uppercase"},children:t.provider})]}),t.monthlyCost!=null&&t.monthlyCost>0&&d.jsxs("div",{style:{fontSize:10,color:"#2563eb",marginTop:4},children:["$",t.monthlyCost.toFixed(0),"/mo"]}),d.jsx(Cr,{type:"source",position:q.Bottom,style:{background:r}})]})}const cC=M.memo(uC);function dC({data:e,selected:t}){return d.jsxs(d.Fragment,{children:[d.jsx(lC,{color:e.dotColor,isVisible:t??!1,minWidth:200,minHeight:100,lineStyle:{borderWidth:1.5},handleStyle:{width:8,height:8,borderRadius:2}}),d.jsxs("div",{style:{position:"absolute",top:6,left:8,display:"inline-flex",alignItems:"center",gap:5,padding:"3px 10px 3px 7px",borderRadius:5,background:e.labelBg,border:`1px solid ${e.dotColor}30`,boxShadow:"0 1px 2px rgba(0,0,0,0.04)",pointerEvents:"none"},children:[d.jsx("span",{style:{width:7,height:7,borderRadius:"50%",background:e.dotColor,flexShrink:0}}),d.jsx("span",{style:{color:e.labelColor,fontSize:11,fontWeight:600,letterSpacing:"0.02em",whiteSpace:"nowrap",lineHeight:1},children:e.label})]})]})}function fC({components:e}){const[t,n]=M.useState(!1),r=M.useMemo(()=>{if(!e||e.length===0)return Object.keys(ou).map(i=>({category:i,count:0}));const o={};for(const i of e){const s=wc(i.service);o[s]=(o[s]||0)+1}return Object.entries(o).sort(([,i],[,s])=>s-i).map(([i,s])=>({category:i,count:s}))},[e]);return d.jsxs("div",{style:{position:"absolute",bottom:16,left:16,zIndex:10,background:"#ffffff",border:"1px solid #e2e8f0",borderRadius:8,padding:"8px 12px",fontSize:11,color:"#64748b",boxShadow:"0 1px 4px rgba(0,0,0,0.08)",maxHeight:t?"auto":260,overflowY:t?"visible":"auto"},children:[d.jsxs("div",{onClick:()=>n(o=>!o),style:{fontWeight:600,marginBottom:t?0:4,color:"#0f172a",cursor:"pointer",userSelect:"none",display:"flex",alignItems:"center",justifyContent:"space-between",gap:8},children:["Legend",d.jsx("span",{style:{fontSize:10,color:"#94a3b8"},children:t?"+":"-"})]}),!t&&r.map(({category:o,count:i})=>{const s=ou[o]||"#94a3b8",l=Sc(o);return d.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6,marginBottom:2},children:[d.jsx("svg",{width:12,height:12,viewBox:"0 0 24 24",fill:"none",stroke:s,strokeWidth:2.5,strokeLinecap:"round",strokeLinejoin:"round",style:{flexShrink:0},children:d.jsx("path",{d:l})}),d.jsx("span",{style:{textTransform:"capitalize"},children:o}),i>0&&d.jsxs("span",{style:{color:"#94a3b8",fontSize:10},children:["(",i,")"]})]},o)})]})}function pC({onExportSvg:e,onExportPng:t,showBoundaries:n,onToggleBoundaries:r}){const o={padding:"4px 10px",borderRadius:4,border:"1px solid #e2e8f0",background:"#ffffff",color:"#475569",cursor:"pointer",fontSize:11};return d.jsxs("div",{style:{position:"absolute",top:16,right:16,zIndex:10,display:"flex",gap:4,background:"#ffffff",padding:4,border:"1px solid #e2e8f0",borderRadius:8,boxShadow:"0 1px 4px rgba(0,0,0,0.08)"},children:[e&&d.jsx("button",{style:o,onClick:e,children:"Export SVG"}),t&&d.jsx("button",{style:o,onClick:t,children:"Export PNG"}),d.jsxs("button",{style:{...o,background:n?"#f1f5f9":"#ffffff"},onClick:r,children:[n?"Hide":"Show"," Boundaries"]})]})}const Wf={borderTop:"1px solid #e2e8f0",margin:"12px 0"},bi={fontSize:11,fontWeight:600,color:"#64748b",textTransform:"uppercase",letterSpacing:"0.05em",marginBottom:8},Hl={display:"block",fontSize:12,fontWeight:600,color:"#64748b",marginBottom:5},Wr={width:"100%",boxSizing:"border-box",border:"1px solid #cbd5e1",borderRadius:6,padding:"8px 10px",color:"#0f172a",fontSize:13,outline:"none",background:"#ffffff"},Vl={display:"flex",justifyContent:"space-between",alignItems:"center",gap:10,color:"#475569",fontSize:13,marginBottom:7};function a0(e){return typeof e=="boolean"?e?"true":"false":e==null?"":String(e)}function hC(e,t){return Object.entries(e??{}).filter(([n,r])=>r!=null&&n!=="tags").map(([n,r])=>`${n}=${a0(r)}`).join(` +`)}function gC(e){const t=e==null?void 0:e.tags;return!t||typeof t!="object"||Array.isArray(t)?"":Object.entries(t).map(([n,r])=>`${n}=${a0(r)}`).join(` +`)}function mC(e){const t=e.trim();return t==="true"?!0:t==="false"?!1:t!==""&&!Number.isNaN(Number(t))?Number(t):e}function Uf(e){const t={};for(const n of e.split(` +`)){const r=n.trim();if(!r)continue;const o=r.indexOf("=");if(o===-1){t[r]=!0;continue}const i=r.slice(0,o).trim();i&&(t[i]=mC(r.slice(o+1)))}return t}function yC({component:e,cost:t,onClose:n,onApply:r,onDelete:o}){var S;const i=e!==null,[s,l]=M.useState(""),[a,u]=M.useState(""),[p,c]=M.useState("2"),[f,x]=M.useState(""),[y,v]=M.useState("");M.useEffect(()=>{e&&(l(e.label),u(e.description??""),c(String(e.tier??2)),x(hC(e.config)),v(gC(e.config)))},[e]);const k=e?wc(e.service):"compute",m=l0(k),g=Sc(k),h=(t==null?void 0:t.monthly)??null,w=M.useMemo(()=>{const b=Number(p);return Number.isFinite(b)?b:2},[p]),_=()=>{if(!e)return;const b=Uf(f),E=Uf(y);Object.keys(E).length>0&&(b.tags=E),r({...e,label:s.trim()||e.label,description:a,tier:w,config:b})};return d.jsxs("div",{style:{position:"absolute",top:0,right:0,width:340,height:"100%",background:"#ffffff",borderLeft:"1px solid #e2e8f0",transform:i?"translateX(0)":"translateX(100%)",transition:"transform 0.2s ease",zIndex:20,display:"flex",flexDirection:"column",overflow:"hidden",boxShadow:"-2px 0 8px rgba(0,0,0,0.06)"},children:[d.jsxs("div",{style:{padding:"16px 16px 12px",borderBottom:"1px solid #e2e8f0"},children:[d.jsxs("div",{style:{display:"flex",alignItems:"center",gap:10,marginBottom:8},children:[d.jsx("div",{style:{width:36,height:36,borderRadius:8,background:`${m}22`,border:`1.5px solid ${m}`,display:"flex",alignItems:"center",justifyContent:"center",flexShrink:0},children:d.jsx("svg",{width:20,height:20,viewBox:"0 0 24 24",fill:"none",stroke:m,strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round",style:{display:"block"},children:d.jsx("path",{d:g})})}),d.jsx("span",{style:{fontSize:16,fontWeight:700,color:"#0f172a",flex:1,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:(e==null?void 0:e.label)??"Resource"}),d.jsx("button",{onClick:n,style:{background:"none",border:"none",color:"#94a3b8",cursor:"pointer",fontSize:18,lineHeight:1,padding:"2px 4px",flexShrink:0},"aria-label":"Close panel",children:"x"})]}),d.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8},children:[d.jsx("span",{style:{background:"#f1f5f9",color:"#475569",borderRadius:4,fontSize:11,fontWeight:600,padding:"2px 8px",textTransform:"uppercase"},children:e==null?void 0:e.provider}),d.jsx("span",{style:{color:"#64748b",fontSize:12},children:e==null?void 0:e.service})]})]}),d.jsxs("div",{style:{flex:1,overflowY:"auto",padding:"12px 16px"},children:[d.jsx("div",{style:bi,children:"Overview"}),d.jsx("label",{style:Hl,htmlFor:"resource-label",children:"Label"}),d.jsx("input",{id:"resource-label","aria-label":"Label",value:s,onChange:b=>l(b.target.value),style:{...Wr,marginBottom:10}}),d.jsx("label",{style:Hl,htmlFor:"resource-description",children:"Description"}),d.jsx("textarea",{id:"resource-description","aria-label":"Description",value:a,onChange:b=>u(b.target.value),rows:3,style:{...Wr,marginBottom:10,resize:"vertical",minHeight:72}}),d.jsx("label",{style:Hl,htmlFor:"resource-tier",children:"Tier"}),d.jsx("input",{id:"resource-tier","aria-label":"Tier",type:"number",value:p,onChange:b=>c(b.target.value),style:{...Wr,marginBottom:10}}),d.jsxs("div",{style:Vl,children:[d.jsx("span",{children:"Service"}),d.jsx("strong",{style:{color:"#0f172a"},children:e==null?void 0:e.service})]}),d.jsxs("div",{style:Vl,children:[d.jsx("span",{children:"Provider"}),d.jsx("strong",{style:{color:"#0f172a"},children:(S=e==null?void 0:e.provider)==null?void 0:S.toUpperCase()})]}),d.jsx("div",{style:Wf}),d.jsx("div",{style:bi,children:"Cost"}),h!==null?d.jsxs("div",{style:Vl,children:[d.jsx("span",{children:"Monthly"}),d.jsxs("strong",{style:{color:"#2563eb"},children:["$",h.toLocaleString(void 0,{minimumFractionDigits:2,maximumFractionDigits:2})]})]}):d.jsx("p",{style:{color:"#94a3b8",fontSize:13},children:"No cost data"}),d.jsx("div",{style:Wf}),d.jsx("div",{style:bi,children:"Configuration"}),d.jsx("textarea",{"aria-label":"Configuration",value:f,onChange:b=>x(b.target.value),rows:7,style:{...Wr,resize:"vertical",minHeight:140,fontFamily:"ui-monospace, SFMono-Regular, Menlo, monospace"}}),d.jsx("div",{style:{...bi,marginTop:16},children:"Tags"}),d.jsx("textarea",{"aria-label":"Tags",value:y,onChange:b=>v(b.target.value),rows:5,style:{...Wr,resize:"vertical",minHeight:110,fontFamily:"ui-monospace, SFMono-Regular, Menlo, monospace"}})]}),d.jsxs("div",{style:{padding:12,borderTop:"1px solid #e2e8f0",display:"flex",gap:8},children:[d.jsx("button",{onClick:_,disabled:!e,style:{flex:1,border:"none",borderRadius:6,padding:"10px 12px",background:"#2563eb",color:"#ffffff",cursor:e?"pointer":"not-allowed",fontSize:14,fontWeight:700},children:"Apply"}),d.jsx("button",{onClick:()=>e&&o(e.id),disabled:!e,style:{border:"1px solid #fecaca",borderRadius:6,padding:"10px 12px",background:"#fef2f2",color:"#b91c1c",cursor:e?"pointer":"not-allowed",fontSize:14,fontWeight:700},children:"Delete"})]})]})}const Yf="/api",Wl={border:"1px solid #cbd5e1",background:"#ffffff",color:"#0f172a",borderRadius:6,padding:"7px 10px",cursor:"pointer",fontSize:12,fontWeight:600};function xC({provider:e,standardsResult:t,onAddResource:n,onAddModule:r,onCheckStandards:o}){const i=(e||"aws").toLowerCase(),[s,l]=M.useState(!0),[a,u]=M.useState("resources"),[p,c]=M.useState(""),[f,x]=M.useState([]),[y,v]=M.useState([]);M.useEffect(()=>{fetch(`${Yf}/catalog/services?provider=${encodeURIComponent(i)}`).then(g=>g.ok?g.json():null).then(g=>x((g==null?void 0:g.services)??[])).catch(()=>x([]))},[i]),M.useEffect(()=>{fetch(`${Yf}/modules`).then(g=>g.ok?g.json():null).then(g=>v((g==null?void 0:g.modules)??[])).catch(()=>v([]))},[]);const k=M.useMemo(()=>{const g=p.trim().toLowerCase();return g?f.filter(h=>[h.name,h.service_key,h.category,h.description??""].some(w=>w.toLowerCase().includes(g))):f},[f,p]),m=M.useMemo(()=>{const g=p.trim().toLowerCase(),h=y.filter(w=>w.provider.toLowerCase()===i);return g?h.filter(w=>[w.name,w.id,w.category,w.description??"",...w.tags??[]].some(_=>_.toLowerCase().includes(g))):h},[y,i,p]);return s?d.jsxs("div",{style:{position:"absolute",top:0,left:0,width:320,height:"100%",zIndex:14,background:"#ffffff",borderRight:"1px solid #e2e8f0",boxShadow:"2px 0 8px rgba(0,0,0,0.06)",display:"flex",flexDirection:"column"},children:[d.jsxs("div",{style:{padding:14,borderBottom:"1px solid #e2e8f0"},children:[d.jsxs("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:10},children:[d.jsx("div",{style:{fontSize:15,fontWeight:700,color:"#0f172a"},children:"Catalog"}),d.jsx("button",{onClick:()=>l(!1),style:{border:"none",background:"transparent",color:"#64748b",cursor:"pointer",fontSize:18},"aria-label":"Close catalog",children:"x"})]}),d.jsx("div",{style:{display:"grid",gridTemplateColumns:"1fr 1fr 1fr",gap:4,marginBottom:10},children:["resources","modules","standards"].map(g=>d.jsx("button",{onClick:()=>u(g),style:{...Wl,padding:"6px 4px",borderColor:a===g?"#2563eb":"#cbd5e1",color:a===g?"#2563eb":"#475569",background:a===g?"#eff6ff":"#ffffff",textTransform:"capitalize"},children:g},g))}),a!=="standards"&&d.jsx("input",{value:p,onChange:g=>c(g.target.value),placeholder:"Search",style:{width:"100%",boxSizing:"border-box",border:"1px solid #cbd5e1",borderRadius:6,padding:"8px 10px",color:"#0f172a",fontSize:13,outline:"none"}})]}),d.jsxs("div",{style:{flex:1,overflowY:"auto",padding:12},children:[a==="resources"&&k.map(g=>d.jsxs("button",{onClick:()=>n(g),style:{width:"100%",textAlign:"left",border:"1px solid #e2e8f0",background:"#ffffff",borderRadius:8,padding:10,marginBottom:8,cursor:"pointer"},children:[d.jsxs("div",{style:{display:"flex",justifyContent:"space-between",gap:8},children:[d.jsx("span",{style:{color:"#0f172a",fontSize:13,fontWeight:700},children:g.name}),d.jsx("span",{style:{color:"#64748b",fontSize:10,textTransform:"uppercase"},children:g.category.replace(/_/g," ")})]}),d.jsx("div",{style:{color:"#64748b",fontSize:11,marginTop:4},children:g.service_key})]},`${g.provider}:${g.service_key}`)),a==="resources"&&k.length===0&&d.jsxs("p",{style:{color:"#64748b",fontSize:13},children:["No resources found for ",i.toUpperCase(),"."]}),a==="modules"&&m.map(g=>d.jsxs("button",{onClick:()=>r(g.id),style:{width:"100%",textAlign:"left",border:"1px solid #bfdbfe",background:"#eff6ff",borderRadius:8,padding:10,marginBottom:8,cursor:"pointer"},children:[d.jsx("div",{style:{color:"#0f172a",fontSize:13,fontWeight:700},children:g.name}),d.jsx("div",{style:{color:"#475569",fontSize:12,marginTop:4,lineHeight:1.35},children:g.description}),d.jsx("div",{style:{color:"#2563eb",fontSize:11,marginTop:6,textTransform:"uppercase"},children:g.category})]},g.id)),a==="modules"&&m.length===0&&d.jsxs("p",{style:{color:"#64748b",fontSize:13},children:["No approved modules found for ",i.toUpperCase(),"."]}),a==="standards"&&d.jsxs(d.Fragment,{children:[d.jsx("button",{onClick:o,style:{...Wl,width:"100%",marginBottom:12},children:"Check Standards"}),!t&&d.jsx("p",{style:{color:"#64748b",fontSize:13},children:"No standards check has run."}),(t==null?void 0:t.passed)&&d.jsx("div",{style:{color:"#166534",background:"#dcfce7",borderRadius:8,padding:10,fontSize:13},children:"Standards passed."}),t&&!t.passed&&d.jsx("div",{children:t.violations.map((g,h)=>d.jsxs("div",{style:{border:"1px solid #fecaca",background:"#fef2f2",borderRadius:8,padding:10,marginBottom:8},children:[d.jsx("div",{style:{color:"#991b1b",fontSize:12,fontWeight:700},children:g.code.replace(/_/g," ")}),d.jsx("div",{style:{color:"#7f1d1d",fontSize:12,marginTop:4,lineHeight:1.4},children:g.message})]},`${g.code}:${h}`))})]})]})]}):d.jsx("button",{onClick:()=>l(!0),style:{...Wl,position:"absolute",left:16,top:16,zIndex:15,boxShadow:"0 1px 4px rgba(0,0,0,0.08)"},children:"Add Resource"})}const Xf=200,Ci=90,Qf=300,vC=240,yt=32,wC=36,Ur=4,Ul="/api",SC={0:"Edge / CDN",1:"Network / Ingress",2:"Application",3:"Data Layer",4:"Platform Services",5:"Platform Services"},kC={0:"edge",1:"subnet",2:"subnet",3:"subnet"},Yl={0:{border:"#60a5fa",bg:"rgba(219, 234, 254, 0.18)",labelColor:"#1d4ed8",labelBg:"rgba(219, 234, 254, 0.92)",dot:"#3b82f6"},1:{border:"#34d399",bg:"rgba(209, 250, 229, 0.18)",labelColor:"#047857",labelBg:"rgba(209, 250, 229, 0.92)",dot:"#10b981"},2:{border:"#fb923c",bg:"rgba(255, 237, 213, 0.18)",labelColor:"#9a3412",labelBg:"rgba(255, 237, 213, 0.92)",dot:"#f97316"},3:{border:"#a78bfa",bg:"rgba(237, 233, 254, 0.18)",labelColor:"#5b21b6",labelBg:"rgba(237, 233, 254, 0.92)",dot:"#8b5cf6"},4:{border:"#2dd4bf",bg:"rgba(204, 251, 241, 0.18)",labelColor:"#0f766e",labelBg:"rgba(204, 251, 241, 0.92)",dot:"#14b8a6"},5:{border:"#2dd4bf",bg:"rgba(204, 251, 241, 0.18)",labelColor:"#0f766e",labelBg:"rgba(204, 251, 241, 0.92)",dot:"#14b8a6"}},Hn={border:"#94a3b8",bg:"rgba(241, 245, 249, 0.35)",labelColor:"#475569",labelBg:"rgba(241, 245, 249, 0.92)",dot:"#94a3b8"},_C={cloudService:cC,boundaryGroup:dC};function iu(e){return JSON.parse(JSON.stringify(e))}function Ei(e){return iu(e??{})}function ji(e,t="resource"){let n=e.trim().toLowerCase().replace(/[^a-z0-9_-]+/g,"_").replace(/^[_-]+|[_-]+$/g,"");return n||(n=t),/^[a-z_]/.test(n)||(n=`${t}_${n}`),n}function Xl(e,t){let n=e,r=2;for(;t.has(n);)n=`${e}-${r}`,r+=1;return t.add(n),n}function bC(e){const t=e.toLowerCase();return t.includes("cdn")||t.includes("edge")?0:t.includes("network")||t.includes("security")?1:t.includes("database")||t.includes("cache")?3:t.includes("storage")||t.includes("analytics")||t.includes("data")?4:2}function Gf(e){return{x:360+e%3*260,y:80+Math.floor(e/3)*150}}function CC(e,t){if(t==="vpc")return Hn;const n=e.match(/^tier-(\d+)$/);return n&&Yl[parseInt(n[1])]||Yl[2]}function EC(e){const t={};for(const i of e){const s=i.tier??2;t[s]||(t[s]=[]),t[s].push(i.id)}const n=Object.keys(t).map(Number).sort(),r=[];for(const i of n)r.push({id:`tier-${i}`,kind:kC[i]||"subnet",label:SC[i]||`Tier ${i}`,component_ids:t[i]});const o=r.filter(i=>i.id!=="tier-0").flatMap(i=>i.component_ids);return o.length>=2&&r.unshift({id:"vpc",kind:"vpc",label:"VPC / Virtual Network",component_ids:o}),r}function jC(e,t,n){var y,v,k,m;const r=[],o=e.boundaries||[],i=o.length>0?o:EC(e.components),s=((v=(y=e.metadata)==null?void 0:y.canvas)==null?void 0:v.nodes)??{},l={};if(t){for(const g of i)if(g.kind!=="vpc")for(const h of g.component_ids)l[h]||(l[h]=g.id)}const a={};for(const g of e.components){const h=g.tier??2;a[h]||(a[h]=[]),a[h].push(g)}const u=Object.keys(a).map(Number).sort(),p={};let c=40;const f={};for(const g of u){f[g]=c;const h=Math.ceil(a[g].length/Ur);c+=vC+(h-1)*(Ci+60)}for(const g of u){const h=a[g],w=f[g];for(let _=0;_0){const g=i.find(w=>w.kind==="vpc");let h;if(g&&g.component_ids.length>0){const w=g.component_ids.map(D=>{var P;return((P=p[D])==null?void 0:P.x)??0}),_=g.component_ids.map(D=>{var P;return((P=p[D])==null?void 0:P.y)??0}),S=Math.min(...w)-yt,b=Math.min(..._)-yt-24-wC,E=Math.max(...w)+Xf+yt,A=Math.max(..._)+Ci+yt;h=`boundary-${g.id}`,x[g.id]={x:S,y:b},r.push({id:h,type:"boundaryGroup",position:{x:S,y:b},data:{label:g.label||g.id,labelColor:Hn.labelColor,labelBg:Hn.labelBg,dotColor:Hn.dot},style:{background:Hn.bg,border:`2px dashed ${Hn.border}`,borderRadius:16,padding:yt,width:E-S,height:A-b},zIndex:-2})}for(const w of i){if(w.kind==="vpc"||w.component_ids.length===0)continue;const _=w.component_ids.map(T=>{var C;return((C=p[T])==null?void 0:C.x)??0}),S=w.component_ids.map(T=>{var C;return((C=p[T])==null?void 0:C.y)??0}),b=Math.min(..._)-yt,E=Math.min(...S)-yt-24,A=Math.max(..._)+Xf+yt,D=Math.max(...S)+Ci+yt;x[w.id]={x:b,y:E};const P=CC(w.id,w.kind),I=!!(h&&g&&w.component_ids.some(T=>g.component_ids.includes(T)));r.push({id:`boundary-${w.id}`,type:"boundaryGroup",position:I?{x:b-x[g.id].x,y:E-x[g.id].y}:{x:b,y:E},data:{label:w.label||w.id,labelColor:P.labelColor,labelBg:P.labelBg,dotColor:P.dot},style:{background:P.bg,border:`1.5px solid ${P.border}`,borderRadius:10,padding:yt,width:A-b,height:D-E},zIndex:-1,parentId:I?h:void 0})}}for(const g of u){const h=a[g];for(const w of h){const _=l[w.id],S=t&&_&&x[_];let b=((k=p[w.id])==null?void 0:k.x)??0,E=((m=p[w.id])==null?void 0:m.y)??0;S&&(b-=x[_].x,E-=x[_].y),r.push({id:w.id,type:"cloudService",position:{x:b,y:E},data:{label:w.label,service:w.service,provider:w.provider,description:w.description,tier:w.tier,config:w.config||{},monthlyCost:n[w.id]},parentId:S?`boundary-${_}`:void 0,extent:S?"parent":void 0})}}return r}function u0(e,t){return`edge:${e.source}:${e.target}:${t}`}function Kf(e){return e.connections.map((t,n)=>{let r=t.label||"";return t.protocol&&!r.includes(t.protocol)&&(r=t.protocol+(t.port?`:${t.port}`:"")),{id:u0(t,n),source:t.source,target:t.target,label:r,style:{stroke:"#94a3b8"},labelStyle:{fill:"#64748b",fontSize:11},animated:!0}})}function NC(e,t){return e&&e.map(n=>({...n,component_ids:n.component_ids.filter(r=>r!==t)}))}function MC({spec:e,onSpecChange:t}){const[n,r]=M.useState(!0),[o,i]=M.useState(null),[s,l]=M.useState(null),a=M.useCallback(T=>{l(null),t(T)},[t]),u=M.useCallback(async T=>{try{const C=await fetch(`${Ul}/export`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({spec:e,format:T})});if(!C.ok)return;const L=await C.blob(),z=URL.createObjectURL(L),R=document.createElement("a");R.href=z,R.download=`architecture.${T}`,R.click(),URL.revokeObjectURL(z)}catch{}},[e]),p=M.useMemo(()=>{var C;const T={};for(const L of((C=e.cost_estimate)==null?void 0:C.breakdown)??[])T[L.component_id]=L.monthly;return T},[e.cost_estimate]),c=M.useMemo(()=>o?e.components.find(T=>T.id===o)??null:null,[o,e.components]),f=M.useMemo(()=>{var T;return o?((T=e.cost_estimate)==null?void 0:T.breakdown.find(C=>C.component_id===o))??null:null},[o,e.cost_estimate]),[x,y,v]=Pb([]),[k,m,g]=Ib([]);M.useEffect(()=>{y(jC(e,n,p)),m(Kf(e))},[e,n,p,y,m]);const h=M.useCallback((T,C)=>{C.id.startsWith("boundary-")||i(C.id)},[]),w=M.useCallback(()=>{i(null)},[]),_=M.useCallback((T,C)=>{if(C.id.startsWith("boundary-"))return;const L=Ei(e.metadata),z=L.canvas??{},R={...z.nodes??{}},j=x.find($=>$.id===C.parentId),N=j?{x:j.position.x+C.position.x,y:j.position.y+C.position.y}:{x:C.position.x,y:C.position.y};R[C.id]=N,L.canvas={...z,nodes:R},a({...e,metadata:L})},[a,x,e]),S=M.useCallback(T=>{!T.source||!T.target||T.source===T.target||e.connections.some(L=>L.source===T.source&&L.target===T.target)||a({...e,connections:[...e.connections,{source:T.source,target:T.target,label:"HTTPS",protocol:"HTTPS",port:443}]})},[a,e]),b=M.useCallback(T=>{if(T.length===0)return;if(!window.confirm(`Delete ${T.length===1?"this connection":"these connections"}?`)){m(Kf(e));return}const C=new Set(T.map(L=>L.id));a({...e,connections:e.connections.filter((L,z)=>!C.has(u0(L,z)))})},[a,m,e]),E=M.useCallback(T=>{a({...e,components:e.components.map(C=>C.id===T.id?T:C)})},[a,e]),A=M.useCallback(T=>{var R,j;const C=e.components.find(N=>N.id===T);if(!C||!window.confirm(`Delete ${C.label||C.id} and its connections?`))return;const L=Ei(e.metadata);(R=L.canvas)!=null&&R.nodes&&delete L.canvas.nodes[T];const z=((j=L.modules)==null?void 0:j.instances)??{};for(const N of Object.values(z))N.component_ids.includes(T)&&(N.component_ids=N.component_ids.filter($=>$!==T),N.partial=!0,N.approved=!1,delete N.terraform);L.modules&&(L.modules.instances=z),a({...e,components:e.components.filter(N=>N.id!==T),connections:e.connections.filter(N=>N.source!==T&&N.target!==T),boundaries:NC(e.boundaries,T),metadata:L}),i(null)},[a,e]),D=M.useCallback(T=>{const C=new Set(e.components.map($=>$.id)),L=Xl(ji(T.service_key),C),z=Ei(e.metadata),R=z.canvas??{},j={...R.nodes??{}};j[L]=Gf(Object.keys(j).length+e.components.length),z.canvas={...R,nodes:j};const N={id:L,service:T.service_key,provider:T.provider.toLowerCase(),label:T.name,description:T.description??"",tier:bC(T.category),config:iu(T.default_config??{})};a({...e,components:[...e.components,N],metadata:z}),i(L)},[a,e]),P=M.useCallback(async T=>{var C;try{const L=await fetch(`${Ul}/modules/${encodeURIComponent(T)}`);if(!L.ok)return;const R=(await L.json()).module,j=new Set(e.components.map(G=>G.id)),N=Ei(e.metadata),$=N.modules??{},O={...$.instances??{}},B=new Set(Object.keys(O)),W=Xl(ji(R.id,"module"),B),V=ji(R.naming.component_id_prefix,W),Y={};for(const G of R.fragment.components)Y[G.id]=Xl(ji(`${V}_${G.id}`,V),j);const X=N.canvas??{},Q={...X.nodes??{}},H=Object.keys(Q).length+e.components.length,K=R.fragment.components.map((G,J)=>{const Z=iu(G.config??{}),re={...R.default_tags??{},...typeof Z.tags=="object"&&Z.tags!==null?Z.tags:{}};Z.tags=re;const le=Y[G.id];return Q[le]=Gf(H+J),{...G,id:le,provider:G.provider.toLowerCase(),config:Z}}),ee=R.fragment.connections.map(G=>({...G,source:Y[G.source],target:Y[G.target]}));O[W]={module_id:R.id,module_version:R.terraform.version,component_ids:K.map(G=>G.id),expected_component_count:K.length,required_tags:[...R.required_tags],naming_prefix:V,approved:R.approved,terraform:{...R.terraform}},N.canvas={...X,nodes:Q},N.modules={...$,instances:O},a({...e,components:[...e.components,...K],connections:[...e.connections,...ee],metadata:N}),i(((C=K[0])==null?void 0:C.id)??null)}catch{}},[a,e]),I=M.useCallback(async()=>{try{const T=await fetch(`${Ul}/canvas/validate`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({spec:e})});if(!T.ok)return;l(await T.json())}catch{l({passed:!1,violations:[{code:"request_failed",severity:"error",message:"Standards check failed."}]})}},[e]);return d.jsxs("div",{style:{width:"100%",height:"100%",position:"relative"},children:[d.jsx(xC,{provider:e.provider||"aws",standardsResult:s,onAddResource:D,onAddModule:P,onCheckStandards:I}),d.jsxs(Tb,{nodes:x,edges:k,nodeTypes:_C,onNodesChange:v,onEdgesChange:g,onEdgesDelete:b,onConnect:S,onNodeDragStop:_,fitView:!0,proOptions:{hideAttribution:!0},style:{background:"#f8fafc"},onNodeClick:h,onPaneClick:w,children:[d.jsx(Db,{color:"#e2e8f0",gap:20}),d.jsx(Ub,{style:{background:"#ffffff",border:"1px solid #e2e8f0",borderRadius:8}})]}),d.jsx(fC,{components:e.components}),d.jsx(pC,{showBoundaries:n,onToggleBoundaries:()=>r(T=>!T),onExportSvg:()=>u("svg"),onExportPng:()=>u("png")}),d.jsx(yC,{component:c??null,cost:f,onClose:()=>i(null),onApply:T=>E({...T,description:T.description??"",config:T.config??{}}),onDelete:A})]})}function zC({estimate:e}){return d.jsxs("div",{style:{padding:32},children:[d.jsx("h2",{style:{fontSize:18,marginBottom:16,color:"#0f172a"},children:"Cost Breakdown"}),d.jsxs("table",{style:{width:"100%",maxWidth:700,borderCollapse:"collapse",fontSize:14},children:[d.jsx("thead",{children:d.jsxs("tr",{style:{borderBottom:"2px solid #e2e8f0",background:"#f8fafc"},children:[d.jsx("th",{style:{textAlign:"left",padding:"10px 12px",color:"#475569"},children:"Component"}),d.jsx("th",{style:{textAlign:"left",padding:"10px 12px",color:"#475569"},children:"Service"}),d.jsx("th",{style:{textAlign:"right",padding:"10px 12px",color:"#475569"},children:"Monthly"}),d.jsx("th",{style:{textAlign:"left",padding:"10px 12px",color:"#475569"},children:"Notes"})]})}),d.jsx("tbody",{children:e.breakdown.map(t=>d.jsxs("tr",{style:{borderBottom:"1px solid #f1f5f9"},children:[d.jsx("td",{style:{padding:"10px 12px",color:"#0f172a"},children:t.component_id}),d.jsx("td",{style:{padding:"10px 12px",color:"#475569"},children:t.service}),d.jsxs("td",{style:{padding:"10px 12px",textAlign:"right",fontFamily:"monospace",color:"#0f172a"},children:["$",t.monthly.toFixed(2)]}),d.jsx("td",{style:{padding:"10px 12px",color:"#64748b",fontSize:12},children:t.notes})]},t.component_id))}),d.jsx("tfoot",{children:d.jsxs("tr",{style:{borderTop:"2px solid #e2e8f0",background:"#f0f9ff"},children:[d.jsx("td",{style:{padding:"12px",fontWeight:700,fontSize:15,color:"#0f172a"},colSpan:2,children:"Total"}),d.jsxs("td",{style:{padding:"12px",textAlign:"right",fontWeight:700,fontSize:15,fontFamily:"monospace",color:"#2563eb"},children:["$",e.monthly_total.toFixed(2)]}),d.jsxs("td",{style:{padding:"12px",color:"#64748b",fontSize:12},children:[e.currency,"/month"]})]})})]})]})}function TC({spec:e,onDownloadTerraform:t,onDownloadYaml:n,validationSummary:r,usage:o}){var s,l;if(!e)return null;const i=[];return o!=null&&o.model&&i.push(o.model.replace("claude-","").replace("anthropic.","")),(o==null?void 0:o.input_tokens)!=null&&(o==null?void 0:o.output_tokens)!=null&&i.push(`${((o.input_tokens+o.output_tokens)/1e3).toFixed(1)}k tokens`),(o==null?void 0:o.cost_usd)!=null&&i.push(`$${o.cost_usd.toFixed(4)}`),(o==null?void 0:o.latency_ms)!=null&&i.push(`${(o.latency_ms/1e3).toFixed(1)}s`),d.jsxs("div",{style:{display:"flex",alignItems:"center",gap:"1rem",padding:"0.5rem 1rem",background:"#ffffff",borderRadius:"0.375rem",marginBottom:"0.5rem",fontSize:"0.875rem",borderBottom:"1px solid #e2e8f0"},children:[d.jsxs("span",{style:{color:"#64748b"},children:["Components: ",d.jsx("strong",{style:{color:"#334155"},children:((s=e.components)==null?void 0:s.length)||0})]}),e.cost_estimate&&d.jsxs("span",{style:{color:"#64748b"},children:["Est. ",d.jsxs("strong",{style:{color:"#2563eb"},children:["$",(l=e.cost_estimate.monthly_total)==null?void 0:l.toFixed(0),"/mo"]})]}),d.jsxs("span",{style:{color:"#64748b"},children:[(e.provider||"aws").toUpperCase()," / ",e.region||"us-east-1"]}),r&&d.jsxs("span",{style:{padding:"0.125rem 0.5rem",borderRadius:"0.25rem",fontSize:"0.75rem",fontWeight:600,background:r.passed===r.total?"#d1fae5":"#fee2e2",color:r.passed===r.total?"#065f46":"#991b1b"},children:["WA: ",r.passed,"/",r.total]}),i.length>0&&d.jsx("span",{style:{color:"#94a3b8",fontSize:"0.75rem"},children:i.join(" · ")}),d.jsxs("div",{style:{marginLeft:"auto",display:"flex",gap:"0.5rem"},children:[t&&d.jsx("button",{onClick:t,style:{padding:"0.25rem 0.75rem",background:"#2563eb",color:"white",border:"none",borderRadius:"0.25rem",cursor:"pointer",fontSize:"0.75rem"},children:"Download Terraform"}),n&&d.jsx("button",{onClick:n,style:{padding:"0.25rem 0.75rem",background:"#f8fafc",color:"#475569",border:"1px solid #e2e8f0",borderRadius:"0.25rem",cursor:"pointer",fontSize:"0.75rem"},children:"Download YAML"})]})]})}async function Mr(e){if(e.status===429){const t=e.headers.get("Retry-After"),n=t?` Retry after ${t}s.`:"";try{const r=await e.json();return`${r.message||r.detail||"Rate limited"}${n}`}catch{return`Rate limited.${n}`}}try{const t=await e.json();return su(t,e.statusText)}catch{return e.statusText||"Request failed"}}function su(e,t="Request failed"){const n=e.message||e.detail||t;return e.suggestion?`${n} — ${e.suggestion}`:n}const PC=[{key:"hipaa",label:"HIPAA"},{key:"pci-dss",label:"PCI-DSS"},{key:"soc2",label:"SOC 2"},{key:"fedramp",label:"FedRAMP"},{key:"gdpr",label:"GDPR"},{key:"well-architected",label:"Well-Architected"}],Ni={critical:0,high:1,medium:2,low:3},Do={critical:{bg:"#fef2f2",text:"#991b1b",border:"#fca5a5"},high:{bg:"#fff7ed",text:"#9a3412",border:"#fdba74"},medium:{bg:"#fffbeb",text:"#92400e",border:"#fcd34d"},low:{bg:"#f0fdf4",text:"#166534",border:"#86efac"}},IC={data_protection:"Data Protection",monitoring:"Monitoring & Logging",identity:"Identity & Access",network_security:"Network Security",reliability:"Reliability",compliance:"Compliance",operations:"Operations",security:"Security",cost:"Cost Optimization"};function RC({score:e,passed:t}){const n=Math.round(e*100),r=54,o=8,i=2*Math.PI*r,s=i*(1-e),l=t?"#16a34a":n>=70?"#f59e0b":"#dc2626";return d.jsxs("div",{style:{display:"flex",flexDirection:"column",alignItems:"center",gap:6},children:[d.jsxs("svg",{width:136,height:136,viewBox:"0 0 136 136",children:[d.jsx("circle",{cx:68,cy:68,r,fill:"none",stroke:"#f1f5f9",strokeWidth:o}),d.jsx("circle",{cx:68,cy:68,r,fill:"none",stroke:l,strokeWidth:o,strokeDasharray:i,strokeDashoffset:s,strokeLinecap:"round",transform:"rotate(-90 68 68)",style:{transition:"stroke-dashoffset 0.6s ease"}}),d.jsxs("text",{x:68,y:62,textAnchor:"middle",fontSize:28,fontWeight:700,fill:"#0f172a",children:[n,"%"]}),d.jsx("text",{x:68,y:82,textAnchor:"middle",fontSize:11,fill:"#64748b",children:"compliance"})]}),d.jsx("span",{style:{display:"inline-block",padding:"3px 12px",borderRadius:4,fontSize:12,fontWeight:600,background:t?"#dcfce7":"#fee2e2",color:t?"#166534":"#991b1b"},children:t?"PASSED":"FAILED"})]})}function LC({severity:e}){const t=Do[e]||Do.medium;return d.jsx("span",{style:{display:"inline-block",padding:"1px 8px",borderRadius:4,fontSize:11,fontWeight:600,background:t.bg,color:t.text,border:`1px solid ${t.border}`,textTransform:"uppercase",letterSpacing:"0.02em"},children:e})}function Zf({check:e,expanded:t,onToggle:n}){const r=Do[e.severity]||Do.medium;return d.jsxs("div",{style:{borderLeft:`3px solid ${e.passed?"#86efac":r.border}`,background:"#ffffff",borderRadius:"0 6px 6px 0",marginBottom:6,cursor:"pointer",transition:"box-shadow 0.15s ease"},onClick:n,onMouseEnter:o=>{o.currentTarget.style.boxShadow="0 1px 4px rgba(0,0,0,0.06)"},onMouseLeave:o=>{o.currentTarget.style.boxShadow="none"},children:[d.jsxs("div",{style:{display:"flex",alignItems:"center",gap:10,padding:"10px 14px"},children:[d.jsx("span",{style:{fontSize:14,flexShrink:0,width:18,textAlign:"center"},children:e.passed?d.jsx("span",{style:{color:"#16a34a"},children:"✓"}):d.jsx("span",{style:{color:"#dc2626",fontWeight:700},children:"✕"})}),d.jsx("span",{style:{flex:1,fontSize:13,color:"#0f172a",fontWeight:500},children:e.name.replace(/_/g," ").replace(/\b\w/g,o=>o.toUpperCase())}),d.jsx(LC,{severity:e.severity}),d.jsx("span",{style:{fontSize:11,color:"#94a3b8",transform:t?"rotate(180deg)":"rotate(0deg)",transition:"transform 0.15s ease",flexShrink:0},children:"▼"})]}),t&&d.jsxs("div",{style:{padding:"0 14px 12px 42px",fontSize:12,lineHeight:1.6},children:[d.jsx("div",{style:{color:"#475569",marginBottom:4},children:e.detail}),e.recommendation&&d.jsxs("div",{style:{marginTop:6,padding:"8px 12px",background:"#f8fafc",borderRadius:4,border:"1px solid #e2e8f0",color:"#334155"},children:[d.jsx("span",{style:{fontWeight:600,color:"#475569",fontSize:11},children:"Recommendation: "}),e.recommendation]})]})]})}function AC({spec:e,apiBase:t}){const[n,r]=M.useState(null),[o,i]=M.useState(null),[s,l]=M.useState(!1),[a,u]=M.useState(null),[p,c]=M.useState(new Set),[f,x]=M.useState(!1),y=M.useCallback(async _=>{i(_),l(!0),u(null),c(new Set),x(!1);try{const S=_==="well-architected",b=await fetch(`${t}/validate`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({spec:e,compliance:S?[]:[_],well_architected:S})});if(!b.ok)throw new Error(await Mr(b));const E=await b.json();r(E.results)}catch(S){u(S instanceof Error?S.message:"Validation failed"),r(null)}finally{l(!1)}},[e,t]),v=M.useCallback(_=>{c(S=>{const b=new Set(S);return b.has(_)?b.delete(_):b.add(_),b})},[]),k=(n==null?void 0:n[0])??null,m=k?k.checks.filter(_=>!_.passed).sort((_,S)=>(Ni[_.severity]??9)-(Ni[S.severity]??9)):[],g=k?k.checks.filter(_=>_.passed).sort((_,S)=>(Ni[_.severity]??9)-(Ni[S.severity]??9)):[],h={};for(const _ of m){const S=_.category;h[S]||(h[S]=[]),h[S].push(_)}const w=k?k.checks.reduce((_,S)=>(S.passed||(_[S.severity]=(_[S.severity]||0)+1),_),{}):{};return d.jsxs("div",{style:{padding:32,maxWidth:900},children:[d.jsx("h2",{style:{fontSize:18,marginBottom:16,color:"#0f172a",fontWeight:700},children:"Validate Architecture"}),d.jsx("div",{style:{display:"flex",gap:8,marginBottom:24},children:PC.map(_=>{const S=o===_.key;return d.jsx("button",{onClick:()=>y(_.key),disabled:s,style:{padding:"8px 18px",borderRadius:6,border:S?"1.5px solid #2563eb":"1px solid #e2e8f0",background:S?"#eff6ff":"#ffffff",color:S?"#1d4ed8":"#475569",cursor:s?"wait":"pointer",fontSize:13,fontWeight:S?600:500,transition:"all 0.15s ease",opacity:s&&!S?.6:1},children:_.label},_.key)})}),s&&d.jsxs("div",{style:{display:"flex",alignItems:"center",gap:10,padding:24,color:"#64748b",fontSize:14},children:[d.jsx("span",{style:{display:"inline-block",width:16,height:16,border:"2px solid #e2e8f0",borderTopColor:"#2563eb",borderRadius:"50%",animation:"spin 0.6s linear infinite"}}),"Running ",o==null?void 0:o.toUpperCase()," validation...",d.jsx("style",{children:"@keyframes spin { to { transform: rotate(360deg); } }"})]}),a&&d.jsx("div",{style:{padding:"12px 16px",background:"#fef2f2",border:"1px solid #fca5a5",borderRadius:8,color:"#991b1b",fontSize:13},children:a}),k&&!s&&d.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:24},children:[d.jsxs("div",{style:{display:"flex",gap:24,alignItems:"flex-start",padding:20,background:"#ffffff",border:"1px solid #e2e8f0",borderRadius:10},children:[d.jsx(RC,{score:k.score,passed:k.passed}),d.jsxs("div",{style:{flex:1},children:[d.jsx("div",{style:{fontSize:16,fontWeight:700,color:"#0f172a",marginBottom:4},children:k.framework}),d.jsxs("div",{style:{fontSize:13,color:"#64748b",marginBottom:14},children:[k.checks.length," checks evaluated ·"," ",g.length," passed ·"," ",m.length," failed"]}),d.jsx("div",{style:{display:"flex",gap:10,flexWrap:"wrap"},children:["critical","high","medium","low"].map(_=>{const S=w[_]||0,b=Do[_];return d.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,padding:"6px 12px",borderRadius:6,background:S>0?b.bg:"#f8fafc",border:`1px solid ${S>0?b.border:"#e2e8f0"}`,minWidth:100},children:[d.jsx("span",{style:{fontSize:18,fontWeight:700,color:S>0?b.text:"#cbd5e1",lineHeight:1},children:S}),d.jsx("span",{style:{fontSize:11,fontWeight:600,color:S>0?b.text:"#94a3b8",textTransform:"uppercase",letterSpacing:"0.03em"},children:_})]},_)})})]})]}),m.length>0&&d.jsxs("div",{children:[d.jsxs("h3",{style:{fontSize:14,fontWeight:600,color:"#0f172a",marginBottom:12,display:"flex",alignItems:"center",gap:8},children:[d.jsx("span",{style:{color:"#dc2626"},children:"✕"}),"Failed Checks (",m.length,")"]}),Object.entries(h).map(([_,S])=>d.jsxs("div",{style:{marginBottom:16},children:[d.jsx("div",{style:{fontSize:11,fontWeight:600,color:"#64748b",textTransform:"uppercase",letterSpacing:"0.05em",marginBottom:6,paddingLeft:4},children:IC[_]||_.replace(/_/g," ")}),S.map(b=>{const E=`${_}-${b.name}`;return d.jsx(Zf,{check:b,expanded:p.has(E),onToggle:()=>v(E)},E)})]},_))]}),g.length>0&&d.jsxs("div",{children:[d.jsxs("button",{onClick:()=>x(_=>!_),style:{display:"flex",alignItems:"center",gap:8,background:"none",border:"none",cursor:"pointer",padding:"4px 0",fontSize:14,fontWeight:600,color:"#0f172a"},children:[d.jsx("span",{style:{color:"#16a34a"},children:"✓"}),"Passed Checks (",g.length,")",d.jsx("span",{style:{fontSize:11,color:"#94a3b8",transform:f?"rotate(180deg)":"rotate(0deg)",transition:"transform 0.15s ease"},children:"▼"})]}),f&&d.jsx("div",{style:{marginTop:8},children:g.map(_=>{const S=`passed-${_.category}-${_.name}`;return d.jsx(Zf,{check:_,expanded:p.has(S),onToggle:()=>v(S)},S)})})]}),d.jsxs("div",{style:{fontSize:11,color:"#94a3b8",borderTop:"1px solid #f1f5f9",paddingTop:12,lineHeight:1.5},children:["Score = percentage of checks passed. A framework is marked FAILED if any critical-severity check fails, regardless of overall score. Checks are defined in the Cloudwright Validator based on ",k.framework," control requirements."]})]}),!k&&!s&&!a&&d.jsx("div",{style:{padding:40,textAlign:"center",color:"#94a3b8",fontSize:14,background:"#f8fafc",borderRadius:8,border:"1px dashed #e2e8f0"},children:"Select a compliance framework above to validate your architecture."})]})}const $C=[{key:"hipaa",label:"HIPAA"},{key:"soc2",label:"SOC 2"},{key:"pci-dss",label:"PCI-DSS"},{key:"fedramp",label:"FedRAMP"},{key:"gdpr",label:"GDPR"},{key:"iso27001",label:"ISO 27001"},{key:"nist",label:"NIST 800-53"}],qf={critical:{bg:"#fef2f2",text:"#991b1b",border:"#fca5a5"},high:{bg:"#fff7ed",text:"#9a3412",border:"#fdba74"},medium:{bg:"#fffbeb",text:"#92400e",border:"#fcd34d"},low:{bg:"#f0fdf4",text:"#166534",border:"#86efac"}};function DC({spec:e,apiBase:t}){const[n,r]=M.useState(["hipaa","soc2","fedramp"]),[o,i]=M.useState(!1),[s,l]=M.useState(null),[a,u]=M.useState(!1),[p,c]=M.useState(null),f=v=>r(k=>k.includes(v)?k.filter(m=>m!==v):[...k,v]),x=M.useCallback(async()=>{u(!0),c(null);try{const v=await fetch(`${t}/compliance`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({spec:e,frameworks:n,oscal:o})});if(!v.ok)throw new Error(await Mr(v));l(await v.json())}catch(v){c(v instanceof Error?v.message:"Compliance scan failed")}finally{u(!1)}},[e,t,n,o]),y=M.useCallback(()=>{if(!(s!=null&&s.oscal))return;const v=new Blob([JSON.stringify(s.oscal,null,2)],{type:"application/json"}),k=URL.createObjectURL(v),m=document.createElement("a");m.href=k,m.download="compliance.oscal.json",m.click(),URL.revokeObjectURL(k)},[s]);return d.jsxs("div",{style:{padding:24,maxWidth:920},children:[d.jsx("h2",{style:{fontSize:18,marginBottom:6,color:"#0f172a"},children:"Compliance Control Mapping"}),d.jsx("p",{style:{fontSize:13,color:"#64748b",marginBottom:16},children:"Every design-stage finding mapped to the framework control it violates — before any infrastructure exists. Folds in a Checkov deep scan when available."}),d.jsx("div",{style:{display:"flex",flexWrap:"wrap",gap:8,marginBottom:16},children:$C.map(v=>d.jsx("button",{onClick:()=>f(v.key),style:{padding:"6px 14px",borderRadius:999,border:`1px solid ${n.includes(v.key)?"#2563eb":"#cbd5e1"}`,background:n.includes(v.key)?"#2563eb":"#ffffff",color:n.includes(v.key)?"#ffffff":"#475569",fontSize:13,cursor:"pointer"},children:v.label},v.key))}),d.jsxs("label",{style:{display:"flex",alignItems:"center",gap:8,fontSize:13,color:"#334155",marginBottom:16},children:[d.jsx("input",{type:"checkbox",checked:o,onChange:v=>i(v.target.checked)}),"Include OSCAL 1.1.2 component-definition export"]}),d.jsxs("div",{style:{display:"flex",gap:8},children:[d.jsx("button",{onClick:x,disabled:a||n.length===0,style:{padding:"10px 22px",borderRadius:8,border:"none",background:a?"#94a3b8":"#0f172a",color:"#ffffff",fontSize:14,fontWeight:600,cursor:a?"default":"pointer"},children:a?"Scanning…":"Run compliance scan"}),(s==null?void 0:s.oscal)&&d.jsx("button",{onClick:y,style:{padding:"10px 22px",borderRadius:8,border:"1px solid #2563eb",background:"#ffffff",color:"#2563eb",fontSize:14,fontWeight:600,cursor:"pointer"},children:"Download OSCAL JSON"})]}),p&&d.jsx("div",{style:{marginTop:16,padding:12,background:"#fef2f2",border:"1px solid #fca5a5",borderRadius:8,color:"#991b1b",fontSize:13},children:p}),s&&d.jsxs("div",{style:{marginTop:24},children:[d.jsxs("div",{style:{fontSize:12,color:"#64748b",marginBottom:8},children:["Scanner: ",d.jsx("strong",{children:s.scanner}),s.checkov_used?" (Checkov deep scan included)":""]}),d.jsxs("table",{style:{width:"100%",borderCollapse:"collapse",marginBottom:24},children:[d.jsx("thead",{children:d.jsxs("tr",{style:{background:"#f8fafc",textAlign:"left"},children:[d.jsx("th",{style:Yr,children:"Framework"}),d.jsx("th",{style:Yr,children:"Controls satisfied"}),d.jsx("th",{style:Yr,children:"Violated"}),d.jsx("th",{style:Yr,children:"Findings"}),d.jsx("th",{style:Yr,children:"Status"})]})}),d.jsx("tbody",{children:s.frameworks.map(v=>d.jsxs("tr",{style:{borderTop:"1px solid #e2e8f0"},children:[d.jsx("td",{style:Xr,children:d.jsx("strong",{children:v.framework})}),d.jsxs("td",{style:Xr,children:[v.controls_satisfied,"/",v.controls_total]}),d.jsx("td",{style:{...Xr,color:"#991b1b"},children:v.controls_violated.length?v.controls_violated.join(", "):"—"}),d.jsx("td",{style:Xr,children:v.findings}),d.jsx("td",{style:Xr,children:d.jsx("span",{style:{padding:"2px 10px",borderRadius:999,fontSize:12,fontWeight:600,background:v.status==="pass"?"#dcfce7":"#fee2e2",color:v.status==="pass"?"#166534":"#991b1b"},children:v.status.toUpperCase()})})]},v.framework))})]}),d.jsxs("h3",{style:{fontSize:15,color:"#0f172a",marginBottom:12},children:["Findings (",s.findings.length,")"]}),s.findings.map((v,k)=>{const m=qf[v.severity]||qf.low;return d.jsxs("div",{style:{border:`1px solid ${m.border}`,background:m.bg,borderRadius:8,padding:14,marginBottom:10},children:[d.jsxs("div",{style:{display:"flex",gap:8,alignItems:"center"},children:[d.jsxs("span",{style:{fontSize:11,fontWeight:700,color:m.text,textTransform:"uppercase"},children:["[",v.severity,"]"]}),d.jsx("span",{style:{fontSize:14,color:"#0f172a"},children:v.message}),d.jsxs("span",{style:{fontSize:11,color:"#64748b"},children:["(",v.source,")"]})]}),v.controls.length>0&&d.jsx("div",{style:{display:"flex",flexWrap:"wrap",gap:6,marginTop:8},children:v.controls.map((g,h)=>d.jsxs("span",{title:g.title,style:{fontSize:11,padding:"2px 8px",borderRadius:4,background:"#e0e7ff",color:"#3730a3",fontFamily:"monospace"},children:[g.framework," ",g.control_id]},h))}),d.jsx("div",{style:{fontSize:12,color:"#475569",marginTop:8},children:v.remediation})]},k)})]})]})}const Yr={padding:"10px 12px",fontSize:12,color:"#475569",fontWeight:600},Xr={padding:"10px 12px",fontSize:13,color:"#0f172a"},OC=[{key:"terraform",label:"Terraform"},{key:"pulumi-python",label:"Pulumi (Python)"},{key:"pulumi-ts",label:"Pulumi (TS)"}];function BC({spec:e,apiBase:t}){const[n,r]=M.useState("terraform"),[o,i]=M.useState(null),[s,l]=M.useState(!1),[a,u]=M.useState(null),p=M.useCallback(async()=>{l(!0),u(null),i(null);try{const c=await fetch(`${t}/plan`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({spec:e,target:n,run_plan:!0})});if(!c.ok)throw new Error(await Mr(c));i(await c.json())}catch(c){u(c instanceof Error?c.message:"Plan failed")}finally{l(!1)}},[e,t,n]);return d.jsxs("div",{style:{padding:24,maxWidth:920},children:[d.jsx("h2",{style:{fontSize:18,marginBottom:6,color:"#0f172a"},children:"Plan / Preview — prove it deploys"}),d.jsxs("p",{style:{fontSize:13,color:"#64748b",marginBottom:16},children:["Runs ",d.jsx("code",{children:"terraform validate/plan"})," or ",d.jsx("code",{children:"pulumi preview"})," against the exported artifact. Read-only — nothing is applied. Validation needs no credentials and is the offline proof of deployability."]}),d.jsx("div",{style:{display:"flex",gap:8,marginBottom:16},children:OC.map(c=>d.jsx("button",{onClick:()=>r(c.key),style:{padding:"6px 14px",borderRadius:8,border:`1px solid ${n===c.key?"#2563eb":"#cbd5e1"}`,background:n===c.key?"#2563eb":"#ffffff",color:n===c.key?"#ffffff":"#475569",fontSize:13,cursor:"pointer"},children:c.label},c.key))}),d.jsx("button",{onClick:p,disabled:s,style:{padding:"10px 22px",borderRadius:8,border:"none",background:s?"#94a3b8":"#0f172a",color:"#ffffff",fontSize:14,fontWeight:600,cursor:s?"default":"pointer"},children:s?"Running plan…":"Run plan"}),a&&d.jsx("div",{style:{marginTop:16,padding:12,background:"#fef2f2",border:"1px solid #fca5a5",borderRadius:8,color:"#991b1b",fontSize:13},children:a}),o&&d.jsxs("div",{style:{marginTop:24},children:[d.jsxs("div",{style:{display:"inline-block",padding:"8px 18px",borderRadius:8,fontSize:15,fontWeight:700,background:o.ok?"#dcfce7":"#fee2e2",color:o.ok?"#166534":"#991b1b",marginBottom:16},children:[o.ok?"DEPLOYABLE":"NOT DEPLOYABLE",o.ok&&!o.plan_ran?" (validate only — no credentials)":""]}),o.summary&&d.jsxs("div",{style:{fontSize:14,marginBottom:16},children:["Resource diff:"," ",d.jsxs("span",{style:{color:"#166534"},children:["+",o.summary.add]})," ",d.jsxs("span",{style:{color:"#92400e"},children:["~",o.summary.change]})," ",d.jsxs("span",{style:{color:"#991b1b"},children:["-",o.summary.destroy]})]}),d.jsx("ul",{style:{fontSize:13,color:"#334155",marginBottom:16,paddingLeft:18},children:o.messages.map((c,f)=>d.jsx("li",{style:{marginBottom:4},children:c},f))}),o.output_tail&&d.jsx("pre",{style:{background:"#0f172a",color:"#e2e8f0",padding:14,borderRadius:8,fontSize:12,overflowX:"auto",maxHeight:280},children:o.output_tail})]})]})}const Jf={critical:{bg:"#fef2f2",text:"#991b1b",border:"#fca5a5"},high:{bg:"#fff7ed",text:"#9a3412",border:"#fdba74"},medium:{bg:"#fffbeb",text:"#92400e",border:"#fcd34d"},low:{bg:"#f0fdf4",text:"#166534",border:"#86efac"}};function FC({spec:e,apiBase:t}){const[n,r]=M.useState(!1),[o,i]=M.useState(null),[s,l]=M.useState(!1),[a,u]=M.useState(null),p=M.useCallback(async()=>{l(!0),u(null);try{const c=await fetch(`${t}/review`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({spec:e,well_architected:n})});if(!c.ok)throw new Error(await Mr(c));i(await c.json())}catch(c){u(c instanceof Error?c.message:"Review failed")}finally{l(!1)}},[e,t,n]);return d.jsxs("div",{style:{padding:24,maxWidth:920},children:[d.jsx("h2",{style:{fontSize:18,marginBottom:6,color:"#0f172a"},children:"Architecture Review"}),d.jsx("p",{style:{fontSize:13,color:"#64748b",marginBottom:16},children:"Deterministic critique — scorer, linter, and validator merged into one severity-ranked report. Runs offline, no LLM call."}),d.jsxs("label",{style:{display:"flex",alignItems:"center",gap:8,fontSize:13,color:"#334155",marginBottom:16},children:[d.jsx("input",{type:"checkbox",checked:n,onChange:c=>r(c.target.checked)}),"Include Well-Architected checks"]}),d.jsx("button",{onClick:p,disabled:s,style:{padding:"10px 22px",borderRadius:8,border:"none",background:s?"#94a3b8":"#0f172a",color:"#ffffff",fontSize:14,fontWeight:600,cursor:s?"default":"pointer"},children:s?"Reviewing…":"Run review"}),a&&d.jsx("div",{style:{marginTop:16,padding:12,background:"#fef2f2",border:"1px solid #fca5a5",borderRadius:8,color:"#991b1b",fontSize:13},children:a}),o&&d.jsxs("div",{style:{marginTop:24},children:[d.jsxs("div",{style:{display:"inline-flex",alignItems:"center",gap:12,padding:"8px 18px",borderRadius:8,fontSize:15,fontWeight:700,background:o.blocking_count===0?"#dcfce7":"#fee2e2",color:o.blocking_count===0?"#166534":"#991b1b",marginBottom:16},children:[o.score.toFixed(0),"/100 (grade ",o.grade,")",d.jsx("span",{style:{fontWeight:500,fontSize:12,marginLeft:8},children:o.blocking_count===0?"no blocking findings":`${o.blocking_count} blocking finding(s)`})]}),d.jsxs("h3",{style:{fontSize:15,color:"#0f172a",marginBottom:12},children:["Findings (",o.findings.length,")"]}),o.findings.length===0?d.jsx("div",{style:{fontSize:14,color:"#166534"},children:"No findings. This architecture passes every critic."}):o.findings.map((c,f)=>{const x=Jf[c.severity]||Jf.low;return d.jsxs("div",{style:{border:`1px solid ${x.border}`,background:x.bg,borderRadius:8,padding:14,marginBottom:10},children:[d.jsxs("div",{style:{display:"flex",gap:8,alignItems:"center"},children:[d.jsxs("span",{style:{fontSize:11,fontWeight:700,color:x.text,textTransform:"uppercase"},children:["[",c.severity,"]"]}),d.jsx("span",{style:{fontSize:14,color:"#0f172a"},children:c.message}),d.jsxs("span",{style:{fontSize:11,color:"#64748b"},children:["(",c.source,")"]})]}),c.recommendation&&d.jsx("div",{style:{fontSize:12,color:"#475569",marginTop:8},children:c.recommendation})]},f)})]})]})}const Ql=[{key:"terraform",label:"Terraform",ext:"tf",lang:"hcl",desc:"HashiCorp Configuration Language"},{key:"cloudformation",label:"CloudFormation",ext:"yaml",lang:"yaml",desc:"AWS CloudFormation template"},{key:"mermaid",label:"Mermaid",ext:"mmd",lang:"mermaid",desc:"Mermaid diagram markup"},{key:"d2",label:"D2",ext:"d2",lang:"d2",desc:"D2 diagram language"},{key:"sbom",label:"SBOM",ext:"json",lang:"json",desc:"CycloneDX Software BOM"},{key:"aibom",label:"AIBOM",ext:"json",lang:"json",desc:"OWASP AI Bill of Materials"},{key:"html",label:"HTML Report",ext:"html",lang:"html",desc:"Self-contained shareable report"}];function ep({format:e}){const t={terraform:"HCL",cloudformation:"CFN",mermaid:"MMD",d2:"D2",sbom:"BOM",aibom:"AI"},n={terraform:"#7c3aed",cloudformation:"#ea580c",mermaid:"#0891b2",d2:"#4f46e5",sbom:"#059669",aibom:"#2563eb"};return d.jsx("span",{style:{display:"inline-flex",alignItems:"center",justifyContent:"center",width:32,height:20,borderRadius:4,fontSize:10,fontWeight:700,background:`${n[e]||"#64748b"}14`,color:n[e]||"#64748b",letterSpacing:"0.02em",flexShrink:0},children:t[e]||e.slice(0,3).toUpperCase()})}function HC({spec:e,apiBase:t}){const[n,r]=M.useState(null),[o,i]=M.useState(""),[s,l]=M.useState(!1),[a,u]=M.useState(null),[p,c]=M.useState(!1),f=M.useRef(null),x=M.useCallback(async g=>{r(g),l(!0),u(null),c(!1);try{const h=await fetch(`${t}/export`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({spec:e,format:g})});if(!h.ok)throw new Error(await Mr(h));const w=await h.json();i(w.content||JSON.stringify(w,null,2))}catch(h){u(h instanceof Error?h.message:"Export failed"),i("")}finally{l(!1)}},[e,t]),y=M.useCallback(async()=>{var g,h;try{await navigator.clipboard.writeText(o),c(!0),setTimeout(()=>c(!1),2e3)}catch{const w=f.current;if(w){const _=document.createRange();_.selectNodeContents(w),(g=window.getSelection())==null||g.removeAllRanges(),(h=window.getSelection())==null||h.addRange(_)}}},[o]),v=M.useCallback(()=>{if(!o||!n)return;const g=Ql.find(S=>S.key===n),h=new Blob([o],{type:"text/plain"}),w=URL.createObjectURL(h),_=document.createElement("a");_.href=w,_.download=`architecture.${(g==null?void 0:g.ext)||"txt"}`,_.click(),URL.revokeObjectURL(w)},[o,n]),k=o?o.split(` +`).length:0,m=Ql.find(g=>g.key===n);return d.jsxs("div",{style:{padding:32,maxWidth:960},children:[d.jsx("h2",{style:{fontSize:18,marginBottom:16,color:"#0f172a",fontWeight:700},children:"Export Architecture"}),d.jsx("div",{style:{display:"grid",gridTemplateColumns:"repeat(3, 1fr)",gap:10,marginBottom:24},children:Ql.map(g=>{const h=n===g.key;return d.jsxs("button",{onClick:()=>x(g.key),disabled:s,style:{display:"flex",alignItems:"center",gap:10,padding:"10px 14px",borderRadius:8,border:h?"1.5px solid #2563eb":"1px solid #e2e8f0",background:h?"#eff6ff":"#ffffff",cursor:s?"wait":"pointer",textAlign:"left",transition:"all 0.15s ease",opacity:s&&!h?.6:1},children:[d.jsx(ep,{format:g.key}),d.jsxs("div",{children:[d.jsx("div",{style:{fontSize:13,fontWeight:h?600:500,color:h?"#1d4ed8":"#0f172a"},children:g.label}),d.jsx("div",{style:{fontSize:11,color:"#94a3b8"},children:g.desc})]})]},g.key)})}),s&&d.jsxs("div",{style:{display:"flex",alignItems:"center",gap:10,padding:24,color:"#64748b",fontSize:14},children:[d.jsx("span",{style:{display:"inline-block",width:16,height:16,border:"2px solid #e2e8f0",borderTopColor:"#2563eb",borderRadius:"50%",animation:"spin 0.6s linear infinite"}}),"Generating ",(m==null?void 0:m.label)||n,"...",d.jsx("style",{children:"@keyframes spin { to { transform: rotate(360deg); } }"})]}),a&&d.jsx("div",{style:{padding:"12px 16px",background:"#fef2f2",border:"1px solid #fca5a5",borderRadius:8,color:"#991b1b",fontSize:13},children:a}),o&&!s&&d.jsxs("div",{style:{border:"1px solid #e2e8f0",borderRadius:10,overflow:"hidden"},children:[d.jsxs("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",padding:"8px 14px",background:"#f8fafc",borderBottom:"1px solid #e2e8f0"},children:[d.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8},children:[d.jsx(ep,{format:n||""}),d.jsxs("span",{style:{fontSize:12,color:"#64748b"},children:["architecture.",(m==null?void 0:m.ext)||"txt"]}),d.jsxs("span",{style:{fontSize:11,color:"#cbd5e1"},children:[k," lines"]})]}),d.jsxs("div",{style:{display:"flex",gap:6},children:[d.jsx("button",{onClick:y,style:{padding:"4px 12px",borderRadius:4,border:"1px solid #e2e8f0",background:p?"#dcfce7":"#ffffff",color:p?"#166534":"#475569",cursor:"pointer",fontSize:12,fontWeight:500,transition:"all 0.15s ease"},children:p?"Copied":"Copy"}),d.jsx("button",{onClick:v,style:{padding:"4px 12px",borderRadius:4,border:"1px solid #e2e8f0",background:"#ffffff",color:"#475569",cursor:"pointer",fontSize:12,fontWeight:500},children:"Download"})]})]}),d.jsx("div",{style:{maxHeight:560,overflow:"auto"},children:d.jsx("pre",{ref:f,style:{margin:0,padding:16,fontSize:12,lineHeight:1.7,color:"#334155",background:"#ffffff",fontFamily:"'SF Mono', 'Cascadia Code', 'Fira Code', Menlo, monospace",counterReset:"line",whiteSpace:"pre-wrap",wordBreak:"break-word"},children:o})})]}),!o&&!s&&!a&&d.jsx("div",{style:{padding:40,textAlign:"center",color:"#94a3b8",fontSize:14,background:"#f8fafc",borderRadius:8,border:"1px dashed #e2e8f0"},children:"Select an export format above to generate infrastructure code."})]})}const VC={0:"Edge / CDN",1:"Load Balancing",2:"Compute",3:"Data",4:"Supporting"};function Gl(e){if(e===null)return"null";if(typeof e=="number"||typeof e=="boolean")return String(e);const t=String(e);return/^[A-Za-z0-9_./:@-]+$/.test(t)?t:JSON.stringify(t)}function lu(e,t=0){const n=" ".repeat(t);if(Array.isArray(e))return e.length===0?"[]":e.map(r=>{if(r&&typeof r=="object"){const o=lu(r,t+2);return`${n}- ${o.trimStart()}`}return`${n}- ${Gl(r)}`}).join(` +`);if(e&&typeof e=="object"){const r=Object.entries(e).filter(([,o])=>o!==void 0);return r.length===0?"{}":r.map(([o,i])=>{if(i&&typeof i=="object"){const s=lu(i,t+2);return`${n}${o}: +${s}`}return`${n}${o}: ${Gl(i)}`}).join(` +`)}return Gl(e)}function Mi({label:e,value:t,sub:n}){return d.jsxs("div",{style:{padding:"14px 16px",background:"#ffffff",border:"1px solid #e2e8f0",borderRadius:8,flex:1,minWidth:120},children:[d.jsx("div",{style:{fontSize:22,fontWeight:700,color:"#0f172a",lineHeight:1.2},children:t}),d.jsx("div",{style:{fontSize:12,color:"#64748b",marginTop:2},children:e}),n&&d.jsx("div",{style:{fontSize:11,color:"#94a3b8",marginTop:2},children:n})]})}function WC({spec:e,yaml:t}){var x;const[n,r]=M.useState("overview"),[o,i]=M.useState(!1),s=M.useRef(null),l=M.useMemo(()=>lu(e)||t||"",[e,t]),a=M.useMemo(()=>{const y=new Set(e.components.map(v=>v.provider));return Array.from(y)},[e.components]),u=M.useMemo(()=>{const y=new Set(e.components.map(v=>v.service));return Array.from(y)},[e.components]),p=M.useMemo(()=>{const y={};for(const v of e.components){const k=v.tier??2;y[k]||(y[k]=[]),y[k].push(v)}return y},[e.components]),c=M.useCallback(async()=>{var y,v;try{await navigator.clipboard.writeText(l),i(!0),setTimeout(()=>i(!1),2e3)}catch{const k=s.current;if(k){const m=document.createRange();m.selectNodeContents(k),(y=window.getSelection())==null||y.removeAllRanges(),(v=window.getSelection())==null||v.addRange(m)}}},[l]),f=M.useCallback(()=>{var m;const y=new Blob([l],{type:"text/yaml"}),v=URL.createObjectURL(y),k=document.createElement("a");k.href=v,k.download=`${((m=e.name)==null?void 0:m.replace(/\s+/g,"-").toLowerCase())||"architecture"}.yaml`,k.click(),URL.revokeObjectURL(v)},[l,e.name]);return d.jsxs("div",{style:{padding:32,maxWidth:960},children:[d.jsxs("div",{style:{display:"flex",alignItems:"baseline",gap:12,marginBottom:20},children:[d.jsx("h2",{style:{fontSize:18,color:"#0f172a",fontWeight:700,margin:0},children:e.name||"Architecture Spec"}),e.provider&&d.jsx("span",{style:{fontSize:12,fontWeight:600,color:"#475569",background:"#f1f5f9",padding:"2px 8px",borderRadius:4},children:e.provider.toUpperCase()}),e.region&&d.jsx("span",{style:{fontSize:12,color:"#94a3b8"},children:e.region})]}),d.jsx("div",{style:{display:"flex",gap:0,marginBottom:20,borderBottom:"1px solid #e2e8f0"},children:["overview","yaml"].map(y=>d.jsx("button",{onClick:()=>r(y),style:{padding:"8px 18px",background:"none",border:"none",borderBottom:n===y?"2px solid #2563eb":"2px solid transparent",color:n===y?"#1d4ed8":"#64748b",fontWeight:n===y?600:500,fontSize:13,cursor:"pointer",transition:"all 0.15s ease"},children:y==="overview"?"Overview":"YAML Source"},y))}),n==="overview"&&d.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:20},children:[d.jsxs("div",{style:{display:"flex",gap:12},children:[d.jsx(Mi,{label:"Components",value:e.components.length}),d.jsx(Mi,{label:"Connections",value:e.connections.length}),d.jsx(Mi,{label:"Services",value:u.length,sub:a.join(", ")}),e.cost_estimate&&d.jsx(Mi,{label:"Monthly Cost",value:`$${e.cost_estimate.monthly_total.toLocaleString()}`,sub:e.cost_estimate.currency})]}),d.jsx("div",{style:{border:"1px solid #e2e8f0",borderRadius:10,overflow:"hidden"},children:d.jsxs("table",{style:{width:"100%",borderCollapse:"collapse",fontSize:13},children:[d.jsx("thead",{children:d.jsxs("tr",{style:{background:"#f8fafc"},children:[d.jsx("th",{style:xt,children:"Component"}),d.jsx("th",{style:xt,children:"Service"}),d.jsx("th",{style:xt,children:"Provider"}),d.jsx("th",{style:xt,children:"Tier"}),d.jsx("th",{style:xt,children:"Description"})]})}),d.jsx("tbody",{children:Object.keys(p).map(Number).sort().flatMap(y=>p[y].map(v=>d.jsxs("tr",{style:{borderBottom:"1px solid #f1f5f9"},children:[d.jsxs("td",{style:vt,children:[d.jsx("span",{style:{fontWeight:600,color:"#0f172a"},children:v.label}),d.jsx("div",{style:{fontSize:11,color:"#94a3b8"},children:v.id})]}),d.jsx("td",{style:vt,children:d.jsx("code",{style:{fontSize:12,background:"#f1f5f9",padding:"1px 6px",borderRadius:3,color:"#334155"},children:v.service})}),d.jsx("td",{style:vt,children:d.jsx("span",{style:{fontSize:12,color:"#475569"},children:v.provider})}),d.jsx("td",{style:vt,children:d.jsx("span",{style:{fontSize:11,fontWeight:600,color:"#64748b",background:"#f1f5f9",padding:"2px 8px",borderRadius:4},children:VC[y]||`Tier ${y}`})}),d.jsx("td",{style:{...vt,color:"#64748b",maxWidth:240},children:v.description})]},v.id)))})]})}),e.connections.length>0&&d.jsxs("div",{style:{border:"1px solid #e2e8f0",borderRadius:10,overflow:"hidden"},children:[d.jsxs("div",{style:{padding:"10px 16px",background:"#f8fafc",borderBottom:"1px solid #e2e8f0",fontSize:13,fontWeight:600,color:"#0f172a"},children:["Connections (",e.connections.length,")"]}),d.jsxs("table",{style:{width:"100%",borderCollapse:"collapse",fontSize:13},children:[d.jsx("thead",{children:d.jsxs("tr",{style:{background:"#fafafa"},children:[d.jsx("th",{style:xt,children:"Source"}),d.jsx("th",{style:xt}),d.jsx("th",{style:xt,children:"Target"}),d.jsx("th",{style:xt,children:"Protocol"}),d.jsx("th",{style:xt,children:"Label"})]})}),d.jsx("tbody",{children:e.connections.map((y,v)=>{const k=e.components.find(g=>g.id===y.source),m=e.components.find(g=>g.id===y.target);return d.jsxs("tr",{style:{borderBottom:"1px solid #f1f5f9"},children:[d.jsx("td",{style:vt,children:d.jsx("span",{style:{fontWeight:500,color:"#0f172a"},children:(k==null?void 0:k.label)||y.source})}),d.jsx("td",{style:{...vt,textAlign:"center",color:"#94a3b8",fontSize:14},children:"→"}),d.jsx("td",{style:vt,children:d.jsx("span",{style:{fontWeight:500,color:"#0f172a"},children:(m==null?void 0:m.label)||y.target})}),d.jsx("td",{style:vt,children:y.protocol&&d.jsxs("code",{style:{fontSize:11,background:"#f1f5f9",padding:"1px 6px",borderRadius:3,color:"#334155"},children:[y.protocol,y.port?`:${y.port}`:""]})}),d.jsx("td",{style:{...vt,color:"#64748b"},children:y.label})]},v)})})]})]}),e.boundaries&&e.boundaries.length>0&&d.jsxs("div",{style:{border:"1px solid #e2e8f0",borderRadius:10,overflow:"hidden"},children:[d.jsxs("div",{style:{padding:"10px 16px",background:"#f8fafc",borderBottom:"1px solid #e2e8f0",fontSize:13,fontWeight:600,color:"#0f172a"},children:["Boundaries (",e.boundaries.length,")"]}),d.jsx("div",{style:{padding:16,display:"flex",flexWrap:"wrap",gap:10},children:e.boundaries.map(y=>d.jsxs("div",{style:{padding:"8px 14px",border:"1px dashed #cbd5e1",borderRadius:8,background:"#fafafa",fontSize:13},children:[d.jsx("div",{style:{fontWeight:600,color:"#0f172a"},children:y.label||y.id}),d.jsxs("div",{style:{fontSize:11,color:"#94a3b8"},children:[y.kind," · ",y.component_ids.length," components"]})]},y.id))})]})]}),n==="yaml"&&d.jsxs("div",{style:{border:"1px solid #e2e8f0",borderRadius:10,overflow:"hidden"},children:[d.jsxs("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",padding:"8px 14px",background:"#f8fafc",borderBottom:"1px solid #e2e8f0"},children:[d.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8},children:[d.jsx("span",{style:{fontSize:10,fontWeight:700,color:"#7c3aed",background:"#7c3aed14",padding:"2px 8px",borderRadius:4},children:"YAML"}),d.jsxs("span",{style:{fontSize:12,color:"#64748b"},children:[((x=e.name)==null?void 0:x.replace(/\s+/g,"-").toLowerCase())||"architecture",".yaml"]}),d.jsxs("span",{style:{fontSize:11,color:"#cbd5e1"},children:[l.split(` +`).length," lines"]})]}),d.jsxs("div",{style:{display:"flex",gap:6},children:[d.jsx("button",{onClick:c,style:{padding:"4px 12px",borderRadius:4,border:"1px solid #e2e8f0",background:o?"#dcfce7":"#ffffff",color:o?"#166534":"#475569",cursor:"pointer",fontSize:12,fontWeight:500,transition:"all 0.15s ease"},children:o?"Copied":"Copy"}),d.jsx("button",{onClick:f,style:{padding:"4px 12px",borderRadius:4,border:"1px solid #e2e8f0",background:"#ffffff",color:"#475569",cursor:"pointer",fontSize:12,fontWeight:500},children:"Download"})]})]}),d.jsx("div",{style:{maxHeight:600,overflow:"auto"},children:d.jsx("pre",{ref:s,style:{margin:0,padding:16,fontSize:13,lineHeight:1.7,color:"#334155",background:"#ffffff",fontFamily:"'SF Mono', 'Cascadia Code', 'Fira Code', Menlo, monospace",whiteSpace:"pre-wrap",wordBreak:"break-word"},children:l||"No YAML available"})})]})]})}const xt={padding:"10px 14px",textAlign:"left",fontSize:11,fontWeight:600,color:"#64748b",textTransform:"uppercase",letterSpacing:"0.05em"},vt={padding:"10px 14px",color:"#0f172a"},Ve="/api",UC=["Add caching layer","Reduce cost","Increase redundancy","Add monitoring","Add security"];function tp(e){var s;if((s=e.metadata)!=null&&s.suggestions&&e.metadata.suggestions.length>0)return e.metadata.suggestions.slice(0,3);const t=e.components.map(l=>l.label.toLowerCase()),n=e.components.map(l=>l.service.toLowerCase()),r=t.some(l=>l.includes("cache")||l.includes("redis")||l.includes("elasticache"))||n.some(l=>l.includes("cache")||l.includes("redis")),o=t.some(l=>l.includes("monitor")||l.includes("cloudwatch")||l.includes("grafana"))||n.some(l=>l.includes("cloudwatch")||l.includes("monitor")),i=t.some(l=>l.includes("waf")||l.includes("firewall")||l.includes("security"))||n.some(l=>l.includes("waf")||l.includes("shield"));return UC.filter(l=>!(l==="Add caching layer"&&r||l==="Add monitoring"&&o||l==="Add security"&&i)).slice(0,3)}function YC(e){return e.split(/(\*\*.*?\*\*)/g).map((t,n)=>t.startsWith("**")&&t.endsWith("**")?d.jsx("strong",{children:t.slice(2,-2)},n):d.jsx("span",{children:t},n))}async function Kl(e,t){var i;let n=e;const[r,o]=await Promise.all([fetch(`${Ve}/cost`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({spec:n})}).then(s=>s.ok?s.json():null).catch(()=>null),fetch(`${Ve}/validate`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({spec:n,compliance:[],well_architected:!0})}).then(s=>s.ok?s.json():null).catch(()=>null)]);if(r!=null&&r.estimate&&(n={...n,cost_estimate:r.estimate}),((i=o==null?void 0:o.results)==null?void 0:i.length)>0){const s=o.results[0].checks||[],l=s.filter(a=>a.passed).length;t({passed:l,total:s.length})}return n}async function np(e,t,n){var a;const r=e?`${Ve}/modify/stream`:`${Ve}/design/stream`,o=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)});if(!o.ok){n.onError(await Mr(o));return}const i=(a=o.body)==null?void 0:a.getReader();if(!i)return;const s=new TextDecoder;let l="";for(;;){const{done:u,value:p}=await i.read();if(u)break;l+=s.decode(p,{stream:!0});const c=l.split(` +`);l=c.pop()||"";for(const f of c)if(f.startsWith("data: "))try{const x=JSON.parse(f.slice(6));switch(x.stage){case"generating":case"costing":case"validating":n.onStage(x.stage,x.message);break;case"generated":n.onSpec(x.spec,x.yaml),x.usage&&n.onUsage&&n.onUsage(x.usage);break;case"costed":n.onCost(x.cost_estimate);break;case"validated":n.onValidation(x.passed,x.total);break;case"done":n.onDone(x.spec,x.yaml),x.usage&&n.onUsage&&n.onUsage(x.usage);break;case"error":n.onError(x.message);break}}catch{}}}function XC(){var _;const[e,t]=M.useState([]),[n,r]=M.useState(""),[o,i]=M.useState("idle"),[s,l]=M.useState(null),[a,u]=M.useState("diagram"),[p,c]=M.useState(""),[f,x]=M.useState(null),[y,v]=M.useState(null),k=M.useRef(null),m=M.useRef(null);M.useEffect(()=>{var S;(S=m.current)==null||S.scrollIntoView({behavior:"smooth"})},[e]);const g=async()=>{var P;if(!n.trim()||o!=="idle")return;const S={role:"user",content:n};t(I=>[...I,S]),r("");const b=s!==null;i(b?"modifying":"generating");let E=null,A="",D=!1;try{const I=b?{spec:s,instruction:n}:{description:n};try{await np(b,I,{onStage:z=>{z==="generating"?i("generating"):(z==="costing"||z==="validating")&&i("costing")},onSpec:z=>{l(z),E=z,i("costing")},onCost:z=>{z&&E&&(E={...E,cost_estimate:z},l(E))},onValidation:(z,R)=>{z!==null&&x({passed:z,total:R})},onDone:(z,R)=>{E=z,A=R,l(z),i("done")},onUsage:z=>v(z),onError:z=>{throw new Error(z)}}),D=E!==null}catch{i(b?"modifying":"generating")}if(!D){const z=b?await fetch(`${Ve}/modify`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({spec:s,instruction:n})}):await fetch(`${Ve}/design`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({description:n})}),R=await z.json();if(!z.ok)throw new Error(su(R));E=R.spec,A=R.yaml,R.usage&&v(R.usage),i("costing"),E=await Kl(E,x),l(E),i("done")}const T=E,L={role:"assistant",content:`${b?"Modified":"Designed"} **${T.name}** with ${T.components.length} components on ${T.provider.toUpperCase()}.${T.cost_estimate?` Estimated cost: $${T.cost_estimate.monthly_total.toFixed(2)}/mo.`:""}`,spec:T,yaml:A,suggestions:tp(T)};t(z=>[...z,L]),u("diagram")}catch(I){const T=I instanceof Error?I.message:"Unknown error";t(C=>[...C,{role:"assistant",content:`Error: ${T}`}])}finally{i("idle"),(P=k.current)==null||P.focus()}},h=async S=>{if(s)try{const b=await fetch(`${Ve}/download`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({spec:s,format:S})});if(!b.ok)return;const E=await b.blob(),D=(b.headers.get("Content-Disposition")||"").match(/filename=([^\s;]+)/),P=D?D[1]:`architecture.${S==="terraform"?"tf":"yaml"}`,I=URL.createObjectURL(E),T=document.createElement("a");T.href=I,T.download=P,T.click(),URL.revokeObjectURL(I)}catch{}},w=async S=>{l(S),x(null);try{const b=await Kl(S,x);l(b)}catch{}};return d.jsxs("div",{style:{display:"flex",height:"100vh",background:"#ffffff"},children:[d.jsxs("div",{style:{width:420,borderRight:"1px solid #e2e8f0",display:"flex",flexDirection:"column",background:"#f8fafc"},children:[d.jsxs("div",{style:{padding:"16px 20px",borderBottom:"1px solid #e2e8f0",display:"flex",alignItems:"center",justifyContent:"space-between"},children:[d.jsxs("div",{children:[d.jsx("h1",{style:{fontSize:20,fontWeight:700,color:"#0f172a"},children:"Cloudwright"}),d.jsx("p",{style:{fontSize:12,color:"#64748b",marginTop:4},children:"Architecture Intelligence"})]}),s&&d.jsx("button",{onClick:()=>{if(window.confirm("Discard current session and start fresh?")){try{localStorage.setItem("cloudwright_last_session",JSON.stringify(e))}catch{}l(null),t([]),x(null)}},style:{padding:"5px 12px",borderRadius:6,border:"1px solid #e2e8f0",background:"#ffffff",color:"#64748b",cursor:"pointer",fontSize:12,fontWeight:500},children:"New"})]}),d.jsxs("div",{style:{flex:1,overflowY:"auto",padding:16},children:[e.length===0&&d.jsxs("div",{style:{color:"#64748b",padding:20,textAlign:"center"},children:[d.jsx("p",{style:{fontSize:14},children:"Describe your cloud architecture"}),d.jsx("p",{style:{fontSize:12,marginTop:8,color:"#94a3b8"},children:'"3-tier web app on AWS with CloudFront, ALB, EC2, and RDS"'})]}),e.map((S,b)=>d.jsxs("div",{style:{marginBottom:12},children:[d.jsx("div",{style:{padding:"10px 14px",borderRadius:8,background:S.role==="user"?"#2563eb":"#f1f5f9",color:S.role==="user"?"#ffffff":"#1e293b",fontSize:14,lineHeight:1.5},children:YC(S.content)}),S.role==="assistant"&&S.spec&&S.suggestions&&S.suggestions.length>0&&d.jsx("div",{style:{display:"flex",gap:6,marginTop:6,flexWrap:"wrap"},children:S.suggestions.map(E=>d.jsx("button",{onClick:()=>{var A;r(E),(A=k.current)==null||A.focus()},disabled:o!=="idle",style:{padding:"4px 10px",borderRadius:12,border:"1px solid #cbd5e1",background:"#ffffff",color:"#2563eb",cursor:o!=="idle"?"not-allowed":"pointer",fontSize:12,fontWeight:500},children:E},E))})]},b)),o!=="idle"&&d.jsxs("div",{style:{padding:"10px 14px",color:"#64748b",fontSize:14},children:[o==="generating"&&"Generating architecture...",o==="modifying"&&"Modifying architecture...",o==="costing"&&"Estimating cost & validating...",o==="done"&&"Finalizing..."]}),d.jsx("div",{ref:m})]}),d.jsx("div",{style:{padding:16,borderTop:"1px solid #e2e8f0"},children:d.jsxs("div",{style:{display:"flex",gap:8},children:[d.jsx("input",{ref:k,value:n,onChange:S=>r(S.target.value),onKeyDown:S=>S.key==="Enter"&&g(),placeholder:"Describe your architecture...",style:{flex:1,padding:"10px 14px",borderRadius:8,border:"1px solid #e2e8f0",background:"#ffffff",color:"#0f172a",fontSize:14,outline:"none"}}),d.jsx("button",{onClick:g,disabled:o!=="idle"||!n.trim(),style:{padding:"10px 20px",borderRadius:8,border:"none",background:o!=="idle"?"#e2e8f0":"#2563eb",color:o!=="idle"?"#94a3b8":"#fff",cursor:o!=="idle"?"not-allowed":"pointer",fontSize:14,fontWeight:600},children:"Send"})]})})]}),d.jsxs("div",{style:{flex:1,display:"flex",flexDirection:"column",background:"#ffffff"},children:[d.jsx("div",{style:{display:"flex",borderBottom:"1px solid #e2e8f0",background:"#ffffff"},children:["diagram","cost","validate","compliance","plan","review","export","spec","modify"].map(S=>d.jsx("button",{onClick:()=>u(S),style:{padding:"12px 24px",border:"none",borderBottom:a===S?"2px solid #2563eb":"2px solid transparent",background:"transparent",color:a===S?"#2563eb":"#64748b",cursor:"pointer",fontSize:14,fontWeight:500,textTransform:"capitalize"},children:S},S))}),d.jsxs("div",{style:{flex:1,overflow:"auto",display:"flex",flexDirection:"column"},children:[d.jsx("div",{style:{padding:"0.5rem 1rem"},children:d.jsx(TC,{spec:s,onDownloadTerraform:s?()=>h("terraform"):void 0,onDownloadYaml:s?()=>h("yaml"):void 0,validationSummary:f,usage:y})}),d.jsxs("div",{style:{flex:1,overflow:"auto"},children:[a==="diagram"&&(s||o!=="idle")&&d.jsxs("div",{style:{position:"relative",width:"100%",height:"100%"},children:[s&&d.jsx(MC,{spec:s,onSpecChange:w}),o!=="idle"&&d.jsxs("div",{style:{position:"absolute",top:16,right:16,background:"rgba(37, 99, 235, 0.9)",color:"white",padding:"8px 16px",borderRadius:8,fontSize:13,fontWeight:500,display:"flex",alignItems:"center",gap:8},children:[d.jsx("span",{style:{width:8,height:8,borderRadius:"50%",background:"white",animation:"pulse 1s infinite"}}),o==="generating"?"Generating...":o==="modifying"?"Modifying...":o==="costing"?"Costing & validating...":"Finalizing..."]})]}),a==="diagram"&&!s&&o==="idle"&&d.jsx("div",{style:{padding:32,color:"#64748b"},children:"Design an architecture to see the diagram."}),a==="cost"&&(s==null?void 0:s.cost_estimate)&&d.jsx(zC,{estimate:s.cost_estimate}),a==="cost"&&(!s||!s.cost_estimate)&&d.jsx("div",{style:{padding:32,color:"#64748b"},children:"No cost estimate available."}),a==="spec"&&s&&d.jsx(WC,{spec:s,yaml:((_=e.findLast(S=>S.yaml))==null?void 0:_.yaml)||"No YAML available"}),a==="spec"&&!s&&d.jsx("div",{style:{padding:32,color:"#64748b"},children:"Design an architecture first."}),a==="validate"&&s&&d.jsx(AC,{spec:s,apiBase:Ve}),a==="validate"&&!s&&d.jsx("div",{style:{padding:32,color:"#64748b"},children:"Design an architecture first."}),a==="compliance"&&s&&d.jsx(DC,{spec:s,apiBase:Ve}),a==="compliance"&&!s&&d.jsx("div",{style:{padding:32,color:"#64748b"},children:"Design an architecture first."}),a==="plan"&&s&&d.jsx(BC,{spec:s,apiBase:Ve}),a==="plan"&&!s&&d.jsx("div",{style:{padding:32,color:"#64748b"},children:"Design an architecture first."}),a==="review"&&s&&d.jsx(FC,{spec:s,apiBase:Ve}),a==="review"&&!s&&d.jsx("div",{style:{padding:32,color:"#64748b"},children:"Design an architecture first."}),a==="export"&&s&&d.jsx(HC,{spec:s,apiBase:Ve}),a==="export"&&!s&&d.jsx("div",{style:{padding:32,color:"#64748b"},children:"Design an architecture first."}),a==="modify"&&s&&d.jsxs("div",{style:{padding:32,maxWidth:800},children:[d.jsx("h2",{style:{fontSize:18,marginBottom:16,color:"#0f172a"},children:"Modify Architecture"}),o!=="idle"&&d.jsxs("div",{style:{marginBottom:12,fontSize:13,color:"#64748b"},children:[o==="modifying"&&"Modifying architecture...",o==="costing"&&"Estimating cost & validating...",o==="done"&&"Finalizing..."]}),d.jsx("div",{style:{display:"flex",gap:8},children:d.jsx("input",{value:p,onChange:S=>c(S.target.value),onKeyDown:async S=>{if(S.key==="Enter"&&p.trim()&&o==="idle"){const b=p;c(""),i("modifying");let E=null,A="",D=!1;try{try{await np(!0,{spec:s,instruction:b},{onStage:I=>{I==="generating"?i("modifying"):(I==="costing"||I==="validating")&&i("costing")},onSpec:I=>{l(I),E=I,i("costing")},onCost:I=>{I&&E&&(E={...E,cost_estimate:I},l(E))},onValidation:(I,T)=>{I!==null&&x({passed:I,total:T})},onDone:(I,T)=>{E=I,A=T,l(I),i("done")},onUsage:I=>v(I),onError:I=>{throw new Error(I)}}),D=E!==null}catch{i("modifying")}if(!D){const I=await fetch(`${Ve}/modify`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({spec:s,instruction:b})}),T=await I.json();if(!I.ok)throw new Error(su(T,"Modification failed"));T.usage&&v(T.usage);const C=T.spec;A=T.yaml,i("costing"),E=await Kl(C,x),l(E),i("done")}const P=E;t(I=>[...I,{role:"user",content:b},{role:"assistant",content:`Modified **${P.name}** with ${P.components.length} components on ${P.provider.toUpperCase()}.${P.cost_estimate?` Estimated cost: $${P.cost_estimate.monthly_total.toFixed(2)}/mo.`:""}`,spec:P,yaml:A,suggestions:tp(P)}])}catch(P){t(I=>[...I,{role:"user",content:b},{role:"assistant",content:`Error: ${P instanceof Error?P.message:"Modification failed"}`}])}finally{i("idle")}}},placeholder:"e.g. Add a Redis cache between web and database",style:{flex:1,padding:"10px 14px",borderRadius:8,border:"1px solid #e2e8f0",background:"#ffffff",color:"#0f172a",fontSize:14,outline:"none"}})}),d.jsx("p",{style:{fontSize:12,color:"#64748b",marginTop:8},children:"Press Enter to apply modification"})]}),a==="modify"&&!s&&d.jsx("div",{style:{padding:32,color:"#64748b"},children:"Design an architecture first."})]})]})]})]})}Zl.createRoot(document.getElementById("root")).render(d.jsx(hp.StrictMode,{children:d.jsx(XC,{})})); diff --git a/packages/web/cloudwright_web/static/assets/index-DU-cIjQd.js b/packages/web/cloudwright_web/static/assets/index-DU-cIjQd.js deleted file mode 100644 index f3fab83..0000000 --- a/packages/web/cloudwright_web/static/assets/index-DU-cIjQd.js +++ /dev/null @@ -1,71 +0,0 @@ -(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const o of document.querySelectorAll('link[rel="modulepreload"]'))r(o);new MutationObserver(o=>{for(const i of o)if(i.type==="childList")for(const s of i.addedNodes)s.tagName==="LINK"&&s.rel==="modulepreload"&&r(s)}).observe(document,{childList:!0,subtree:!0});function n(o){const i={};return o.integrity&&(i.integrity=o.integrity),o.referrerPolicy&&(i.referrerPolicy=o.referrerPolicy),o.crossOrigin==="use-credentials"?i.credentials="include":o.crossOrigin==="anonymous"?i.credentials="omit":i.credentials="same-origin",i}function r(o){if(o.ep)return;o.ep=!0;const i=n(o);fetch(o.href,i)}})();function np(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var rp={exports:{}},js={},op={exports:{}},te={};/** - * @license React - * react.production.min.js - * - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */var Do=Symbol.for("react.element"),fy=Symbol.for("react.portal"),py=Symbol.for("react.fragment"),hy=Symbol.for("react.strict_mode"),gy=Symbol.for("react.profiler"),my=Symbol.for("react.provider"),yy=Symbol.for("react.context"),xy=Symbol.for("react.forward_ref"),vy=Symbol.for("react.suspense"),wy=Symbol.for("react.memo"),Sy=Symbol.for("react.lazy"),zc=Symbol.iterator;function ky(e){return e===null||typeof e!="object"?null:(e=zc&&e[zc]||e["@@iterator"],typeof e=="function"?e:null)}var ip={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},sp=Object.assign,lp={};function br(e,t,n){this.props=e,this.context=t,this.refs=lp,this.updater=n||ip}br.prototype.isReactComponent={};br.prototype.setState=function(e,t){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")};br.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function ap(){}ap.prototype=br.prototype;function au(e,t,n){this.props=e,this.context=t,this.refs=lp,this.updater=n||ip}var uu=au.prototype=new ap;uu.constructor=au;sp(uu,br.prototype);uu.isPureReactComponent=!0;var Pc=Array.isArray,up=Object.prototype.hasOwnProperty,cu={current:null},cp={key:!0,ref:!0,__self:!0,__source:!0};function dp(e,t,n){var r,o={},i=null,s=null;if(t!=null)for(r in t.ref!==void 0&&(s=t.ref),t.key!==void 0&&(i=""+t.key),t)up.call(t,r)&&!cp.hasOwnProperty(r)&&(o[r]=t[r]);var l=arguments.length-2;if(l===1)o.children=n;else if(1>>1,B=N[O];if(0>>1;Oo(Y,$))Xo(Q,Y)?(N[O]=Q,N[X]=$,O=X):(N[O]=Y,N[V]=$,O=V);else if(Xo(Q,$))N[O]=Q,N[X]=$,O=X;else break e}}return j}function o(N,j){var $=N.sortIndex-j.sortIndex;return $!==0?$:N.id-j.id}if(typeof performance=="object"&&typeof performance.now=="function"){var i=performance;e.unstable_now=function(){return i.now()}}else{var s=Date,l=s.now();e.unstable_now=function(){return s.now()-l}}var a=[],u=[],p=1,c=null,d=3,x=!1,y=!1,w=!1,k=typeof setTimeout=="function"?setTimeout:null,m=typeof clearTimeout=="function"?clearTimeout:null,g=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function h(N){for(var j=n(u);j!==null;){if(j.callback===null)r(u);else if(j.startTime<=N)r(u),j.sortIndex=j.expirationTime,t(a,j);else break;j=n(u)}}function v(N){if(w=!1,h(N),!y)if(n(a)!==null)y=!0,M(_);else{var j=n(u);j!==null&&R(v,j.startTime-N)}}function _(N,j){y=!1,w&&(w=!1,m(b),b=-1),x=!0;var $=d;try{for(h(j),c=n(a);c!==null&&(!(c.expirationTime>j)||N&&!T());){var O=c.callback;if(typeof O=="function"){c.callback=null,d=c.priorityLevel;var B=O(c.expirationTime<=j);j=e.unstable_now(),typeof B=="function"?c.callback=B:c===n(a)&&r(a),h(j)}else r(a);c=n(a)}if(c!==null)var W=!0;else{var V=n(u);V!==null&&R(v,V.startTime-j),W=!1}return W}finally{c=null,d=$,x=!1}}var S=!1,E=null,b=-1,A=5,D=-1;function T(){return!(e.unstable_now()-DN||125O?(N.sortIndex=$,t(u,N),n(a)===null&&N===n(u)&&(w?(m(b),b=-1):w=!0,R(v,$-O))):(N.sortIndex=B,t(a,N),y||x||(y=!0,M(_))),N},e.unstable_shouldYield=T,e.unstable_wrapCallback=function(N){var j=d;return function(){var $=d;d=j;try{return N.apply(this,arguments)}finally{d=$}}}})(yp);mp.exports=yp;var Iy=mp.exports;/** - * @license React - * react-dom.production.min.js - * - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */var Ry=z,Xe=Iy;function F(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),ql=Object.prototype.hasOwnProperty,Ly=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,Ic={},Rc={};function Ay(e){return ql.call(Rc,e)?!0:ql.call(Ic,e)?!1:Ly.test(e)?Rc[e]=!0:(Ic[e]=!0,!1)}function $y(e,t,n,r){if(n!==null&&n.type===0)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return r?!1:n!==null?!n.acceptsBooleans:(e=e.toLowerCase().slice(0,5),e!=="data-"&&e!=="aria-");default:return!1}}function Dy(e,t,n,r){if(t===null||typeof t>"u"||$y(e,t,n,r))return!0;if(r)return!1;if(n!==null)switch(n.type){case 3:return!t;case 4:return t===!1;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}function Ae(e,t,n,r,o,i,s){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=r,this.attributeNamespace=o,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=i,this.removeEmptyString=s}var Ne={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){Ne[e]=new Ae(e,0,!1,e,null,!1,!1)});[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0];Ne[t]=new Ae(t,1,!1,e[1],null,!1,!1)});["contentEditable","draggable","spellCheck","value"].forEach(function(e){Ne[e]=new Ae(e,2,!1,e.toLowerCase(),null,!1,!1)});["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){Ne[e]=new Ae(e,2,!1,e,null,!1,!1)});"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){Ne[e]=new Ae(e,3,!1,e.toLowerCase(),null,!1,!1)});["checked","multiple","muted","selected"].forEach(function(e){Ne[e]=new Ae(e,3,!0,e,null,!1,!1)});["capture","download"].forEach(function(e){Ne[e]=new Ae(e,4,!1,e,null,!1,!1)});["cols","rows","size","span"].forEach(function(e){Ne[e]=new Ae(e,6,!1,e,null,!1,!1)});["rowSpan","start"].forEach(function(e){Ne[e]=new Ae(e,5,!1,e.toLowerCase(),null,!1,!1)});var fu=/[\-:]([a-z])/g;function pu(e){return e[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var t=e.replace(fu,pu);Ne[t]=new Ae(t,1,!1,e,null,!1,!1)});"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var t=e.replace(fu,pu);Ne[t]=new Ae(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)});["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(fu,pu);Ne[t]=new Ae(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)});["tabIndex","crossOrigin"].forEach(function(e){Ne[e]=new Ae(e,1,!1,e.toLowerCase(),null,!1,!1)});Ne.xlinkHref=new Ae("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1);["src","href","action","formAction"].forEach(function(e){Ne[e]=new Ae(e,1,!1,e.toLowerCase(),null,!0,!0)});function hu(e,t,n,r){var o=Ne.hasOwnProperty(t)?Ne[t]:null;(o!==null?o.type!==0:r||!(2l||o[s]!==i[l]){var a=` -`+o[s].replace(" at new "," at ");return e.displayName&&a.includes("")&&(a=a.replace("",e.displayName)),a}while(1<=s&&0<=l);break}}}finally{al=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?Xr(e):""}function Oy(e){switch(e.tag){case 5:return Xr(e.type);case 16:return Xr("Lazy");case 13:return Xr("Suspense");case 19:return Xr("SuspenseList");case 0:case 2:case 15:return e=ul(e.type,!1),e;case 11:return e=ul(e.type.render,!1),e;case 1:return e=ul(e.type,!0),e;default:return""}}function na(e){if(e==null)return null;if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case Wn:return"Fragment";case Vn:return"Portal";case Jl:return"Profiler";case gu:return"StrictMode";case ea:return"Suspense";case ta:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case wp:return(e.displayName||"Context")+".Consumer";case vp:return(e._context.displayName||"Context")+".Provider";case mu:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case yu:return t=e.displayName||null,t!==null?t:na(e.type)||"Memo";case Xt:t=e._payload,e=e._init;try{return na(e(t))}catch{}}return null}function By(e){var t=e.type;switch(e.tag){case 24:return"Cache";case 9:return(t.displayName||"Context")+".Consumer";case 10:return(t._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=t.render,e=e.displayName||e.name||"",t.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return t;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return na(t);case 8:return t===gu?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof t=="function")return t.displayName||t.name||null;if(typeof t=="string")return t}return null}function cn(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function kp(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function Fy(e){var t=kp(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=""+e[t];if(!e.hasOwnProperty(t)&&typeof n<"u"&&typeof n.get=="function"&&typeof n.set=="function"){var o=n.get,i=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return o.call(this)},set:function(s){r=""+s,i.call(this,s)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(s){r=""+s},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function ei(e){e._valueTracker||(e._valueTracker=Fy(e))}function _p(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=kp(e)?e.checked?"true":"false":e.value),e=r,e!==n?(t.setValue(e),!0):!1}function Xi(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}function ra(e,t){var n=t.checked;return me({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:n??e._wrapperState.initialChecked})}function Ac(e,t){var n=t.defaultValue==null?"":t.defaultValue,r=t.checked!=null?t.checked:t.defaultChecked;n=cn(t.value!=null?t.value:n),e._wrapperState={initialChecked:r,initialValue:n,controlled:t.type==="checkbox"||t.type==="radio"?t.checked!=null:t.value!=null}}function Ep(e,t){t=t.checked,t!=null&&hu(e,"checked",t,!1)}function oa(e,t){Ep(e,t);var n=cn(t.value),r=t.type;if(n!=null)r==="number"?(n===0&&e.value===""||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if(r==="submit"||r==="reset"){e.removeAttribute("value");return}t.hasOwnProperty("value")?ia(e,t.type,n):t.hasOwnProperty("defaultValue")&&ia(e,t.type,cn(t.defaultValue)),t.checked==null&&t.defaultChecked!=null&&(e.defaultChecked=!!t.defaultChecked)}function $c(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var r=t.type;if(!(r!=="submit"&&r!=="reset"||t.value!==void 0&&t.value!==null))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}n=e.name,n!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,n!==""&&(e.name=n)}function ia(e,t,n){(t!=="number"||Xi(e.ownerDocument)!==e)&&(n==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}var Qr=Array.isArray;function rr(e,t,n,r){if(e=e.options,t){t={};for(var o=0;o"+t.valueOf().toString()+"",t=ti.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}});function fo(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&n.nodeType===3){n.nodeValue=t;return}}e.textContent=t}var Jr={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},Hy=["Webkit","ms","Moz","O"];Object.keys(Jr).forEach(function(e){Hy.forEach(function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),Jr[t]=Jr[e]})});function jp(e,t,n){return t==null||typeof t=="boolean"||t===""?"":n||typeof t!="number"||t===0||Jr.hasOwnProperty(e)&&Jr[e]?(""+t).trim():t+"px"}function Mp(e,t){e=e.style;for(var n in t)if(t.hasOwnProperty(n)){var r=n.indexOf("--")===0,o=jp(n,t[n],r);n==="float"&&(n="cssFloat"),r?e.setProperty(n,o):e[n]=o}}var Vy=me({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function aa(e,t){if(t){if(Vy[e]&&(t.children!=null||t.dangerouslySetInnerHTML!=null))throw Error(F(137,e));if(t.dangerouslySetInnerHTML!=null){if(t.children!=null)throw Error(F(60));if(typeof t.dangerouslySetInnerHTML!="object"||!("__html"in t.dangerouslySetInnerHTML))throw Error(F(61))}if(t.style!=null&&typeof t.style!="object")throw Error(F(62))}}function ua(e,t){if(e.indexOf("-")===-1)return typeof t.is=="string";switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var ca=null;function xu(e){return e=e.target||e.srcElement||window,e.correspondingUseElement&&(e=e.correspondingUseElement),e.nodeType===3?e.parentNode:e}var da=null,or=null,ir=null;function Bc(e){if(e=Fo(e)){if(typeof da!="function")throw Error(F(280));var t=e.stateNode;t&&(t=Is(t),da(e.stateNode,e.type,t))}}function zp(e){or?ir?ir.push(e):ir=[e]:or=e}function Pp(){if(or){var e=or,t=ir;if(ir=or=null,Bc(e),t)for(e=0;e>>=0,e===0?32:31-(ex(e)/tx|0)|0}var ni=64,ri=4194304;function Gr(e){switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return e&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return e}}function Zi(e,t){var n=e.pendingLanes;if(n===0)return 0;var r=0,o=e.suspendedLanes,i=e.pingedLanes,s=n&268435455;if(s!==0){var l=s&~o;l!==0?r=Gr(l):(i&=s,i!==0&&(r=Gr(i)))}else s=n&~o,s!==0?r=Gr(s):i!==0&&(r=Gr(i));if(r===0)return 0;if(t!==0&&t!==r&&!(t&o)&&(o=r&-r,i=t&-t,o>=i||o===16&&(i&4194240)!==0))return t;if(r&4&&(r|=n&16),t=e.entangledLanes,t!==0)for(e=e.entanglements,t&=r;0n;n++)t.push(e);return t}function Oo(e,t,n){e.pendingLanes|=t,t!==536870912&&(e.suspendedLanes=0,e.pingedLanes=0),e=e.eventTimes,t=31-ft(t),e[t]=n}function ix(e,t){var n=e.pendingLanes&~t;e.pendingLanes=t,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=t,e.mutableReadLanes&=t,e.entangledLanes&=t,t=e.entanglements;var r=e.eventTimes;for(e=e.expirationTimes;0=to),Gc=" ",Kc=!1;function Zp(e,t){switch(e){case"keyup":return Ix.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function qp(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var Un=!1;function Lx(e,t){switch(e){case"compositionend":return qp(t);case"keypress":return t.which!==32?null:(Kc=!0,Gc);case"textInput":return e=t.data,e===Gc&&Kc?null:e;default:return null}}function Ax(e,t){if(Un)return e==="compositionend"||!bu&&Zp(e,t)?(e=Gp(),Ii=_u=qt=null,Un=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}e:{for(;n;){if(n.nextSibling){n=n.nextSibling;break e}n=n.parentNode}n=void 0}n=ed(n)}}function nh(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?nh(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function rh(){for(var e=window,t=Xi();t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href=="string"}catch{n=!1}if(n)e=t.contentWindow;else break;t=Xi(e.document)}return t}function Nu(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}function Ux(e){var t=rh(),n=e.focusedElem,r=e.selectionRange;if(t!==n&&n&&n.ownerDocument&&nh(n.ownerDocument.documentElement,n)){if(r!==null&&Nu(n)){if(t=r.start,e=r.end,e===void 0&&(e=t),"selectionStart"in n)n.selectionStart=t,n.selectionEnd=Math.min(e,n.value.length);else if(e=(t=n.ownerDocument||document)&&t.defaultView||window,e.getSelection){e=e.getSelection();var o=n.textContent.length,i=Math.min(r.start,o);r=r.end===void 0?i:Math.min(r.end,o),!e.extend&&i>r&&(o=r,r=i,i=o),o=td(n,i);var s=td(n,r);o&&s&&(e.rangeCount!==1||e.anchorNode!==o.node||e.anchorOffset!==o.offset||e.focusNode!==s.node||e.focusOffset!==s.offset)&&(t=t.createRange(),t.setStart(o.node,o.offset),e.removeAllRanges(),i>r?(e.addRange(t),e.extend(s.node,s.offset)):(t.setEnd(s.node,s.offset),e.addRange(t)))}}for(t=[],e=n;e=e.parentNode;)e.nodeType===1&&t.push({element:e,left:e.scrollLeft,top:e.scrollTop});for(typeof n.focus=="function"&&n.focus(),n=0;n=document.documentMode,Yn=null,ya=null,ro=null,xa=!1;function nd(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;xa||Yn==null||Yn!==Xi(r)||(r=Yn,"selectionStart"in r&&Nu(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),ro&&xo(ro,r)||(ro=r,r=es(ya,"onSelect"),0Gn||(e.current=Ea[Gn],Ea[Gn]=null,Gn--)}function ae(e,t){Gn++,Ea[Gn]=e.current,e.current=t}var dn={},Te=pn(dn),Be=pn(!1),Nn=dn;function fr(e,t){var n=e.type.contextTypes;if(!n)return dn;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var o={},i;for(i in n)o[i]=t[i];return r&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=o),o}function Fe(e){return e=e.childContextTypes,e!=null}function ns(){ce(Be),ce(Te)}function ud(e,t,n){if(Te.current!==dn)throw Error(F(168));ae(Te,t),ae(Be,n)}function fh(e,t,n){var r=e.stateNode;if(t=t.childContextTypes,typeof r.getChildContext!="function")return n;r=r.getChildContext();for(var o in r)if(!(o in t))throw Error(F(108,By(e)||"Unknown",o));return me({},n,r)}function rs(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||dn,Nn=Te.current,ae(Te,e),ae(Be,Be.current),!0}function cd(e,t,n){var r=e.stateNode;if(!r)throw Error(F(169));n?(e=fh(e,t,Nn),r.__reactInternalMemoizedMergedChildContext=e,ce(Be),ce(Te),ae(Te,e)):ce(Be),ae(Be,n)}var Pt=null,Rs=!1,_l=!1;function ph(e){Pt===null?Pt=[e]:Pt.push(e)}function r1(e){Rs=!0,ph(e)}function hn(){if(!_l&&Pt!==null){_l=!0;var e=0,t=se;try{var n=Pt;for(se=1;e>=s,o-=s,Tt=1<<32-ft(t)+o|n<b?(A=E,E=null):A=E.sibling;var D=d(m,E,h[b],v);if(D===null){E===null&&(E=A);break}e&&E&&D.alternate===null&&t(m,E),g=i(D,g,b),S===null?_=D:S.sibling=D,S=D,E=A}if(b===h.length)return n(m,E),de&&mn(m,b),_;if(E===null){for(;bb?(A=E,E=null):A=E.sibling;var T=d(m,E,D.value,v);if(T===null){E===null&&(E=A);break}e&&E&&T.alternate===null&&t(m,E),g=i(T,g,b),S===null?_=T:S.sibling=T,S=T,E=A}if(D.done)return n(m,E),de&&mn(m,b),_;if(E===null){for(;!D.done;b++,D=h.next())D=c(m,D.value,v),D!==null&&(g=i(D,g,b),S===null?_=D:S.sibling=D,S=D);return de&&mn(m,b),_}for(E=r(m,E);!D.done;b++,D=h.next())D=x(E,m,b,D.value,v),D!==null&&(e&&D.alternate!==null&&E.delete(D.key===null?b:D.key),g=i(D,g,b),S===null?_=D:S.sibling=D,S=D);return e&&E.forEach(function(I){return t(m,I)}),de&&mn(m,b),_}function k(m,g,h,v){if(typeof h=="object"&&h!==null&&h.type===Wn&&h.key===null&&(h=h.props.children),typeof h=="object"&&h!==null){switch(h.$$typeof){case Jo:e:{for(var _=h.key,S=g;S!==null;){if(S.key===_){if(_=h.type,_===Wn){if(S.tag===7){n(m,S.sibling),g=o(S,h.props.children),g.return=m,m=g;break e}}else if(S.elementType===_||typeof _=="object"&&_!==null&&_.$$typeof===Xt&&pd(_)===S.type){n(m,S.sibling),g=o(S,h.props),g.ref=Dr(m,S,h),g.return=m,m=g;break e}n(m,S);break}else t(m,S);S=S.sibling}h.type===Wn?(g=En(h.props.children,m.mode,v,h.key),g.return=m,m=g):(v=Fi(h.type,h.key,h.props,null,m.mode,v),v.ref=Dr(m,g,h),v.return=m,m=v)}return s(m);case Vn:e:{for(S=h.key;g!==null;){if(g.key===S)if(g.tag===4&&g.stateNode.containerInfo===h.containerInfo&&g.stateNode.implementation===h.implementation){n(m,g.sibling),g=o(g,h.children||[]),g.return=m,m=g;break e}else{n(m,g);break}else t(m,g);g=g.sibling}g=Pl(h,m.mode,v),g.return=m,m=g}return s(m);case Xt:return S=h._init,k(m,g,S(h._payload),v)}if(Qr(h))return y(m,g,h,v);if(Ir(h))return w(m,g,h,v);ci(m,h)}return typeof h=="string"&&h!==""||typeof h=="number"?(h=""+h,g!==null&&g.tag===6?(n(m,g.sibling),g=o(g,h),g.return=m,m=g):(n(m,g),g=zl(h,m.mode,v),g.return=m,m=g),s(m)):n(m,g)}return k}var hr=yh(!0),xh=yh(!1),ss=pn(null),ls=null,qn=null,Pu=null;function Tu(){Pu=qn=ls=null}function Iu(e){var t=ss.current;ce(ss),e._currentValue=t}function Na(e,t,n){for(;e!==null;){var r=e.alternate;if((e.childLanes&t)!==t?(e.childLanes|=t,r!==null&&(r.childLanes|=t)):r!==null&&(r.childLanes&t)!==t&&(r.childLanes|=t),e===n)break;e=e.return}}function lr(e,t){ls=e,Pu=qn=null,e=e.dependencies,e!==null&&e.firstContext!==null&&(e.lanes&t&&(De=!0),e.firstContext=null)}function nt(e){var t=e._currentValue;if(Pu!==e)if(e={context:e,memoizedValue:t,next:null},qn===null){if(ls===null)throw Error(F(308));qn=e,ls.dependencies={lanes:0,firstContext:e}}else qn=qn.next=e;return t}var wn=null;function Ru(e){wn===null?wn=[e]:wn.push(e)}function vh(e,t,n,r){var o=t.interleaved;return o===null?(n.next=n,Ru(t)):(n.next=o.next,o.next=n),t.interleaved=n,Dt(e,r)}function Dt(e,t){e.lanes|=t;var n=e.alternate;for(n!==null&&(n.lanes|=t),n=e,e=e.return;e!==null;)e.childLanes|=t,n=e.alternate,n!==null&&(n.childLanes|=t),n=e,e=e.return;return n.tag===3?n.stateNode:null}var Qt=!1;function Lu(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,interleaved:null,lanes:0},effects:null}}function wh(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,effects:e.effects})}function Lt(e,t){return{eventTime:e,lane:t,tag:0,payload:null,callback:null,next:null}}function on(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,oe&2){var o=r.pending;return o===null?t.next=t:(t.next=o.next,o.next=t),r.pending=t,Dt(e,n)}return o=r.interleaved,o===null?(t.next=t,Ru(r)):(t.next=o.next,o.next=t),r.interleaved=t,Dt(e,n)}function Li(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,(n&4194240)!==0)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,wu(e,n)}}function hd(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var o=null,i=null;if(n=n.firstBaseUpdate,n!==null){do{var s={eventTime:n.eventTime,lane:n.lane,tag:n.tag,payload:n.payload,callback:n.callback,next:null};i===null?o=i=s:i=i.next=s,n=n.next}while(n!==null);i===null?o=i=t:i=i.next=t}else o=i=t;n={baseState:r.baseState,firstBaseUpdate:o,lastBaseUpdate:i,shared:r.shared,effects:r.effects},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}function as(e,t,n,r){var o=e.updateQueue;Qt=!1;var i=o.firstBaseUpdate,s=o.lastBaseUpdate,l=o.shared.pending;if(l!==null){o.shared.pending=null;var a=l,u=a.next;a.next=null,s===null?i=u:s.next=u,s=a;var p=e.alternate;p!==null&&(p=p.updateQueue,l=p.lastBaseUpdate,l!==s&&(l===null?p.firstBaseUpdate=u:l.next=u,p.lastBaseUpdate=a))}if(i!==null){var c=o.baseState;s=0,p=u=a=null,l=i;do{var d=l.lane,x=l.eventTime;if((r&d)===d){p!==null&&(p=p.next={eventTime:x,lane:0,tag:l.tag,payload:l.payload,callback:l.callback,next:null});e:{var y=e,w=l;switch(d=t,x=n,w.tag){case 1:if(y=w.payload,typeof y=="function"){c=y.call(x,c,d);break e}c=y;break e;case 3:y.flags=y.flags&-65537|128;case 0:if(y=w.payload,d=typeof y=="function"?y.call(x,c,d):y,d==null)break e;c=me({},c,d);break e;case 2:Qt=!0}}l.callback!==null&&l.lane!==0&&(e.flags|=64,d=o.effects,d===null?o.effects=[l]:d.push(l))}else x={eventTime:x,lane:d,tag:l.tag,payload:l.payload,callback:l.callback,next:null},p===null?(u=p=x,a=c):p=p.next=x,s|=d;if(l=l.next,l===null){if(l=o.shared.pending,l===null)break;d=l,l=d.next,d.next=null,o.lastBaseUpdate=d,o.shared.pending=null}}while(!0);if(p===null&&(a=c),o.baseState=a,o.firstBaseUpdate=u,o.lastBaseUpdate=p,t=o.shared.interleaved,t!==null){o=t;do s|=o.lane,o=o.next;while(o!==t)}else i===null&&(o.shared.lanes=0);zn|=s,e.lanes=s,e.memoizedState=c}}function gd(e,t,n){if(e=t.effects,t.effects=null,e!==null)for(t=0;tn?n:4,e(!0);var r=Cl.transition;Cl.transition={};try{e(!1),t()}finally{se=n,Cl.transition=r}}function $h(){return rt().memoizedState}function l1(e,t,n){var r=ln(e);if(n={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null},Dh(e))Oh(t,n);else if(n=vh(e,t,n,r),n!==null){var o=Re();pt(n,e,r,o),Bh(n,t,r)}}function a1(e,t,n){var r=ln(e),o={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null};if(Dh(e))Oh(t,o);else{var i=e.alternate;if(e.lanes===0&&(i===null||i.lanes===0)&&(i=t.lastRenderedReducer,i!==null))try{var s=t.lastRenderedState,l=i(s,n);if(o.hasEagerState=!0,o.eagerState=l,ht(l,s)){var a=t.interleaved;a===null?(o.next=o,Ru(t)):(o.next=a.next,a.next=o),t.interleaved=o;return}}catch{}finally{}n=vh(e,t,o,r),n!==null&&(o=Re(),pt(n,e,r,o),Bh(n,t,r))}}function Dh(e){var t=e.alternate;return e===ge||t!==null&&t===ge}function Oh(e,t){oo=cs=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function Bh(e,t,n){if(n&4194240){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,wu(e,n)}}var ds={readContext:nt,useCallback:Me,useContext:Me,useEffect:Me,useImperativeHandle:Me,useInsertionEffect:Me,useLayoutEffect:Me,useMemo:Me,useReducer:Me,useRef:Me,useState:Me,useDebugValue:Me,useDeferredValue:Me,useTransition:Me,useMutableSource:Me,useSyncExternalStore:Me,useId:Me,unstable_isNewReconciler:!1},u1={readContext:nt,useCallback:function(e,t){return wt().memoizedState=[e,t===void 0?null:t],e},useContext:nt,useEffect:yd,useImperativeHandle:function(e,t,n){return n=n!=null?n.concat([e]):null,$i(4194308,4,Th.bind(null,t,e),n)},useLayoutEffect:function(e,t){return $i(4194308,4,e,t)},useInsertionEffect:function(e,t){return $i(4,2,e,t)},useMemo:function(e,t){var n=wt();return t=t===void 0?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var r=wt();return t=n!==void 0?n(t):t,r.memoizedState=r.baseState=t,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:t},r.queue=e,e=e.dispatch=l1.bind(null,ge,e),[r.memoizedState,e]},useRef:function(e){var t=wt();return e={current:e},t.memoizedState=e},useState:md,useDebugValue:Vu,useDeferredValue:function(e){return wt().memoizedState=e},useTransition:function(){var e=md(!1),t=e[0];return e=s1.bind(null,e[1]),wt().memoizedState=e,[t,e]},useMutableSource:function(){},useSyncExternalStore:function(e,t,n){var r=ge,o=wt();if(de){if(n===void 0)throw Error(F(407));n=n()}else{if(n=t(),Ee===null)throw Error(F(349));Mn&30||Eh(r,t,n)}o.memoizedState=n;var i={value:n,getSnapshot:t};return o.queue=i,yd(bh.bind(null,r,i,e),[e]),r.flags|=2048,bo(9,Ch.bind(null,r,i,n,t),void 0,null),n},useId:function(){var e=wt(),t=Ee.identifierPrefix;if(de){var n=It,r=Tt;n=(r&~(1<<32-ft(r)-1)).toString(32)+n,t=":"+t+"R"+n,n=Eo++,0<\/script>",e=e.removeChild(e.firstChild)):typeof r.is=="string"?e=s.createElement(n,{is:r.is}):(e=s.createElement(n),n==="select"&&(s=e,r.multiple?s.multiple=!0:r.size&&(s.size=r.size))):e=s.createElementNS(e,n),e[kt]=t,e[So]=r,Kh(e,t,!1,!1),t.stateNode=e;e:{switch(s=ua(n,r),n){case"dialog":ue("cancel",e),ue("close",e),o=r;break;case"iframe":case"object":case"embed":ue("load",e),o=r;break;case"video":case"audio":for(o=0;oyr&&(t.flags|=128,r=!0,Or(i,!1),t.lanes=4194304)}else{if(!r)if(e=us(s),e!==null){if(t.flags|=128,r=!0,n=e.updateQueue,n!==null&&(t.updateQueue=n,t.flags|=4),Or(i,!0),i.tail===null&&i.tailMode==="hidden"&&!s.alternate&&!de)return ze(t),null}else 2*xe()-i.renderingStartTime>yr&&n!==1073741824&&(t.flags|=128,r=!0,Or(i,!1),t.lanes=4194304);i.isBackwards?(s.sibling=t.child,t.child=s):(n=i.last,n!==null?n.sibling=s:t.child=s,i.last=s)}return i.tail!==null?(t=i.tail,i.rendering=t,i.tail=t.sibling,i.renderingStartTime=xe(),t.sibling=null,n=he.current,ae(he,r?n&1|2:n&1),t):(ze(t),null);case 22:case 23:return Gu(),r=t.memoizedState!==null,e!==null&&e.memoizedState!==null!==r&&(t.flags|=8192),r&&t.mode&1?Ve&1073741824&&(ze(t),t.subtreeFlags&6&&(t.flags|=8192)):ze(t),null;case 24:return null;case 25:return null}throw Error(F(156,t.tag))}function y1(e,t){switch(Mu(t),t.tag){case 1:return Fe(t.type)&&ns(),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return gr(),ce(Be),ce(Te),Du(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 5:return $u(t),null;case 13:if(ce(he),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(F(340));pr()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return ce(he),null;case 4:return gr(),null;case 10:return Iu(t.type._context),null;case 22:case 23:return Gu(),null;case 24:return null;default:return null}}var fi=!1,Pe=!1,x1=typeof WeakSet=="function"?WeakSet:Set,U=null;function Jn(e,t){var n=e.ref;if(n!==null)if(typeof n=="function")try{n(null)}catch(r){ye(e,t,r)}else n.current=null}function Aa(e,t,n){try{n()}catch(r){ye(e,t,r)}}var jd=!1;function v1(e,t){if(va=qi,e=rh(),Nu(e)){if("selectionStart"in e)var n={start:e.selectionStart,end:e.selectionEnd};else e:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var o=r.anchorOffset,i=r.focusNode;r=r.focusOffset;try{n.nodeType,i.nodeType}catch{n=null;break e}var s=0,l=-1,a=-1,u=0,p=0,c=e,d=null;t:for(;;){for(var x;c!==n||o!==0&&c.nodeType!==3||(l=s+o),c!==i||r!==0&&c.nodeType!==3||(a=s+r),c.nodeType===3&&(s+=c.nodeValue.length),(x=c.firstChild)!==null;)d=c,c=x;for(;;){if(c===e)break t;if(d===n&&++u===o&&(l=s),d===i&&++p===r&&(a=s),(x=c.nextSibling)!==null)break;c=d,d=c.parentNode}c=x}n=l===-1||a===-1?null:{start:l,end:a}}else n=null}n=n||{start:0,end:0}}else n=null;for(wa={focusedElem:e,selectionRange:n},qi=!1,U=t;U!==null;)if(t=U,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,U=e;else for(;U!==null;){t=U;try{var y=t.alternate;if(t.flags&1024)switch(t.tag){case 0:case 11:case 15:break;case 1:if(y!==null){var w=y.memoizedProps,k=y.memoizedState,m=t.stateNode,g=m.getSnapshotBeforeUpdate(t.elementType===t.type?w:it(t.type,w),k);m.__reactInternalSnapshotBeforeUpdate=g}break;case 3:var h=t.stateNode.containerInfo;h.nodeType===1?h.textContent="":h.nodeType===9&&h.documentElement&&h.removeChild(h.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(F(163))}}catch(v){ye(t,t.return,v)}if(e=t.sibling,e!==null){e.return=t.return,U=e;break}U=t.return}return y=jd,jd=!1,y}function io(e,t,n){var r=t.updateQueue;if(r=r!==null?r.lastEffect:null,r!==null){var o=r=r.next;do{if((o.tag&e)===e){var i=o.destroy;o.destroy=void 0,i!==void 0&&Aa(t,n,i)}o=o.next}while(o!==r)}}function $s(e,t){if(t=t.updateQueue,t=t!==null?t.lastEffect:null,t!==null){var n=t=t.next;do{if((n.tag&e)===e){var r=n.create;n.destroy=r()}n=n.next}while(n!==t)}}function $a(e){var t=e.ref;if(t!==null){var n=e.stateNode;switch(e.tag){case 5:e=n;break;default:e=n}typeof t=="function"?t(e):t.current=e}}function Jh(e){var t=e.alternate;t!==null&&(e.alternate=null,Jh(t)),e.child=null,e.deletions=null,e.sibling=null,e.tag===5&&(t=e.stateNode,t!==null&&(delete t[kt],delete t[So],delete t[_a],delete t[t1],delete t[n1])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function eg(e){return e.tag===5||e.tag===3||e.tag===4}function Md(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||eg(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function Da(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.nodeType===8?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(n.nodeType===8?(t=n.parentNode,t.insertBefore(e,n)):(t=n,t.appendChild(e)),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=ts));else if(r!==4&&(e=e.child,e!==null))for(Da(e,t,n),e=e.sibling;e!==null;)Da(e,t,n),e=e.sibling}function Oa(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(e=e.child,e!==null))for(Oa(e,t,n),e=e.sibling;e!==null;)Oa(e,t,n),e=e.sibling}var Ce=null,st=!1;function Wt(e,t,n){for(n=n.child;n!==null;)tg(e,t,n),n=n.sibling}function tg(e,t,n){if(_t&&typeof _t.onCommitFiberUnmount=="function")try{_t.onCommitFiberUnmount(Ms,n)}catch{}switch(n.tag){case 5:Pe||Jn(n,t);case 6:var r=Ce,o=st;Ce=null,Wt(e,t,n),Ce=r,st=o,Ce!==null&&(st?(e=Ce,n=n.stateNode,e.nodeType===8?e.parentNode.removeChild(n):e.removeChild(n)):Ce.removeChild(n.stateNode));break;case 18:Ce!==null&&(st?(e=Ce,n=n.stateNode,e.nodeType===8?kl(e.parentNode,n):e.nodeType===1&&kl(e,n),mo(e)):kl(Ce,n.stateNode));break;case 4:r=Ce,o=st,Ce=n.stateNode.containerInfo,st=!0,Wt(e,t,n),Ce=r,st=o;break;case 0:case 11:case 14:case 15:if(!Pe&&(r=n.updateQueue,r!==null&&(r=r.lastEffect,r!==null))){o=r=r.next;do{var i=o,s=i.destroy;i=i.tag,s!==void 0&&(i&2||i&4)&&Aa(n,t,s),o=o.next}while(o!==r)}Wt(e,t,n);break;case 1:if(!Pe&&(Jn(n,t),r=n.stateNode,typeof r.componentWillUnmount=="function"))try{r.props=n.memoizedProps,r.state=n.memoizedState,r.componentWillUnmount()}catch(l){ye(n,t,l)}Wt(e,t,n);break;case 21:Wt(e,t,n);break;case 22:n.mode&1?(Pe=(r=Pe)||n.memoizedState!==null,Wt(e,t,n),Pe=r):Wt(e,t,n);break;default:Wt(e,t,n)}}function zd(e){var t=e.updateQueue;if(t!==null){e.updateQueue=null;var n=e.stateNode;n===null&&(n=e.stateNode=new x1),t.forEach(function(r){var o=j1.bind(null,e,r);n.has(r)||(n.add(r),r.then(o,o))})}}function ot(e,t){var n=t.deletions;if(n!==null)for(var r=0;ro&&(o=s),r&=~i}if(r=o,r=xe()-r,r=(120>r?120:480>r?480:1080>r?1080:1920>r?1920:3e3>r?3e3:4320>r?4320:1960*S1(r/1960))-r,10e?16:e,Jt===null)var r=!1;else{if(e=Jt,Jt=null,hs=0,oe&6)throw Error(F(331));var o=oe;for(oe|=4,U=e.current;U!==null;){var i=U,s=i.child;if(U.flags&16){var l=i.deletions;if(l!==null){for(var a=0;axe()-Xu?_n(e,0):Yu|=n),He(e,t)}function ug(e,t){t===0&&(e.mode&1?(t=ri,ri<<=1,!(ri&130023424)&&(ri=4194304)):t=1);var n=Re();e=Dt(e,t),e!==null&&(Oo(e,t,n),He(e,n))}function N1(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),ug(e,n)}function j1(e,t){var n=0;switch(e.tag){case 13:var r=e.stateNode,o=e.memoizedState;o!==null&&(n=o.retryLane);break;case 19:r=e.stateNode;break;default:throw Error(F(314))}r!==null&&r.delete(t),ug(e,n)}var cg;cg=function(e,t,n){if(e!==null)if(e.memoizedProps!==t.pendingProps||Be.current)De=!0;else{if(!(e.lanes&n)&&!(t.flags&128))return De=!1,g1(e,t,n);De=!!(e.flags&131072)}else De=!1,de&&t.flags&1048576&&hh(t,is,t.index);switch(t.lanes=0,t.tag){case 2:var r=t.type;Di(e,t),e=t.pendingProps;var o=fr(t,Te.current);lr(t,n),o=Bu(null,t,r,e,o,n);var i=Fu();return t.flags|=1,typeof o=="object"&&o!==null&&typeof o.render=="function"&&o.$$typeof===void 0?(t.tag=1,t.memoizedState=null,t.updateQueue=null,Fe(r)?(i=!0,rs(t)):i=!1,t.memoizedState=o.state!==null&&o.state!==void 0?o.state:null,Lu(t),o.updater=As,t.stateNode=o,o._reactInternals=t,Ma(t,r,e,n),t=Ta(null,t,r,!0,i,n)):(t.tag=0,de&&i&&ju(t),Ie(null,t,o,n),t=t.child),t;case 16:r=t.elementType;e:{switch(Di(e,t),e=t.pendingProps,o=r._init,r=o(r._payload),t.type=r,o=t.tag=z1(r),e=it(r,e),o){case 0:t=Pa(null,t,r,e,n);break e;case 1:t=Cd(null,t,r,e,n);break e;case 11:t=_d(null,t,r,e,n);break e;case 14:t=Ed(null,t,r,it(r.type,e),n);break e}throw Error(F(306,r,""))}return t;case 0:return r=t.type,o=t.pendingProps,o=t.elementType===r?o:it(r,o),Pa(e,t,r,o,n);case 1:return r=t.type,o=t.pendingProps,o=t.elementType===r?o:it(r,o),Cd(e,t,r,o,n);case 3:e:{if(Xh(t),e===null)throw Error(F(387));r=t.pendingProps,i=t.memoizedState,o=i.element,wh(e,t),as(t,r,null,n);var s=t.memoizedState;if(r=s.element,i.isDehydrated)if(i={element:r,isDehydrated:!1,cache:s.cache,pendingSuspenseBoundaries:s.pendingSuspenseBoundaries,transitions:s.transitions},t.updateQueue.baseState=i,t.memoizedState=i,t.flags&256){o=mr(Error(F(423)),t),t=bd(e,t,r,n,o);break e}else if(r!==o){o=mr(Error(F(424)),t),t=bd(e,t,r,n,o);break e}else for(Ue=rn(t.stateNode.containerInfo.firstChild),Ye=t,de=!0,at=null,n=xh(t,null,r,n),t.child=n;n;)n.flags=n.flags&-3|4096,n=n.sibling;else{if(pr(),r===o){t=Ot(e,t,n);break e}Ie(e,t,r,n)}t=t.child}return t;case 5:return Sh(t),e===null&&ba(t),r=t.type,o=t.pendingProps,i=e!==null?e.memoizedProps:null,s=o.children,Sa(r,o)?s=null:i!==null&&Sa(r,i)&&(t.flags|=32),Yh(e,t),Ie(e,t,s,n),t.child;case 6:return e===null&&ba(t),null;case 13:return Qh(e,t,n);case 4:return Au(t,t.stateNode.containerInfo),r=t.pendingProps,e===null?t.child=hr(t,null,r,n):Ie(e,t,r,n),t.child;case 11:return r=t.type,o=t.pendingProps,o=t.elementType===r?o:it(r,o),_d(e,t,r,o,n);case 7:return Ie(e,t,t.pendingProps,n),t.child;case 8:return Ie(e,t,t.pendingProps.children,n),t.child;case 12:return Ie(e,t,t.pendingProps.children,n),t.child;case 10:e:{if(r=t.type._context,o=t.pendingProps,i=t.memoizedProps,s=o.value,ae(ss,r._currentValue),r._currentValue=s,i!==null)if(ht(i.value,s)){if(i.children===o.children&&!Be.current){t=Ot(e,t,n);break e}}else for(i=t.child,i!==null&&(i.return=t);i!==null;){var l=i.dependencies;if(l!==null){s=i.child;for(var a=l.firstContext;a!==null;){if(a.context===r){if(i.tag===1){a=Lt(-1,n&-n),a.tag=2;var u=i.updateQueue;if(u!==null){u=u.shared;var p=u.pending;p===null?a.next=a:(a.next=p.next,p.next=a),u.pending=a}}i.lanes|=n,a=i.alternate,a!==null&&(a.lanes|=n),Na(i.return,n,t),l.lanes|=n;break}a=a.next}}else if(i.tag===10)s=i.type===t.type?null:i.child;else if(i.tag===18){if(s=i.return,s===null)throw Error(F(341));s.lanes|=n,l=s.alternate,l!==null&&(l.lanes|=n),Na(s,n,t),s=i.sibling}else s=i.child;if(s!==null)s.return=i;else for(s=i;s!==null;){if(s===t){s=null;break}if(i=s.sibling,i!==null){i.return=s.return,s=i;break}s=s.return}i=s}Ie(e,t,o.children,n),t=t.child}return t;case 9:return o=t.type,r=t.pendingProps.children,lr(t,n),o=nt(o),r=r(o),t.flags|=1,Ie(e,t,r,n),t.child;case 14:return r=t.type,o=it(r,t.pendingProps),o=it(r.type,o),Ed(e,t,r,o,n);case 15:return Wh(e,t,t.type,t.pendingProps,n);case 17:return r=t.type,o=t.pendingProps,o=t.elementType===r?o:it(r,o),Di(e,t),t.tag=1,Fe(r)?(e=!0,rs(t)):e=!1,lr(t,n),Fh(t,r,o),Ma(t,r,o,n),Ta(null,t,r,!0,e,n);case 19:return Gh(e,t,n);case 22:return Uh(e,t,n)}throw Error(F(156,t.tag))};function dg(e,t){return Dp(e,t)}function M1(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function et(e,t,n,r){return new M1(e,t,n,r)}function Zu(e){return e=e.prototype,!(!e||!e.isReactComponent)}function z1(e){if(typeof e=="function")return Zu(e)?1:0;if(e!=null){if(e=e.$$typeof,e===mu)return 11;if(e===yu)return 14}return 2}function an(e,t){var n=e.alternate;return n===null?(n=et(e.tag,t,e.key,e.mode),n.elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.subtreeFlags=0,n.deletions=null),n.flags=e.flags&14680064,n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=t===null?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function Fi(e,t,n,r,o,i){var s=2;if(r=e,typeof e=="function")Zu(e)&&(s=1);else if(typeof e=="string")s=5;else e:switch(e){case Wn:return En(n.children,o,i,t);case gu:s=8,o|=8;break;case Jl:return e=et(12,n,t,o|2),e.elementType=Jl,e.lanes=i,e;case ea:return e=et(13,n,t,o),e.elementType=ea,e.lanes=i,e;case ta:return e=et(19,n,t,o),e.elementType=ta,e.lanes=i,e;case Sp:return Os(n,o,i,t);default:if(typeof e=="object"&&e!==null)switch(e.$$typeof){case vp:s=10;break e;case wp:s=9;break e;case mu:s=11;break e;case yu:s=14;break e;case Xt:s=16,r=null;break e}throw Error(F(130,e==null?e:typeof e,""))}return t=et(s,n,t,o),t.elementType=e,t.type=r,t.lanes=i,t}function En(e,t,n,r){return e=et(7,e,r,t),e.lanes=n,e}function Os(e,t,n,r){return e=et(22,e,r,t),e.elementType=Sp,e.lanes=n,e.stateNode={isHidden:!1},e}function zl(e,t,n){return e=et(6,e,null,t),e.lanes=n,e}function Pl(e,t,n){return t=et(4,e.children!==null?e.children:[],e.key,t),t.lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function P1(e,t,n,r,o){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=dl(0),this.expirationTimes=dl(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=dl(0),this.identifierPrefix=r,this.onRecoverableError=o,this.mutableSourceEagerHydrationData=null}function qu(e,t,n,r,o,i,s,l,a){return e=new P1(e,t,n,l,a),t===1?(t=1,i===!0&&(t|=8)):t=0,i=et(3,null,null,t),e.current=i,i.stateNode=e,i.memoizedState={element:r,isDehydrated:n,cache:null,transitions:null,pendingSuspenseBoundaries:null},Lu(i),e}function T1(e,t,n){var r=3"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(gg)}catch(e){console.error(e)}}gg(),gp.exports=Ge;var $1=gp.exports,Dd=$1;Zl.createRoot=Dd.createRoot,Zl.hydrateRoot=Dd.hydrateRoot;function we(e){if(typeof e=="string"||typeof e=="number")return""+e;let t="";if(Array.isArray(e))for(let n=0,r;n{}};function Ws(){for(var e=0,t=arguments.length,n={},r;e=0&&(r=n.slice(o+1),n=n.slice(0,o)),n&&!t.hasOwnProperty(n))throw new Error("unknown type: "+n);return{type:n,name:r}})}Hi.prototype=Ws.prototype={constructor:Hi,on:function(e,t){var n=this._,r=O1(e+"",n),o,i=-1,s=r.length;if(arguments.length<2){for(;++i0)for(var n=new Array(o),r=0,o,i;r=0&&(t=e.slice(0,n))!=="xmlns"&&(e=e.slice(n+1)),Bd.hasOwnProperty(t)?{space:Bd[t],local:e}:e}function F1(e){return function(){var t=this.ownerDocument,n=this.namespaceURI;return n===Wa&&t.documentElement.namespaceURI===Wa?t.createElement(e):t.createElementNS(n,e)}}function H1(e){return function(){return this.ownerDocument.createElementNS(e.space,e.local)}}function mg(e){var t=Us(e);return(t.local?H1:F1)(t)}function V1(){}function nc(e){return e==null?V1:function(){return this.querySelector(e)}}function W1(e){typeof e!="function"&&(e=nc(e));for(var t=this._groups,n=t.length,r=new Array(n),o=0;o=h&&(h=g+1);!(_=k[h])&&++h=0;)(s=r[o])&&(i&&s.compareDocumentPosition(i)^4&&i.parentNode.insertBefore(s,i),i=s);return this}function gv(e){e||(e=mv);function t(c,d){return c&&d?e(c.__data__,d.__data__):!c-!d}for(var n=this._groups,r=n.length,o=new Array(r),i=0;it?1:e>=t?0:NaN}function yv(){var e=arguments[0];return arguments[0]=this,e.apply(null,arguments),this}function xv(){return Array.from(this)}function vv(){for(var e=this._groups,t=0,n=e.length;t1?this.each((t==null?zv:typeof t=="function"?Tv:Pv)(e,t,n??"")):xr(this.node(),e)}function xr(e,t){return e.style.getPropertyValue(t)||Sg(e).getComputedStyle(e,null).getPropertyValue(t)}function Rv(e){return function(){delete this[e]}}function Lv(e,t){return function(){this[e]=t}}function Av(e,t){return function(){var n=t.apply(this,arguments);n==null?delete this[e]:this[e]=n}}function $v(e,t){return arguments.length>1?this.each((t==null?Rv:typeof t=="function"?Av:Lv)(e,t)):this.node()[e]}function kg(e){return e.trim().split(/^|\s+/)}function rc(e){return e.classList||new _g(e)}function _g(e){this._node=e,this._names=kg(e.getAttribute("class")||"")}_g.prototype={add:function(e){var t=this._names.indexOf(e);t<0&&(this._names.push(e),this._node.setAttribute("class",this._names.join(" ")))},remove:function(e){var t=this._names.indexOf(e);t>=0&&(this._names.splice(t,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(e){return this._names.indexOf(e)>=0}};function Eg(e,t){for(var n=rc(e),r=-1,o=t.length;++r=0&&(n=t.slice(r+1),t=t.slice(0,r)),{type:t,name:n}})}function dw(e){return function(){var t=this.__on;if(t){for(var n=0,r=-1,o=t.length,i;n()=>e;function Ua(e,{sourceEvent:t,subject:n,target:r,identifier:o,active:i,x:s,y:l,dx:a,dy:u,dispatch:p}){Object.defineProperties(this,{type:{value:e,enumerable:!0,configurable:!0},sourceEvent:{value:t,enumerable:!0,configurable:!0},subject:{value:n,enumerable:!0,configurable:!0},target:{value:r,enumerable:!0,configurable:!0},identifier:{value:o,enumerable:!0,configurable:!0},active:{value:i,enumerable:!0,configurable:!0},x:{value:s,enumerable:!0,configurable:!0},y:{value:l,enumerable:!0,configurable:!0},dx:{value:a,enumerable:!0,configurable:!0},dy:{value:u,enumerable:!0,configurable:!0},_:{value:p}})}Ua.prototype.on=function(){var e=this._.on.apply(this._,arguments);return e===this._?this:e};function Sw(e){return!e.ctrlKey&&!e.button}function kw(){return this.parentNode}function _w(e,t){return t??{x:e.x,y:e.y}}function Ew(){return navigator.maxTouchPoints||"ontouchstart"in this}function zg(){var e=Sw,t=kw,n=_w,r=Ew,o={},i=Ws("start","drag","end"),s=0,l,a,u,p,c=0;function d(v){v.on("mousedown.drag",x).filter(r).on("touchstart.drag",k).on("touchmove.drag",m,ww).on("touchend.drag touchcancel.drag",g).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function x(v,_){if(!(p||!e.call(this,v,_))){var S=h(this,t.call(this,v,_),v,_,"mouse");S&&(We(v.view).on("mousemove.drag",y,jo).on("mouseup.drag",w,jo),jg(v.view),Tl(v),u=!1,l=v.clientX,a=v.clientY,S("start",v))}}function y(v){if(ur(v),!u){var _=v.clientX-l,S=v.clientY-a;u=_*_+S*S>c}o.mouse("drag",v)}function w(v){We(v.view).on("mousemove.drag mouseup.drag",null),Mg(v.view,u),ur(v),o.mouse("end",v)}function k(v,_){if(e.call(this,v,_)){var S=v.changedTouches,E=t.call(this,v,_),b=S.length,A,D;for(A=0;A>8&15|t>>4&240,t>>4&15|t&240,(t&15)<<4|t&15,1):n===8?mi(t>>24&255,t>>16&255,t>>8&255,(t&255)/255):n===4?mi(t>>12&15|t>>8&240,t>>8&15|t>>4&240,t>>4&15|t&240,((t&15)<<4|t&15)/255):null):(t=bw.exec(e))?new Oe(t[1],t[2],t[3],1):(t=Nw.exec(e))?new Oe(t[1]*255/100,t[2]*255/100,t[3]*255/100,1):(t=jw.exec(e))?mi(t[1],t[2],t[3],t[4]):(t=Mw.exec(e))?mi(t[1]*255/100,t[2]*255/100,t[3]*255/100,t[4]):(t=zw.exec(e))?Xd(t[1],t[2]/100,t[3]/100,1):(t=Pw.exec(e))?Xd(t[1],t[2]/100,t[3]/100,t[4]):Fd.hasOwnProperty(e)?Wd(Fd[e]):e==="transparent"?new Oe(NaN,NaN,NaN,0):null}function Wd(e){return new Oe(e>>16&255,e>>8&255,e&255,1)}function mi(e,t,n,r){return r<=0&&(e=t=n=NaN),new Oe(e,t,n,r)}function Rw(e){return e instanceof Wo||(e=Tn(e)),e?(e=e.rgb(),new Oe(e.r,e.g,e.b,e.opacity)):new Oe}function Ya(e,t,n,r){return arguments.length===1?Rw(e):new Oe(e,t,n,r??1)}function Oe(e,t,n,r){this.r=+e,this.g=+t,this.b=+n,this.opacity=+r}oc(Oe,Ya,Pg(Wo,{brighter(e){return e=e==null?xs:Math.pow(xs,e),new Oe(this.r*e,this.g*e,this.b*e,this.opacity)},darker(e){return e=e==null?Mo:Math.pow(Mo,e),new Oe(this.r*e,this.g*e,this.b*e,this.opacity)},rgb(){return this},clamp(){return new Oe(Cn(this.r),Cn(this.g),Cn(this.b),vs(this.opacity))},displayable(){return-.5<=this.r&&this.r<255.5&&-.5<=this.g&&this.g<255.5&&-.5<=this.b&&this.b<255.5&&0<=this.opacity&&this.opacity<=1},hex:Ud,formatHex:Ud,formatHex8:Lw,formatRgb:Yd,toString:Yd}));function Ud(){return`#${kn(this.r)}${kn(this.g)}${kn(this.b)}`}function Lw(){return`#${kn(this.r)}${kn(this.g)}${kn(this.b)}${kn((isNaN(this.opacity)?1:this.opacity)*255)}`}function Yd(){const e=vs(this.opacity);return`${e===1?"rgb(":"rgba("}${Cn(this.r)}, ${Cn(this.g)}, ${Cn(this.b)}${e===1?")":`, ${e})`}`}function vs(e){return isNaN(e)?1:Math.max(0,Math.min(1,e))}function Cn(e){return Math.max(0,Math.min(255,Math.round(e)||0))}function kn(e){return e=Cn(e),(e<16?"0":"")+e.toString(16)}function Xd(e,t,n,r){return r<=0?e=t=n=NaN:n<=0||n>=1?e=t=NaN:t<=0&&(e=NaN),new ut(e,t,n,r)}function Tg(e){if(e instanceof ut)return new ut(e.h,e.s,e.l,e.opacity);if(e instanceof Wo||(e=Tn(e)),!e)return new ut;if(e instanceof ut)return e;e=e.rgb();var t=e.r/255,n=e.g/255,r=e.b/255,o=Math.min(t,n,r),i=Math.max(t,n,r),s=NaN,l=i-o,a=(i+o)/2;return l?(t===i?s=(n-r)/l+(n0&&a<1?0:s,new ut(s,l,a,e.opacity)}function Aw(e,t,n,r){return arguments.length===1?Tg(e):new ut(e,t,n,r??1)}function ut(e,t,n,r){this.h=+e,this.s=+t,this.l=+n,this.opacity=+r}oc(ut,Aw,Pg(Wo,{brighter(e){return e=e==null?xs:Math.pow(xs,e),new ut(this.h,this.s,this.l*e,this.opacity)},darker(e){return e=e==null?Mo:Math.pow(Mo,e),new ut(this.h,this.s,this.l*e,this.opacity)},rgb(){var e=this.h%360+(this.h<0)*360,t=isNaN(e)||isNaN(this.s)?0:this.s,n=this.l,r=n+(n<.5?n:1-n)*t,o=2*n-r;return new Oe(Il(e>=240?e-240:e+120,o,r),Il(e,o,r),Il(e<120?e+240:e-120,o,r),this.opacity)},clamp(){return new ut(Qd(this.h),yi(this.s),yi(this.l),vs(this.opacity))},displayable(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1},formatHsl(){const e=vs(this.opacity);return`${e===1?"hsl(":"hsla("}${Qd(this.h)}, ${yi(this.s)*100}%, ${yi(this.l)*100}%${e===1?")":`, ${e})`}`}}));function Qd(e){return e=(e||0)%360,e<0?e+360:e}function yi(e){return Math.max(0,Math.min(1,e||0))}function Il(e,t,n){return(e<60?t+(n-t)*e/60:e<180?n:e<240?t+(n-t)*(240-e)/60:t)*255}const ic=e=>()=>e;function $w(e,t){return function(n){return e+n*t}}function Dw(e,t,n){return e=Math.pow(e,n),t=Math.pow(t,n)-e,n=1/n,function(r){return Math.pow(e+r*t,n)}}function Ow(e){return(e=+e)==1?Ig:function(t,n){return n-t?Dw(t,n,e):ic(isNaN(t)?n:t)}}function Ig(e,t){var n=t-e;return n?$w(e,n):ic(isNaN(e)?t:e)}const ws=function e(t){var n=Ow(t);function r(o,i){var s=n((o=Ya(o)).r,(i=Ya(i)).r),l=n(o.g,i.g),a=n(o.b,i.b),u=Ig(o.opacity,i.opacity);return function(p){return o.r=s(p),o.g=l(p),o.b=a(p),o.opacity=u(p),o+""}}return r.gamma=e,r}(1);function Bw(e,t){t||(t=[]);var n=e?Math.min(t.length,e.length):0,r=t.slice(),o;return function(i){for(o=0;on&&(i=t.slice(n,i),l[s]?l[s]+=i:l[++s]=i),(r=r[0])===(o=o[0])?l[s]?l[s]+=o:l[++s]=o:(l[++s]=null,a.push({i:s,x:St(r,o)})),n=Rl.lastIndex;return n180?p+=360:p-u>180&&(u+=360),d.push({i:c.push(o(c)+"rotate(",null,r)-2,x:St(u,p)})):p&&c.push(o(c)+"rotate("+p+r)}function l(u,p,c,d){u!==p?d.push({i:c.push(o(c)+"skewX(",null,r)-2,x:St(u,p)}):p&&c.push(o(c)+"skewX("+p+r)}function a(u,p,c,d,x,y){if(u!==c||p!==d){var w=x.push(o(x)+"scale(",null,",",null,")");y.push({i:w-4,x:St(u,c)},{i:w-2,x:St(p,d)})}else(c!==1||d!==1)&&x.push(o(x)+"scale("+c+","+d+")")}return function(u,p){var c=[],d=[];return u=e(u),p=e(p),i(u.translateX,u.translateY,p.translateX,p.translateY,c,d),s(u.rotate,p.rotate,c,d),l(u.skewX,p.skewX,c,d),a(u.scaleX,u.scaleY,p.scaleX,p.scaleY,c,d),u=p=null,function(x){for(var y=-1,w=d.length,k;++y=0&&e._call.call(void 0,t),e=e._next;--vr}function Zd(){In=(ks=Po.now())+Ys,vr=Zr=0;try{t2()}finally{vr=0,r2(),In=0}}function n2(){var e=Po.now(),t=e-ks;t>$g&&(Ys-=t,ks=e)}function r2(){for(var e,t=Ss,n,r=1/0;t;)t._call?(r>t._time&&(r=t._time),e=t,t=t._next):(n=t._next,t._next=null,t=e?e._next=n:Ss=n);qr=e,Ga(r)}function Ga(e){if(!vr){Zr&&(Zr=clearTimeout(Zr));var t=e-In;t>24?(e<1/0&&(Zr=setTimeout(Zd,e-Po.now()-Ys)),Fr&&(Fr=clearInterval(Fr))):(Fr||(ks=Po.now(),Fr=setInterval(n2,$g)),vr=1,Dg(Zd))}}function qd(e,t,n){var r=new _s;return t=t==null?0:+t,r.restart(o=>{r.stop(),e(o+t)},t,n),r}var o2=Ws("start","end","cancel","interrupt"),i2=[],Bg=0,Jd=1,Ka=2,Wi=3,ef=4,Za=5,Ui=6;function Xs(e,t,n,r,o,i){var s=e.__transition;if(!s)e.__transition={};else if(n in s)return;s2(e,n,{name:t,index:r,group:o,on:o2,tween:i2,time:i.time,delay:i.delay,duration:i.duration,ease:i.ease,timer:null,state:Bg})}function lc(e,t){var n=gt(e,t);if(n.state>Bg)throw new Error("too late; already scheduled");return n}function Nt(e,t){var n=gt(e,t);if(n.state>Wi)throw new Error("too late; already running");return n}function gt(e,t){var n=e.__transition;if(!n||!(n=n[t]))throw new Error("transition not found");return n}function s2(e,t,n){var r=e.__transition,o;r[t]=n,n.timer=Og(i,0,n.time);function i(u){n.state=Jd,n.timer.restart(s,n.delay,n.time),n.delay<=u&&s(u-n.delay)}function s(u){var p,c,d,x;if(n.state!==Jd)return a();for(p in r)if(x=r[p],x.name===n.name){if(x.state===Wi)return qd(s);x.state===ef?(x.state=Ui,x.timer.stop(),x.on.call("interrupt",e,e.__data__,x.index,x.group),delete r[p]):+pKa&&r.state=0&&(t=t.slice(0,n)),!t||t==="start"})}function A2(e,t,n){var r,o,i=L2(t)?lc:Nt;return function(){var s=i(this,e),l=s.on;l!==r&&(o=(r=l).copy()).on(t,n),s.on=o}}function $2(e,t){var n=this._id;return arguments.length<2?gt(this.node(),n).on.on(e):this.each(A2(n,e,t))}function D2(e){return function(){var t=this.parentNode;for(var n in this.__transition)if(+n!==e)return;t&&t.removeChild(this)}}function O2(){return this.on("end.remove",D2(this._id))}function B2(e){var t=this._name,n=this._id;typeof e!="function"&&(e=nc(e));for(var r=this._groups,o=r.length,i=new Array(o),s=0;s()=>e;function dS(e,{sourceEvent:t,target:n,transform:r,dispatch:o}){Object.defineProperties(this,{type:{value:e,enumerable:!0,configurable:!0},sourceEvent:{value:t,enumerable:!0,configurable:!0},target:{value:n,enumerable:!0,configurable:!0},transform:{value:r,enumerable:!0,configurable:!0},_:{value:o}})}function Rt(e,t,n){this.k=e,this.x=t,this.y=n}Rt.prototype={constructor:Rt,scale:function(e){return e===1?this:new Rt(this.k*e,this.x,this.y)},translate:function(e,t){return e===0&t===0?this:new Rt(this.k,this.x+this.k*e,this.y+this.k*t)},apply:function(e){return[e[0]*this.k+this.x,e[1]*this.k+this.y]},applyX:function(e){return e*this.k+this.x},applyY:function(e){return e*this.k+this.y},invert:function(e){return[(e[0]-this.x)/this.k,(e[1]-this.y)/this.k]},invertX:function(e){return(e-this.x)/this.k},invertY:function(e){return(e-this.y)/this.k},rescaleX:function(e){return e.copy().domain(e.range().map(this.invertX,this).map(e.invert,e))},rescaleY:function(e){return e.copy().domain(e.range().map(this.invertY,this).map(e.invert,e))},toString:function(){return"translate("+this.x+","+this.y+") scale("+this.k+")"}};var Qs=new Rt(1,0,0);Wg.prototype=Rt.prototype;function Wg(e){for(;!e.__zoom;)if(!(e=e.parentNode))return Qs;return e.__zoom}function Ll(e){e.stopImmediatePropagation()}function Hr(e){e.preventDefault(),e.stopImmediatePropagation()}function fS(e){return(!e.ctrlKey||e.type==="wheel")&&!e.button}function pS(){var e=this;return e instanceof SVGElement?(e=e.ownerSVGElement||e,e.hasAttribute("viewBox")?(e=e.viewBox.baseVal,[[e.x,e.y],[e.x+e.width,e.y+e.height]]):[[0,0],[e.width.baseVal.value,e.height.baseVal.value]]):[[0,0],[e.clientWidth,e.clientHeight]]}function tf(){return this.__zoom||Qs}function hS(e){return-e.deltaY*(e.deltaMode===1?.05:e.deltaMode?1:.002)*(e.ctrlKey?10:1)}function gS(){return navigator.maxTouchPoints||"ontouchstart"in this}function mS(e,t,n){var r=e.invertX(t[0][0])-n[0][0],o=e.invertX(t[1][0])-n[1][0],i=e.invertY(t[0][1])-n[0][1],s=e.invertY(t[1][1])-n[1][1];return e.translate(o>r?(r+o)/2:Math.min(0,r)||Math.max(0,o),s>i?(i+s)/2:Math.min(0,i)||Math.max(0,s))}function Ug(){var e=fS,t=pS,n=mS,r=hS,o=gS,i=[0,1/0],s=[[-1/0,-1/0],[1/0,1/0]],l=250,a=Vi,u=Ws("start","zoom","end"),p,c,d,x=500,y=150,w=0,k=10;function m(C){C.property("__zoom",tf).on("wheel.zoom",b,{passive:!1}).on("mousedown.zoom",A).on("dblclick.zoom",D).filter(o).on("touchstart.zoom",T).on("touchmove.zoom",I).on("touchend.zoom touchcancel.zoom",P).style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}m.transform=function(C,L,M,R){var N=C.selection?C.selection():C;N.property("__zoom",tf),C!==N?_(C,L,M,R):N.interrupt().each(function(){S(this,arguments).event(R).start().zoom(null,typeof L=="function"?L.apply(this,arguments):L).end()})},m.scaleBy=function(C,L,M,R){m.scaleTo(C,function(){var N=this.__zoom.k,j=typeof L=="function"?L.apply(this,arguments):L;return N*j},M,R)},m.scaleTo=function(C,L,M,R){m.transform(C,function(){var N=t.apply(this,arguments),j=this.__zoom,$=M==null?v(N):typeof M=="function"?M.apply(this,arguments):M,O=j.invert($),B=typeof L=="function"?L.apply(this,arguments):L;return n(h(g(j,B),$,O),N,s)},M,R)},m.translateBy=function(C,L,M,R){m.transform(C,function(){return n(this.__zoom.translate(typeof L=="function"?L.apply(this,arguments):L,typeof M=="function"?M.apply(this,arguments):M),t.apply(this,arguments),s)},null,R)},m.translateTo=function(C,L,M,R,N){m.transform(C,function(){var j=t.apply(this,arguments),$=this.__zoom,O=R==null?v(j):typeof R=="function"?R.apply(this,arguments):R;return n(Qs.translate(O[0],O[1]).scale($.k).translate(typeof L=="function"?-L.apply(this,arguments):-L,typeof M=="function"?-M.apply(this,arguments):-M),j,s)},R,N)};function g(C,L){return L=Math.max(i[0],Math.min(i[1],L)),L===C.k?C:new Rt(L,C.x,C.y)}function h(C,L,M){var R=L[0]-M[0]*C.k,N=L[1]-M[1]*C.k;return R===C.x&&N===C.y?C:new Rt(C.k,R,N)}function v(C){return[(+C[0][0]+ +C[1][0])/2,(+C[0][1]+ +C[1][1])/2]}function _(C,L,M,R){C.on("start.zoom",function(){S(this,arguments).event(R).start()}).on("interrupt.zoom end.zoom",function(){S(this,arguments).event(R).end()}).tween("zoom",function(){var N=this,j=arguments,$=S(N,j).event(R),O=t.apply(N,j),B=M==null?v(O):typeof M=="function"?M.apply(N,j):M,W=Math.max(O[1][0]-O[0][0],O[1][1]-O[0][1]),V=N.__zoom,Y=typeof L=="function"?L.apply(N,j):L,X=a(V.invert(B).concat(W/V.k),Y.invert(B).concat(W/Y.k));return function(Q){if(Q===1)Q=Y;else{var H=X(Q),K=W/H[2];Q=new Rt(K,B[0]-H[0]*K,B[1]-H[1]*K)}$.zoom(null,Q)}})}function S(C,L,M){return!M&&C.__zooming||new E(C,L)}function E(C,L){this.that=C,this.args=L,this.active=0,this.sourceEvent=null,this.extent=t.apply(C,L),this.taps=0}E.prototype={event:function(C){return C&&(this.sourceEvent=C),this},start:function(){return++this.active===1&&(this.that.__zooming=this,this.emit("start")),this},zoom:function(C,L){return this.mouse&&C!=="mouse"&&(this.mouse[1]=L.invert(this.mouse[0])),this.touch0&&C!=="touch"&&(this.touch0[1]=L.invert(this.touch0[0])),this.touch1&&C!=="touch"&&(this.touch1[1]=L.invert(this.touch1[0])),this.that.__zoom=L,this.emit("zoom"),this},end:function(){return--this.active===0&&(delete this.that.__zooming,this.emit("end")),this},emit:function(C){var L=We(this.that).datum();u.call(C,this.that,new dS(C,{sourceEvent:this.sourceEvent,target:m,transform:this.that.__zoom,dispatch:u}),L)}};function b(C,...L){if(!e.apply(this,arguments))return;var M=S(this,L).event(C),R=this.__zoom,N=Math.max(i[0],Math.min(i[1],R.k*Math.pow(2,r.apply(this,arguments)))),j=lt(C);if(M.wheel)(M.mouse[0][0]!==j[0]||M.mouse[0][1]!==j[1])&&(M.mouse[1]=R.invert(M.mouse[0]=j)),clearTimeout(M.wheel);else{if(R.k===N)return;M.mouse=[j,R.invert(j)],Yi(this),M.start()}Hr(C),M.wheel=setTimeout($,y),M.zoom("mouse",n(h(g(R,N),M.mouse[0],M.mouse[1]),M.extent,s));function $(){M.wheel=null,M.end()}}function A(C,...L){if(d||!e.apply(this,arguments))return;var M=C.currentTarget,R=S(this,L,!0).event(C),N=We(C.view).on("mousemove.zoom",B,!0).on("mouseup.zoom",W,!0),j=lt(C,M),$=C.clientX,O=C.clientY;jg(C.view),Ll(C),R.mouse=[j,this.__zoom.invert(j)],Yi(this),R.start();function B(V){if(Hr(V),!R.moved){var Y=V.clientX-$,X=V.clientY-O;R.moved=Y*Y+X*X>w}R.event(V).zoom("mouse",n(h(R.that.__zoom,R.mouse[0]=lt(V,M),R.mouse[1]),R.extent,s))}function W(V){N.on("mousemove.zoom mouseup.zoom",null),Mg(V.view,R.moved),Hr(V),R.event(V).end()}}function D(C,...L){if(e.apply(this,arguments)){var M=this.__zoom,R=lt(C.changedTouches?C.changedTouches[0]:C,this),N=M.invert(R),j=M.k*(C.shiftKey?.5:2),$=n(h(g(M,j),R,N),t.apply(this,L),s);Hr(C),l>0?We(this).transition().duration(l).call(_,$,R,C):We(this).call(m.transform,$,R,C)}}function T(C,...L){if(e.apply(this,arguments)){var M=C.touches,R=M.length,N=S(this,L,C.changedTouches.length===R).event(C),j,$,O,B;for(Ll(C),$=0;$"[React Flow]: Seems like you have not used zustand provider as an ancestor. Help: https://reactflow.dev/error#001",error002:()=>"It looks like you've created a new nodeTypes or edgeTypes object. If this wasn't on purpose please define the nodeTypes/edgeTypes outside of the component or memoize them.",error003:e=>`Node type "${e}" not found. Using fallback type "default".`,error004:()=>"The React Flow parent container needs a width and a height to render the graph.",error005:()=>"Only child nodes can use a parent extent.",error006:()=>"Can't create edge. An edge needs a source and a target.",error007:e=>`The old edge with id=${e} does not exist.`,error009:e=>`Marker type "${e}" doesn't exist.`,error008:(e,{id:t,sourceHandle:n,targetHandle:r})=>`Couldn't create edge for ${e} handle id: "${e==="source"?n:r}", edge id: ${t}.`,error010:()=>"Handle: No node id found. Make sure to only use a Handle inside a custom Node.",error011:e=>`Edge type "${e}" not found. Using fallback type "default".`,error012:e=>`Node with id "${e}" does not exist, it may have been removed. This can happen when a node is deleted before the "onNodeClick" handler is called.`,error013:(e="react")=>`It seems that you haven't loaded the styles. Please import '@xyflow/${e}/dist/style.css' or base.css to make sure everything is working properly.`,error014:()=>"useNodeConnections: No node ID found. Call useNodeConnections inside a custom Node or provide a node ID.",error015:()=>"It seems that you are trying to drag a node that is not initialized. Please use onNodesChange as explained in the docs."},To=[[Number.NEGATIVE_INFINITY,Number.NEGATIVE_INFINITY],[Number.POSITIVE_INFINITY,Number.POSITIVE_INFINITY]],Yg=["Enter"," ","Escape"],Xg={"node.a11yDescription.default":"Press enter or space to select a node. Press delete to remove it and escape to cancel.","node.a11yDescription.keyboardDisabled":"Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.","node.a11yDescription.ariaLiveMessage":({direction:e,x:t,y:n})=>`Moved selected node ${e}. New position, x: ${t}, y: ${n}`,"edge.a11yDescription.default":"Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.","controls.ariaLabel":"Control Panel","controls.zoomIn.ariaLabel":"Zoom In","controls.zoomOut.ariaLabel":"Zoom Out","controls.fitView.ariaLabel":"Fit View","controls.interactive.ariaLabel":"Toggle Interactivity","minimap.ariaLabel":"Mini Map","handle.ariaLabel":"Handle"};var wr;(function(e){e.Strict="strict",e.Loose="loose"})(wr||(wr={}));var bn;(function(e){e.Free="free",e.Vertical="vertical",e.Horizontal="horizontal"})(bn||(bn={}));var Io;(function(e){e.Partial="partial",e.Full="full"})(Io||(Io={}));const Qg={inProgress:!1,isValid:null,from:null,fromHandle:null,fromPosition:null,fromNode:null,to:null,toHandle:null,toPosition:null,toNode:null,pointer:null};var Zt;(function(e){e.Bezier="default",e.Straight="straight",e.Step="step",e.SmoothStep="smoothstep",e.SimpleBezier="simplebezier"})(Zt||(Zt={}));var Es;(function(e){e.Arrow="arrow",e.ArrowClosed="arrowclosed"})(Es||(Es={}));var q;(function(e){e.Left="left",e.Top="top",e.Right="right",e.Bottom="bottom"})(q||(q={}));const nf={[q.Left]:q.Right,[q.Right]:q.Left,[q.Top]:q.Bottom,[q.Bottom]:q.Top};function Gg(e){return e===null?null:e?"valid":"invalid"}const Kg=e=>"id"in e&&"source"in e&&"target"in e,yS=e=>"id"in e&&"position"in e&&!("source"in e)&&!("target"in e),uc=e=>"id"in e&&"internals"in e&&!("source"in e)&&!("target"in e),Uo=(e,t=[0,0])=>{const{width:n,height:r}=Ht(e),o=e.origin??t,i=n*o[0],s=r*o[1];return{x:e.position.x-i,y:e.position.y-s}},xS=(e,t={nodeOrigin:[0,0]})=>{if(e.length===0)return{x:0,y:0,width:0,height:0};const n=e.reduce((r,o)=>{const i=typeof o=="string";let s=!t.nodeLookup&&!i?o:void 0;t.nodeLookup&&(s=i?t.nodeLookup.get(o):uc(o)?o:t.nodeLookup.get(o.id));const l=s?Cs(s,t.nodeOrigin):{x:0,y:0,x2:0,y2:0};return Gs(r,l)},{x:1/0,y:1/0,x2:-1/0,y2:-1/0});return Ks(n)},Yo=(e,t={})=>{let n={x:1/0,y:1/0,x2:-1/0,y2:-1/0},r=!1;return e.forEach(o=>{(t.filter===void 0||t.filter(o))&&(n=Gs(n,Cs(o)),r=!0)}),r?Ks(n):{x:0,y:0,width:0,height:0}},cc=(e,t,[n,r,o]=[0,0,1],i=!1,s=!1)=>{const l={...Qo(t,[n,r,o]),width:t.width/o,height:t.height/o},a=[];for(const u of e.values()){const{measured:p,selectable:c=!0,hidden:d=!1}=u;if(s&&!c||d)continue;const x=p.width??u.width??u.initialWidth??null,y=p.height??u.height??u.initialHeight??null,w=Ro(l,kr(u)),k=(x??0)*(y??0),m=i&&w>0;(!u.internals.handleBounds||m||w>=k||u.dragging)&&a.push(u)}return a},vS=(e,t)=>{const n=new Set;return e.forEach(r=>{n.add(r.id)}),t.filter(r=>n.has(r.source)||n.has(r.target))};function wS(e,t){const n=new Map,r=t!=null&&t.nodes?new Set(t.nodes.map(o=>o.id)):null;return e.forEach(o=>{o.measured.width&&o.measured.height&&((t==null?void 0:t.includeHiddenNodes)||!o.hidden)&&(!r||r.has(o.id))&&n.set(o.id,o)}),n}async function SS({nodes:e,width:t,height:n,panZoom:r,minZoom:o,maxZoom:i},s){if(e.size===0)return Promise.resolve(!0);const l=wS(e,s),a=Yo(l),u=dc(a,t,n,(s==null?void 0:s.minZoom)??o,(s==null?void 0:s.maxZoom)??i,(s==null?void 0:s.padding)??.1);return await r.setViewport(u,{duration:s==null?void 0:s.duration,ease:s==null?void 0:s.ease,interpolate:s==null?void 0:s.interpolate}),Promise.resolve(!0)}function Zg({nodeId:e,nextPosition:t,nodeLookup:n,nodeOrigin:r=[0,0],nodeExtent:o,onError:i}){const s=n.get(e),l=s.parentId?n.get(s.parentId):void 0,{x:a,y:u}=l?l.internals.positionAbsolute:{x:0,y:0},p=s.origin??r;let c=s.extent||o;if(s.extent==="parent"&&!s.expandParent)if(!l)i==null||i("005",bt.error005());else{const x=l.measured.width,y=l.measured.height;x&&y&&(c=[[a,u],[a+x,u+y]])}else l&&_r(s.extent)&&(c=[[s.extent[0][0]+a,s.extent[0][1]+u],[s.extent[1][0]+a,s.extent[1][1]+u]]);const d=_r(c)?Rn(t,c,s.measured):t;return(s.measured.width===void 0||s.measured.height===void 0)&&(i==null||i("015",bt.error015())),{position:{x:d.x-a+(s.measured.width??0)*p[0],y:d.y-u+(s.measured.height??0)*p[1]},positionAbsolute:d}}async function kS({nodesToRemove:e=[],edgesToRemove:t=[],nodes:n,edges:r,onBeforeDelete:o}){const i=new Set(e.map(d=>d.id)),s=[];for(const d of n){if(d.deletable===!1)continue;const x=i.has(d.id),y=!x&&d.parentId&&s.find(w=>w.id===d.parentId);(x||y)&&s.push(d)}const l=new Set(t.map(d=>d.id)),a=r.filter(d=>d.deletable!==!1),p=vS(s,a);for(const d of a)l.has(d.id)&&!p.find(y=>y.id===d.id)&&p.push(d);if(!o)return{edges:p,nodes:s};const c=await o({nodes:s,edges:p});return typeof c=="boolean"?c?{edges:p,nodes:s}:{edges:[],nodes:[]}:c}const Sr=(e,t=0,n=1)=>Math.min(Math.max(e,t),n),Rn=(e={x:0,y:0},t,n)=>({x:Sr(e.x,t[0][0],t[1][0]-((n==null?void 0:n.width)??0)),y:Sr(e.y,t[0][1],t[1][1]-((n==null?void 0:n.height)??0))});function qg(e,t,n){const{width:r,height:o}=Ht(n),{x:i,y:s}=n.internals.positionAbsolute;return Rn(e,[[i,s],[i+r,s+o]],t)}const rf=(e,t,n)=>en?-Sr(Math.abs(e-n),1,t)/t:0,Jg=(e,t,n=15,r=40)=>{const o=rf(e.x,r,t.width-r)*n,i=rf(e.y,r,t.height-r)*n;return[o,i]},Gs=(e,t)=>({x:Math.min(e.x,t.x),y:Math.min(e.y,t.y),x2:Math.max(e.x2,t.x2),y2:Math.max(e.y2,t.y2)}),qa=({x:e,y:t,width:n,height:r})=>({x:e,y:t,x2:e+n,y2:t+r}),Ks=({x:e,y:t,x2:n,y2:r})=>({x:e,y:t,width:n-e,height:r-t}),kr=(e,t=[0,0])=>{var o,i;const{x:n,y:r}=uc(e)?e.internals.positionAbsolute:Uo(e,t);return{x:n,y:r,width:((o=e.measured)==null?void 0:o.width)??e.width??e.initialWidth??0,height:((i=e.measured)==null?void 0:i.height)??e.height??e.initialHeight??0}},Cs=(e,t=[0,0])=>{var o,i;const{x:n,y:r}=uc(e)?e.internals.positionAbsolute:Uo(e,t);return{x:n,y:r,x2:n+(((o=e.measured)==null?void 0:o.width)??e.width??e.initialWidth??0),y2:r+(((i=e.measured)==null?void 0:i.height)??e.height??e.initialHeight??0)}},e0=(e,t)=>Ks(Gs(qa(e),qa(t))),Ro=(e,t)=>{const n=Math.max(0,Math.min(e.x+e.width,t.x+t.width)-Math.max(e.x,t.x)),r=Math.max(0,Math.min(e.y+e.height,t.y+t.height)-Math.max(e.y,t.y));return Math.ceil(n*r)},of=e=>ct(e.width)&&ct(e.height)&&ct(e.x)&&ct(e.y),ct=e=>!isNaN(e)&&isFinite(e),_S=(e,t)=>{},Xo=(e,t=[1,1])=>({x:t[0]*Math.round(e.x/t[0]),y:t[1]*Math.round(e.y/t[1])}),Qo=({x:e,y:t},[n,r,o],i=!1,s=[1,1])=>{const l={x:(e-n)/o,y:(t-r)/o};return i?Xo(l,s):l},bs=({x:e,y:t},[n,r,o])=>({x:e*o+n,y:t*o+r});function Fn(e,t){if(typeof e=="number")return Math.floor((t-t/(1+e))*.5);if(typeof e=="string"&&e.endsWith("px")){const n=parseFloat(e);if(!Number.isNaN(n))return Math.floor(n)}if(typeof e=="string"&&e.endsWith("%")){const n=parseFloat(e);if(!Number.isNaN(n))return Math.floor(t*n*.01)}return console.error(`[React Flow] The padding value "${e}" is invalid. Please provide a number or a string with a valid unit (px or %).`),0}function ES(e,t,n){if(typeof e=="string"||typeof e=="number"){const r=Fn(e,n),o=Fn(e,t);return{top:r,right:o,bottom:r,left:o,x:o*2,y:r*2}}if(typeof e=="object"){const r=Fn(e.top??e.y??0,n),o=Fn(e.bottom??e.y??0,n),i=Fn(e.left??e.x??0,t),s=Fn(e.right??e.x??0,t);return{top:r,right:s,bottom:o,left:i,x:i+s,y:r+o}}return{top:0,right:0,bottom:0,left:0,x:0,y:0}}function CS(e,t,n,r,o,i){const{x:s,y:l}=bs(e,[t,n,r]),{x:a,y:u}=bs({x:e.x+e.width,y:e.y+e.height},[t,n,r]),p=o-a,c=i-u;return{left:Math.floor(s),top:Math.floor(l),right:Math.floor(p),bottom:Math.floor(c)}}const dc=(e,t,n,r,o,i)=>{const s=ES(i,t,n),l=(t-s.x)/e.width,a=(n-s.y)/e.height,u=Math.min(l,a),p=Sr(u,r,o),c=e.x+e.width/2,d=e.y+e.height/2,x=t/2-c*p,y=n/2-d*p,w=CS(e,x,y,p,t,n),k={left:Math.min(w.left-s.left,0),top:Math.min(w.top-s.top,0),right:Math.min(w.right-s.right,0),bottom:Math.min(w.bottom-s.bottom,0)};return{x:x-k.left+k.right,y:y-k.top+k.bottom,zoom:p}},Lo=()=>{var e;return typeof navigator<"u"&&((e=navigator==null?void 0:navigator.userAgent)==null?void 0:e.indexOf("Mac"))>=0};function _r(e){return e!=null&&e!=="parent"}function Ht(e){var t,n;return{width:((t=e.measured)==null?void 0:t.width)??e.width??e.initialWidth??0,height:((n=e.measured)==null?void 0:n.height)??e.height??e.initialHeight??0}}function t0(e){var t,n;return(((t=e.measured)==null?void 0:t.width)??e.width??e.initialWidth)!==void 0&&(((n=e.measured)==null?void 0:n.height)??e.height??e.initialHeight)!==void 0}function n0(e,t={width:0,height:0},n,r,o){const i={...e},s=r.get(n);if(s){const l=s.origin||o;i.x+=s.internals.positionAbsolute.x-(t.width??0)*l[0],i.y+=s.internals.positionAbsolute.y-(t.height??0)*l[1]}return i}function sf(e,t){if(e.size!==t.size)return!1;for(const n of e)if(!t.has(n))return!1;return!0}function bS(){let e,t;return{promise:new Promise((r,o)=>{e=r,t=o}),resolve:e,reject:t}}function NS(e){return{...Xg,...e||{}}}function uo(e,{snapGrid:t=[0,0],snapToGrid:n=!1,transform:r,containerBounds:o}){const{x:i,y:s}=dt(e),l=Qo({x:i-((o==null?void 0:o.left)??0),y:s-((o==null?void 0:o.top)??0)},r),{x:a,y:u}=n?Xo(l,t):l;return{xSnapped:a,ySnapped:u,...l}}const fc=e=>({width:e.offsetWidth,height:e.offsetHeight}),r0=e=>{var t;return((t=e==null?void 0:e.getRootNode)==null?void 0:t.call(e))||(window==null?void 0:window.document)},jS=["INPUT","SELECT","TEXTAREA"];function o0(e){var r,o;const t=((o=(r=e.composedPath)==null?void 0:r.call(e))==null?void 0:o[0])||e.target;return(t==null?void 0:t.nodeType)!==1?!1:jS.includes(t.nodeName)||t.hasAttribute("contenteditable")||!!t.closest(".nokey")}const i0=e=>"clientX"in e,dt=(e,t)=>{var i,s;const n=i0(e),r=n?e.clientX:(i=e.touches)==null?void 0:i[0].clientX,o=n?e.clientY:(s=e.touches)==null?void 0:s[0].clientY;return{x:r-((t==null?void 0:t.left)??0),y:o-((t==null?void 0:t.top)??0)}},lf=(e,t,n,r,o)=>{const i=t.querySelectorAll(`.${e}`);return!i||!i.length?null:Array.from(i).map(s=>{const l=s.getBoundingClientRect();return{id:s.getAttribute("data-handleid"),type:e,nodeId:o,position:s.getAttribute("data-handlepos"),x:(l.left-n.left)/r,y:(l.top-n.top)/r,...fc(s)}})};function s0({sourceX:e,sourceY:t,targetX:n,targetY:r,sourceControlX:o,sourceControlY:i,targetControlX:s,targetControlY:l}){const a=e*.125+o*.375+s*.375+n*.125,u=t*.125+i*.375+l*.375+r*.125,p=Math.abs(a-e),c=Math.abs(u-t);return[a,u,p,c]}function wi(e,t){return e>=0?.5*e:t*25*Math.sqrt(-e)}function af({pos:e,x1:t,y1:n,x2:r,y2:o,c:i}){switch(e){case q.Left:return[t-wi(t-r,i),n];case q.Right:return[t+wi(r-t,i),n];case q.Top:return[t,n-wi(n-o,i)];case q.Bottom:return[t,n+wi(o-n,i)]}}function l0({sourceX:e,sourceY:t,sourcePosition:n=q.Bottom,targetX:r,targetY:o,targetPosition:i=q.Top,curvature:s=.25}){const[l,a]=af({pos:n,x1:e,y1:t,x2:r,y2:o,c:s}),[u,p]=af({pos:i,x1:r,y1:o,x2:e,y2:t,c:s}),[c,d,x,y]=s0({sourceX:e,sourceY:t,targetX:r,targetY:o,sourceControlX:l,sourceControlY:a,targetControlX:u,targetControlY:p});return[`M${e},${t} C${l},${a} ${u},${p} ${r},${o}`,c,d,x,y]}function a0({sourceX:e,sourceY:t,targetX:n,targetY:r}){const o=Math.abs(n-e)/2,i=n0}const PS=({source:e,sourceHandle:t,target:n,targetHandle:r})=>`xy-edge__${e}${t||""}-${n}${r||""}`,TS=(e,t)=>t.some(n=>n.source===e.source&&n.target===e.target&&(n.sourceHandle===e.sourceHandle||!n.sourceHandle&&!e.sourceHandle)&&(n.targetHandle===e.targetHandle||!n.targetHandle&&!e.targetHandle)),IS=(e,t,n={})=>{if(!e.source||!e.target)return t;const r=n.getEdgeId||PS;let o;return Kg(e)?o={...e}:o={...e,id:r(e)},TS(o,t)?t:(o.sourceHandle===null&&delete o.sourceHandle,o.targetHandle===null&&delete o.targetHandle,t.concat(o))};function u0({sourceX:e,sourceY:t,targetX:n,targetY:r}){const[o,i,s,l]=a0({sourceX:e,sourceY:t,targetX:n,targetY:r});return[`M ${e},${t}L ${n},${r}`,o,i,s,l]}const uf={[q.Left]:{x:-1,y:0},[q.Right]:{x:1,y:0},[q.Top]:{x:0,y:-1},[q.Bottom]:{x:0,y:1}},RS=({source:e,sourcePosition:t=q.Bottom,target:n})=>t===q.Left||t===q.Right?e.xMath.sqrt(Math.pow(t.x-e.x,2)+Math.pow(t.y-e.y,2));function LS({source:e,sourcePosition:t=q.Bottom,target:n,targetPosition:r=q.Top,center:o,offset:i,stepPosition:s}){const l=uf[t],a=uf[r],u={x:e.x+l.x*i,y:e.y+l.y*i},p={x:n.x+a.x*i,y:n.y+a.y*i},c=RS({source:u,sourcePosition:t,target:p}),d=c.x!==0?"x":"y",x=c[d];let y=[],w,k;const m={x:0,y:0},g={x:0,y:0},[,,h,v]=a0({sourceX:e.x,sourceY:e.y,targetX:n.x,targetY:n.y});if(l[d]*a[d]===-1){d==="x"?(w=o.x??u.x+(p.x-u.x)*s,k=o.y??(u.y+p.y)/2):(w=o.x??(u.x+p.x)/2,k=o.y??u.y+(p.y-u.y)*s);const S=[{x:w,y:u.y},{x:w,y:p.y}],E=[{x:u.x,y:k},{x:p.x,y:k}];l[d]===x?y=d==="x"?S:E:y=d==="x"?E:S}else{const S=[{x:u.x,y:p.y}],E=[{x:p.x,y:u.y}];if(d==="x"?y=l.x===x?E:S:y=l.y===x?S:E,t===r){const I=Math.abs(e[d]-n[d]);if(I<=i){const P=Math.min(i-1,i-I);l[d]===x?m[d]=(u[d]>e[d]?-1:1)*P:g[d]=(p[d]>n[d]?-1:1)*P}}if(t!==r){const I=d==="x"?"y":"x",P=l[d]===a[I],C=u[I]>p[I],L=u[I]=T?(w=(b.x+A.x)/2,k=y[0].y):(w=y[0].x,k=(b.y+A.y)/2)}return[[e,{x:u.x+m.x,y:u.y+m.y},...y,{x:p.x+g.x,y:p.y+g.y},n],w,k,h,v]}function AS(e,t,n,r){const o=Math.min(cf(e,t)/2,cf(t,n)/2,r),{x:i,y:s}=t;if(e.x===i&&i===n.x||e.y===s&&s===n.y)return`L${i} ${s}`;if(e.y===s){const u=e.x{let v="";return h>0&&hn.id===t):e[0])||null}function eu(e,t){return e?typeof e=="string"?e:`${t?`${t}__`:""}${Object.keys(e).sort().map(r=>`${r}=${e[r]}`).join("&")}`:""}function DS(e,{id:t,defaultColor:n,defaultMarkerStart:r,defaultMarkerEnd:o}){const i=new Set;return e.reduce((s,l)=>([l.markerStart||r,l.markerEnd||o].forEach(a=>{if(a&&typeof a=="object"){const u=eu(a,t);i.has(u)||(s.push({id:u,color:a.color||n,...a}),i.add(u))}}),s),[]).sort((s,l)=>s.id.localeCompare(l.id))}const c0=1e3,OS=10,pc={nodeOrigin:[0,0],nodeExtent:To,elevateNodesOnSelect:!0,zIndexMode:"basic",defaults:{}},BS={...pc,checkEquality:!0};function hc(e,t){const n={...e};for(const r in t)t[r]!==void 0&&(n[r]=t[r]);return n}function FS(e,t,n){const r=hc(pc,n);for(const o of e.values())if(o.parentId)mc(o,e,t,r);else{const i=Uo(o,r.nodeOrigin),s=_r(o.extent)?o.extent:r.nodeExtent,l=Rn(i,s,Ht(o));o.internals.positionAbsolute=l}}function HS(e,t){if(!e.handles)return e.measured?t==null?void 0:t.internals.handleBounds:void 0;const n=[],r=[];for(const o of e.handles){const i={id:o.id,width:o.width??1,height:o.height??1,nodeId:e.id,x:o.x,y:o.y,position:o.position,type:o.type};o.type==="source"?n.push(i):o.type==="target"&&r.push(i)}return{source:n,target:r}}function gc(e){return e==="manual"}function tu(e,t,n,r={}){var u,p;const o=hc(BS,r),i={i:0},s=new Map(t),l=o!=null&&o.elevateNodesOnSelect&&!gc(o.zIndexMode)?c0:0;let a=e.length>0;t.clear(),n.clear();for(const c of e){let d=s.get(c.id);if(o.checkEquality&&c===(d==null?void 0:d.internals.userNode))t.set(c.id,d);else{const x=Uo(c,o.nodeOrigin),y=_r(c.extent)?c.extent:o.nodeExtent,w=Rn(x,y,Ht(c));d={...o.defaults,...c,measured:{width:(u=c.measured)==null?void 0:u.width,height:(p=c.measured)==null?void 0:p.height},internals:{positionAbsolute:w,handleBounds:HS(c,d),z:d0(c,l,o.zIndexMode),userNode:c}},t.set(c.id,d)}(d.measured===void 0||d.measured.width===void 0||d.measured.height===void 0)&&!d.hidden&&(a=!1),c.parentId&&mc(d,t,n,r,i)}return a}function VS(e,t){if(!e.parentId)return;const n=t.get(e.parentId);n?n.set(e.id,e):t.set(e.parentId,new Map([[e.id,e]]))}function mc(e,t,n,r,o){const{elevateNodesOnSelect:i,nodeOrigin:s,nodeExtent:l,zIndexMode:a}=hc(pc,r),u=e.parentId,p=t.get(u);if(!p){console.warn(`Parent node ${u} not found. Please make sure that parent nodes are in front of their child nodes in the nodes array.`);return}VS(e,n),o&&!p.parentId&&p.internals.rootParentIndex===void 0&&a==="auto"&&(p.internals.rootParentIndex=++o.i,p.internals.z=p.internals.z+o.i*OS),o&&p.internals.rootParentIndex!==void 0&&(o.i=p.internals.rootParentIndex);const c=i&&!gc(a)?c0:0,{x:d,y:x,z:y}=WS(e,p,s,l,c,a),{positionAbsolute:w}=e.internals,k=d!==w.x||x!==w.y;(k||y!==e.internals.z)&&t.set(e.id,{...e,internals:{...e.internals,positionAbsolute:k?{x:d,y:x}:w,z:y}})}function d0(e,t,n){const r=ct(e.zIndex)?e.zIndex:0;return gc(n)?r:r+(e.selected?t:0)}function WS(e,t,n,r,o,i){const{x:s,y:l}=t.internals.positionAbsolute,a=Ht(e),u=Uo(e,n),p=_r(e.extent)?Rn(u,e.extent,a):u;let c=Rn({x:s+p.x,y:l+p.y},r,a);e.extent==="parent"&&(c=qg(c,a,t));const d=d0(e,o,i),x=t.internals.z??0;return{x:c.x,y:c.y,z:x>=d?x+1:d}}function yc(e,t,n,r=[0,0]){var s;const o=[],i=new Map;for(const l of e){const a=t.get(l.parentId);if(!a)continue;const u=((s=i.get(l.parentId))==null?void 0:s.expandedRect)??kr(a),p=e0(u,l.rect);i.set(l.parentId,{expandedRect:p,parent:a})}return i.size>0&&i.forEach(({expandedRect:l,parent:a},u)=>{var h;const p=a.internals.positionAbsolute,c=Ht(a),d=a.origin??r,x=l.x0||y>0||m||g)&&(o.push({id:u,type:"position",position:{x:a.position.x-x+m,y:a.position.y-y+g}}),(h=n.get(u))==null||h.forEach(v=>{e.some(_=>_.id===v.id)||o.push({id:v.id,type:"position",position:{x:v.position.x+x,y:v.position.y+y}})})),(c.width0){const x=yc(d,t,n,o);u.push(...x)}return{changes:u,updatedInternals:a}}async function YS({delta:e,panZoom:t,transform:n,translateExtent:r,width:o,height:i}){if(!t||!e.x&&!e.y)return Promise.resolve(!1);const s=await t.setViewportConstrained({x:n[0]+e.x,y:n[1]+e.y,zoom:n[2]},[[0,0],[o,i]],r),l=!!s&&(s.x!==n[0]||s.y!==n[1]||s.k!==n[2]);return Promise.resolve(l)}function hf(e,t,n,r,o,i){let s=o;const l=r.get(s)||new Map;r.set(s,l.set(n,t)),s=`${o}-${e}`;const a=r.get(s)||new Map;if(r.set(s,a.set(n,t)),i){s=`${o}-${e}-${i}`;const u=r.get(s)||new Map;r.set(s,u.set(n,t))}}function f0(e,t,n){e.clear(),t.clear();for(const r of n){const{source:o,target:i,sourceHandle:s=null,targetHandle:l=null}=r,a={edgeId:r.id,source:o,target:i,sourceHandle:s,targetHandle:l},u=`${o}-${s}--${i}-${l}`,p=`${i}-${l}--${o}-${s}`;hf("source",a,p,e,o,s),hf("target",a,u,e,i,l),t.set(r.id,r)}}function p0(e,t){if(!e.parentId)return!1;const n=t.get(e.parentId);return n?n.selected?!0:p0(n,t):!1}function gf(e,t,n){var o;let r=e;do{if((o=r==null?void 0:r.matches)!=null&&o.call(r,t))return!0;if(r===n)return!1;r=r==null?void 0:r.parentElement}while(r);return!1}function XS(e,t,n,r){const o=new Map;for(const[i,s]of e)if((s.selected||s.id===r)&&(!s.parentId||!p0(s,e))&&(s.draggable||t&&typeof s.draggable>"u")){const l=e.get(i);l&&o.set(i,{id:i,position:l.position||{x:0,y:0},distance:{x:n.x-l.internals.positionAbsolute.x,y:n.y-l.internals.positionAbsolute.y},extent:l.extent,parentId:l.parentId,origin:l.origin,expandParent:l.expandParent,internals:{positionAbsolute:l.internals.positionAbsolute||{x:0,y:0}},measured:{width:l.measured.width??0,height:l.measured.height??0}})}return o}function Al({nodeId:e,dragItems:t,nodeLookup:n,dragging:r=!0}){var s,l,a;const o=[];for(const[u,p]of t){const c=(s=n.get(u))==null?void 0:s.internals.userNode;c&&o.push({...c,position:p.position,dragging:r})}if(!e)return[o[0],o];const i=(l=n.get(e))==null?void 0:l.internals.userNode;return[i?{...i,position:((a=t.get(e))==null?void 0:a.position)||i.position,dragging:r}:o[0],o]}function QS({dragItems:e,snapGrid:t,x:n,y:r}){const o=e.values().next().value;if(!o)return null;const i={x:n-o.distance.x,y:r-o.distance.y},s=Xo(i,t);return{x:s.x-i.x,y:s.y-i.y}}function GS({onNodeMouseDown:e,getStoreItems:t,onDragStart:n,onDrag:r,onDragStop:o}){let i={x:null,y:null},s=0,l=new Map,a=!1,u={x:0,y:0},p=null,c=!1,d=null,x=!1,y=!1,w=null;function k({noDragClassName:g,handleSelector:h,domNode:v,isSelectable:_,nodeId:S,nodeClickDistance:E=0}){d=We(v);function b({x:I,y:P}){const{nodeLookup:C,nodeExtent:L,snapGrid:M,snapToGrid:R,nodeOrigin:N,onNodeDrag:j,onSelectionDrag:$,onError:O,updateNodePositions:B}=t();i={x:I,y:P};let W=!1;const V=l.size>1,Y=V&&L?qa(Yo(l)):null,X=V&&R?QS({dragItems:l,snapGrid:M,x:I,y:P}):null;for(const[Q,H]of l){if(!C.has(Q))continue;let K={x:I-H.distance.x,y:P-H.distance.y};R&&(K=X?{x:Math.round(K.x+X.x),y:Math.round(K.y+X.y)}:Xo(K,M));let ee=null;if(V&&L&&!H.extent&&Y){const{positionAbsolute:Z}=H.internals,re=Z.x-Y.x+L[0][0],le=Z.x+H.measured.width-Y.x2+L[1][0],ie=Z.y-Y.y+L[0][1],je=Z.y+H.measured.height-Y.y2+L[1][1];ee=[[re,ie],[le,je]]}const{position:G,positionAbsolute:J}=Zg({nodeId:Q,nextPosition:K,nodeLookup:C,nodeExtent:ee||L,nodeOrigin:N,onError:O});W=W||H.position.x!==G.x||H.position.y!==G.y,H.position=G,H.internals.positionAbsolute=J}if(y=y||W,!!W&&(B(l,!0),w&&(r||j||!S&&$))){const[Q,H]=Al({nodeId:S,dragItems:l,nodeLookup:C});r==null||r(w,l,Q,H),j==null||j(w,Q,H),S||$==null||$(w,H)}}async function A(){if(!p)return;const{transform:I,panBy:P,autoPanSpeed:C,autoPanOnNodeDrag:L}=t();if(!L){a=!1,cancelAnimationFrame(s);return}const[M,R]=Jg(u,p,C);(M!==0||R!==0)&&(i.x=(i.x??0)-M/I[2],i.y=(i.y??0)-R/I[2],await P({x:M,y:R})&&b(i)),s=requestAnimationFrame(A)}function D(I){var V;const{nodeLookup:P,multiSelectionActive:C,nodesDraggable:L,transform:M,snapGrid:R,snapToGrid:N,selectNodesOnDrag:j,onNodeDragStart:$,onSelectionDragStart:O,unselectNodesAndEdges:B}=t();c=!0,(!j||!_)&&!C&&S&&((V=P.get(S))!=null&&V.selected||B()),_&&j&&S&&(e==null||e(S));const W=uo(I.sourceEvent,{transform:M,snapGrid:R,snapToGrid:N,containerBounds:p});if(i=W,l=XS(P,L,W,S),l.size>0&&(n||$||!S&&O)){const[Y,X]=Al({nodeId:S,dragItems:l,nodeLookup:P});n==null||n(I.sourceEvent,l,Y,X),$==null||$(I.sourceEvent,Y,X),S||O==null||O(I.sourceEvent,X)}}const T=zg().clickDistance(E).on("start",I=>{const{domNode:P,nodeDragThreshold:C,transform:L,snapGrid:M,snapToGrid:R}=t();p=(P==null?void 0:P.getBoundingClientRect())||null,x=!1,y=!1,w=I.sourceEvent,C===0&&D(I),i=uo(I.sourceEvent,{transform:L,snapGrid:M,snapToGrid:R,containerBounds:p}),u=dt(I.sourceEvent,p)}).on("drag",I=>{const{autoPanOnNodeDrag:P,transform:C,snapGrid:L,snapToGrid:M,nodeDragThreshold:R,nodeLookup:N}=t(),j=uo(I.sourceEvent,{transform:C,snapGrid:L,snapToGrid:M,containerBounds:p});if(w=I.sourceEvent,(I.sourceEvent.type==="touchmove"&&I.sourceEvent.touches.length>1||S&&!N.has(S))&&(x=!0),!x){if(!a&&P&&c&&(a=!0,A()),!c){const $=dt(I.sourceEvent,p),O=$.x-u.x,B=$.y-u.y;Math.sqrt(O*O+B*B)>R&&D(I)}(i.x!==j.xSnapped||i.y!==j.ySnapped)&&l&&c&&(u=dt(I.sourceEvent,p),b(j))}}).on("end",I=>{if(!(!c||x)&&(a=!1,c=!1,cancelAnimationFrame(s),l.size>0)){const{nodeLookup:P,updateNodePositions:C,onNodeDragStop:L,onSelectionDragStop:M}=t();if(y&&(C(l,!1),y=!1),o||L||!S&&M){const[R,N]=Al({nodeId:S,dragItems:l,nodeLookup:P,dragging:!1});o==null||o(I.sourceEvent,l,R,N),L==null||L(I.sourceEvent,R,N),S||M==null||M(I.sourceEvent,N)}}}).filter(I=>{const P=I.target;return!I.button&&(!g||!gf(P,`.${g}`,v))&&(!h||gf(P,h,v))});d.call(T)}function m(){d==null||d.on(".drag",null)}return{update:k,destroy:m}}function KS(e,t,n){const r=[],o={x:e.x-n,y:e.y-n,width:n*2,height:n*2};for(const i of t.values())Ro(o,kr(i))>0&&r.push(i);return r}const ZS=250;function qS(e,t,n,r){var l,a;let o=[],i=1/0;const s=KS(e,n,t+ZS);for(const u of s){const p=[...((l=u.internals.handleBounds)==null?void 0:l.source)??[],...((a=u.internals.handleBounds)==null?void 0:a.target)??[]];for(const c of p){if(r.nodeId===c.nodeId&&r.type===c.type&&r.id===c.id)continue;const{x:d,y:x}=Ln(u,c,c.position,!0),y=Math.sqrt(Math.pow(d-e.x,2)+Math.pow(x-e.y,2));y>t||(y1){const u=r.type==="source"?"target":"source";return o.find(p=>p.type===u)??o[0]}return o[0]}function h0(e,t,n,r,o,i=!1){var u,p,c;const s=r.get(e);if(!s)return null;const l=o==="strict"?(u=s.internals.handleBounds)==null?void 0:u[t]:[...((p=s.internals.handleBounds)==null?void 0:p.source)??[],...((c=s.internals.handleBounds)==null?void 0:c.target)??[]],a=(n?l==null?void 0:l.find(d=>d.id===n):l==null?void 0:l[0])??null;return a&&i?{...a,...Ln(s,a,a.position,!0)}:a}function g0(e,t){return e||(t!=null&&t.classList.contains("target")?"target":t!=null&&t.classList.contains("source")?"source":null)}function JS(e,t){let n=null;return t?n=!0:e&&!t&&(n=!1),n}const m0=()=>!0;function ek(e,{connectionMode:t,connectionRadius:n,handleId:r,nodeId:o,edgeUpdaterType:i,isTarget:s,domNode:l,nodeLookup:a,lib:u,autoPanOnConnect:p,flowId:c,panBy:d,cancelConnection:x,onConnectStart:y,onConnect:w,onConnectEnd:k,isValidConnection:m=m0,onReconnectEnd:g,updateConnection:h,getTransform:v,getFromHandle:_,autoPanSpeed:S,dragThreshold:E=1,handleDomNode:b}){const A=r0(e.target);let D=0,T;const{x:I,y:P}=dt(e),C=g0(i,b),L=l==null?void 0:l.getBoundingClientRect();let M=!1;if(!L||!C)return;const R=h0(o,C,r,a,t);if(!R)return;let N=dt(e,L),j=!1,$=null,O=!1,B=null;function W(){if(!p||!L)return;const[G,J]=Jg(N,L,S);d({x:G,y:J}),D=requestAnimationFrame(W)}const V={...R,nodeId:o,type:C,position:R.position},Y=a.get(o);let Q={inProgress:!0,isValid:null,from:Ln(Y,V,q.Left,!0),fromHandle:V,fromPosition:V.position,fromNode:Y,to:N,toHandle:null,toPosition:nf[V.position],toNode:null,pointer:N};function H(){M=!0,h(Q),y==null||y(e,{nodeId:o,handleId:r,handleType:C})}E===0&&H();function K(G){if(!M){const{x:je,y:Vt}=dt(G),jt=je-I,gn=Vt-P;if(!(jt*jt+gn*gn>E*E))return;H()}if(!_()||!V){ee(G);return}const J=v();N=dt(G,L),T=qS(Qo(N,J,!1,[1,1]),n,a,V),j||(W(),j=!0);const Z=y0(G,{handle:T,connectionMode:t,fromNodeId:o,fromHandleId:r,fromType:s?"target":"source",isValidConnection:m,doc:A,lib:u,flowId:c,nodeLookup:a});B=Z.handleDomNode,$=Z.connection,O=JS(!!T,Z.isValid);const re=a.get(o),le=re?Ln(re,V,q.Left,!0):Q.from,ie={...Q,from:le,isValid:O,to:Z.toHandle&&O?bs({x:Z.toHandle.x,y:Z.toHandle.y},J):N,toHandle:Z.toHandle,toPosition:O&&Z.toHandle?Z.toHandle.position:nf[V.position],toNode:Z.toHandle?a.get(Z.toHandle.nodeId):null,pointer:N};h(ie),Q=ie}function ee(G){if(!("touches"in G&&G.touches.length>0)){if(M){(T||B)&&$&&O&&(w==null||w($));const{inProgress:J,...Z}=Q,re={...Z,toPosition:Q.toHandle?Q.toPosition:null};k==null||k(G,re),i&&(g==null||g(G,re))}x(),cancelAnimationFrame(D),j=!1,O=!1,$=null,B=null,A.removeEventListener("mousemove",K),A.removeEventListener("mouseup",ee),A.removeEventListener("touchmove",K),A.removeEventListener("touchend",ee)}}A.addEventListener("mousemove",K),A.addEventListener("mouseup",ee),A.addEventListener("touchmove",K),A.addEventListener("touchend",ee)}function y0(e,{handle:t,connectionMode:n,fromNodeId:r,fromHandleId:o,fromType:i,doc:s,lib:l,flowId:a,isValidConnection:u=m0,nodeLookup:p}){const c=i==="target",d=t?s.querySelector(`.${l}-flow__handle[data-id="${a}-${t==null?void 0:t.nodeId}-${t==null?void 0:t.id}-${t==null?void 0:t.type}"]`):null,{x,y}=dt(e),w=s.elementFromPoint(x,y),k=w!=null&&w.classList.contains(`${l}-flow__handle`)?w:d,m={handleDomNode:k,isValid:!1,connection:null,toHandle:null};if(k){const g=g0(void 0,k),h=k.getAttribute("data-nodeid"),v=k.getAttribute("data-handleid"),_=k.classList.contains("connectable"),S=k.classList.contains("connectableend");if(!h||!g)return m;const E={source:c?h:r,sourceHandle:c?v:o,target:c?r:h,targetHandle:c?o:v};m.connection=E;const A=_&&S&&(n===wr.Strict?c&&g==="source"||!c&&g==="target":h!==r||v!==o);m.isValid=A&&u(E),m.toHandle=h0(h,g,v,p,n,!0)}return m}const nu={onPointerDown:ek,isValid:y0};function tk({domNode:e,panZoom:t,getTransform:n,getViewScale:r}){const o=We(e);function i({translateExtent:l,width:a,height:u,zoomStep:p=1,pannable:c=!0,zoomable:d=!0,inversePan:x=!1}){const y=h=>{if(h.sourceEvent.type!=="wheel"||!t)return;const v=n(),_=h.sourceEvent.ctrlKey&&Lo()?10:1,S=-h.sourceEvent.deltaY*(h.sourceEvent.deltaMode===1?.05:h.sourceEvent.deltaMode?1:.002)*p,E=v[2]*Math.pow(2,S*_);t.scaleTo(E)};let w=[0,0];const k=h=>{(h.sourceEvent.type==="mousedown"||h.sourceEvent.type==="touchstart")&&(w=[h.sourceEvent.clientX??h.sourceEvent.touches[0].clientX,h.sourceEvent.clientY??h.sourceEvent.touches[0].clientY])},m=h=>{const v=n();if(h.sourceEvent.type!=="mousemove"&&h.sourceEvent.type!=="touchmove"||!t)return;const _=[h.sourceEvent.clientX??h.sourceEvent.touches[0].clientX,h.sourceEvent.clientY??h.sourceEvent.touches[0].clientY],S=[_[0]-w[0],_[1]-w[1]];w=_;const E=r()*Math.max(v[2],Math.log(v[2]))*(x?-1:1),b={x:v[0]-S[0]*E,y:v[1]-S[1]*E},A=[[0,0],[a,u]];t.setViewportConstrained({x:b.x,y:b.y,zoom:v[2]},A,l)},g=Ug().on("start",k).on("zoom",c?m:null).on("zoom.wheel",d?y:null);o.call(g,{})}function s(){o.on("zoom",null)}return{update:i,destroy:s,pointer:lt}}const Zs=e=>({x:e.x,y:e.y,zoom:e.k}),$l=({x:e,y:t,zoom:n})=>Qs.translate(e,t).scale(n),tr=(e,t)=>e.target.closest(`.${t}`),x0=(e,t)=>t===2&&Array.isArray(e)&&e.includes(2),nk=e=>((e*=2)<=1?e*e*e:(e-=2)*e*e+2)/2,Dl=(e,t=0,n=nk,r=()=>{})=>{const o=typeof t=="number"&&t>0;return o||r(),o?e.transition().duration(t).ease(n).on("end",r):e},v0=e=>{const t=e.ctrlKey&&Lo()?10:1;return-e.deltaY*(e.deltaMode===1?.05:e.deltaMode?1:.002)*t};function rk({zoomPanValues:e,noWheelClassName:t,d3Selection:n,d3Zoom:r,panOnScrollMode:o,panOnScrollSpeed:i,zoomOnPinch:s,onPanZoomStart:l,onPanZoom:a,onPanZoomEnd:u}){return p=>{if(tr(p,t))return p.ctrlKey&&p.preventDefault(),!1;p.preventDefault(),p.stopImmediatePropagation();const c=n.property("__zoom").k||1;if(p.ctrlKey&&s){const k=lt(p),m=v0(p),g=c*Math.pow(2,m);r.scaleTo(n,g,k,p);return}const d=p.deltaMode===1?20:1;let x=o===bn.Vertical?0:p.deltaX*d,y=o===bn.Horizontal?0:p.deltaY*d;!Lo()&&p.shiftKey&&o!==bn.Vertical&&(x=p.deltaY*d,y=0),r.translateBy(n,-(x/c)*i,-(y/c)*i,{internal:!0});const w=Zs(n.property("__zoom"));clearTimeout(e.panScrollTimeout),e.isPanScrolling?(a==null||a(p,w),e.panScrollTimeout=setTimeout(()=>{u==null||u(p,w),e.isPanScrolling=!1},150)):(e.isPanScrolling=!0,l==null||l(p,w))}}function ok({noWheelClassName:e,preventScrolling:t,d3ZoomHandler:n}){return function(r,o){const i=r.type==="wheel",s=!t&&i&&!r.ctrlKey,l=tr(r,e);if(r.ctrlKey&&i&&l&&r.preventDefault(),s||l)return null;r.preventDefault(),n.call(this,r,o)}}function ik({zoomPanValues:e,onDraggingChange:t,onPanZoomStart:n}){return r=>{var i,s,l;if((i=r.sourceEvent)!=null&&i.internal)return;const o=Zs(r.transform);e.mouseButton=((s=r.sourceEvent)==null?void 0:s.button)||0,e.isZoomingOrPanning=!0,e.prevViewport=o,((l=r.sourceEvent)==null?void 0:l.type)==="mousedown"&&t(!0),n&&(n==null||n(r.sourceEvent,o))}}function sk({zoomPanValues:e,panOnDrag:t,onPaneContextMenu:n,onTransformChange:r,onPanZoom:o}){return i=>{var s,l;e.usedRightMouseButton=!!(n&&x0(t,e.mouseButton??0)),(s=i.sourceEvent)!=null&&s.sync||r([i.transform.x,i.transform.y,i.transform.k]),o&&!((l=i.sourceEvent)!=null&&l.internal)&&(o==null||o(i.sourceEvent,Zs(i.transform)))}}function lk({zoomPanValues:e,panOnDrag:t,panOnScroll:n,onDraggingChange:r,onPanZoomEnd:o,onPaneContextMenu:i}){return s=>{var l;if(!((l=s.sourceEvent)!=null&&l.internal)&&(e.isZoomingOrPanning=!1,i&&x0(t,e.mouseButton??0)&&!e.usedRightMouseButton&&s.sourceEvent&&i(s.sourceEvent),e.usedRightMouseButton=!1,r(!1),o)){const a=Zs(s.transform);e.prevViewport=a,clearTimeout(e.timerId),e.timerId=setTimeout(()=>{o==null||o(s.sourceEvent,a)},n?150:0)}}}function ak({zoomActivationKeyPressed:e,zoomOnScroll:t,zoomOnPinch:n,panOnDrag:r,panOnScroll:o,zoomOnDoubleClick:i,userSelectionActive:s,noWheelClassName:l,noPanClassName:a,lib:u,connectionInProgress:p}){return c=>{var k;const d=e||t,x=n&&c.ctrlKey,y=c.type==="wheel";if(c.button===1&&c.type==="mousedown"&&(tr(c,`${u}-flow__node`)||tr(c,`${u}-flow__edge`)))return!0;if(!r&&!d&&!o&&!i&&!n||s||p&&!y||tr(c,l)&&y||tr(c,a)&&(!y||o&&y&&!e)||!n&&c.ctrlKey&&y)return!1;if(!n&&c.type==="touchstart"&&((k=c.touches)==null?void 0:k.length)>1)return c.preventDefault(),!1;if(!d&&!o&&!x&&y||!r&&(c.type==="mousedown"||c.type==="touchstart")||Array.isArray(r)&&!r.includes(c.button)&&c.type==="mousedown")return!1;const w=Array.isArray(r)&&r.includes(c.button)||!c.button||c.button<=1;return(!c.ctrlKey||y)&&w}}function uk({domNode:e,minZoom:t,maxZoom:n,translateExtent:r,viewport:o,onPanZoom:i,onPanZoomStart:s,onPanZoomEnd:l,onDraggingChange:a}){const u={isZoomingOrPanning:!1,usedRightMouseButton:!1,prevViewport:{},mouseButton:0,timerId:void 0,panScrollTimeout:void 0,isPanScrolling:!1},p=e.getBoundingClientRect(),c=Ug().scaleExtent([t,n]).translateExtent(r),d=We(e).call(c);g({x:o.x,y:o.y,zoom:Sr(o.zoom,t,n)},[[0,0],[p.width,p.height]],r);const x=d.on("wheel.zoom"),y=d.on("dblclick.zoom");c.wheelDelta(v0);function w(T,I){return d?new Promise(P=>{c==null||c.interpolate((I==null?void 0:I.interpolate)==="linear"?ao:Vi).transform(Dl(d,I==null?void 0:I.duration,I==null?void 0:I.ease,()=>P(!0)),T)}):Promise.resolve(!1)}function k({noWheelClassName:T,noPanClassName:I,onPaneContextMenu:P,userSelectionActive:C,panOnScroll:L,panOnDrag:M,panOnScrollMode:R,panOnScrollSpeed:N,preventScrolling:j,zoomOnPinch:$,zoomOnScroll:O,zoomOnDoubleClick:B,zoomActivationKeyPressed:W,lib:V,onTransformChange:Y,connectionInProgress:X,paneClickDistance:Q,selectionOnDrag:H}){C&&!u.isZoomingOrPanning&&m();const K=L&&!W&&!C;c.clickDistance(H?1/0:!ct(Q)||Q<0?0:Q);const ee=K?rk({zoomPanValues:u,noWheelClassName:T,d3Selection:d,d3Zoom:c,panOnScrollMode:R,panOnScrollSpeed:N,zoomOnPinch:$,onPanZoomStart:s,onPanZoom:i,onPanZoomEnd:l}):ok({noWheelClassName:T,preventScrolling:j,d3ZoomHandler:x});if(d.on("wheel.zoom",ee,{passive:!1}),!C){const J=ik({zoomPanValues:u,onDraggingChange:a,onPanZoomStart:s});c.on("start",J);const Z=sk({zoomPanValues:u,panOnDrag:M,onPaneContextMenu:!!P,onPanZoom:i,onTransformChange:Y});c.on("zoom",Z);const re=lk({zoomPanValues:u,panOnDrag:M,panOnScroll:L,onPaneContextMenu:P,onPanZoomEnd:l,onDraggingChange:a});c.on("end",re)}const G=ak({zoomActivationKeyPressed:W,panOnDrag:M,zoomOnScroll:O,panOnScroll:L,zoomOnDoubleClick:B,zoomOnPinch:$,userSelectionActive:C,noPanClassName:I,noWheelClassName:T,lib:V,connectionInProgress:X});c.filter(G),B?d.on("dblclick.zoom",y):d.on("dblclick.zoom",null)}function m(){c.on("zoom",null)}async function g(T,I,P){const C=$l(T),L=c==null?void 0:c.constrain()(C,I,P);return L&&await w(L),new Promise(M=>M(L))}async function h(T,I){const P=$l(T);return await w(P,I),new Promise(C=>C(P))}function v(T){if(d){const I=$l(T),P=d.property("__zoom");(P.k!==T.zoom||P.x!==T.x||P.y!==T.y)&&(c==null||c.transform(d,I,null,{sync:!0}))}}function _(){const T=d?Wg(d.node()):{x:0,y:0,k:1};return{x:T.x,y:T.y,zoom:T.k}}function S(T,I){return d?new Promise(P=>{c==null||c.interpolate((I==null?void 0:I.interpolate)==="linear"?ao:Vi).scaleTo(Dl(d,I==null?void 0:I.duration,I==null?void 0:I.ease,()=>P(!0)),T)}):Promise.resolve(!1)}function E(T,I){return d?new Promise(P=>{c==null||c.interpolate((I==null?void 0:I.interpolate)==="linear"?ao:Vi).scaleBy(Dl(d,I==null?void 0:I.duration,I==null?void 0:I.ease,()=>P(!0)),T)}):Promise.resolve(!1)}function b(T){c==null||c.scaleExtent(T)}function A(T){c==null||c.translateExtent(T)}function D(T){const I=!ct(T)||T<0?0:T;c==null||c.clickDistance(I)}return{update:k,destroy:m,setViewport:h,setViewportConstrained:g,getViewport:_,scaleTo:S,scaleBy:E,setScaleExtent:b,setTranslateExtent:A,syncViewport:v,setClickDistance:D}}var An;(function(e){e.Line="line",e.Handle="handle"})(An||(An={}));const ck=["top-left","top-right","bottom-left","bottom-right"],dk=["top","right","bottom","left"];function fk({width:e,prevWidth:t,height:n,prevHeight:r,affectsX:o,affectsY:i}){const s=e-t,l=n-r,a=[s>0?1:s<0?-1:0,l>0?1:l<0?-1:0];return s&&o&&(a[0]=a[0]*-1),l&&i&&(a[1]=a[1]*-1),a}function mf(e){const t=e.includes("right")||e.includes("left"),n=e.includes("bottom")||e.includes("top"),r=e.includes("left"),o=e.includes("top");return{isHorizontal:t,isVertical:n,affectsX:r,affectsY:o}}function Ut(e,t){return Math.max(0,t-e)}function Yt(e,t){return Math.max(0,e-t)}function Si(e,t,n){return Math.max(0,t-e,e-n)}function yf(e,t){return e?!t:t}function pk(e,t,n,r,o,i,s,l){let{affectsX:a,affectsY:u}=t;const{isHorizontal:p,isVertical:c}=t,d=p&&c,{xSnapped:x,ySnapped:y}=n,{minWidth:w,maxWidth:k,minHeight:m,maxHeight:g}=r,{x:h,y:v,width:_,height:S,aspectRatio:E}=e;let b=Math.floor(p?x-e.pointerX:0),A=Math.floor(c?y-e.pointerY:0);const D=_+(a?-b:b),T=S+(u?-A:A),I=-i[0]*_,P=-i[1]*S;let C=Si(D,w,k),L=Si(T,m,g);if(s){let N=0,j=0;a&&b<0?N=Ut(h+b+I,s[0][0]):!a&&b>0&&(N=Yt(h+D+I,s[1][0])),u&&A<0?j=Ut(v+A+P,s[0][1]):!u&&A>0&&(j=Yt(v+T+P,s[1][1])),C=Math.max(C,N),L=Math.max(L,j)}if(l){let N=0,j=0;a&&b>0?N=Yt(h+b,l[0][0]):!a&&b<0&&(N=Ut(h+D,l[1][0])),u&&A>0?j=Yt(v+A,l[0][1]):!u&&A<0&&(j=Ut(v+T,l[1][1])),C=Math.max(C,N),L=Math.max(L,j)}if(o){if(p){const N=Si(D/E,m,g)*E;if(C=Math.max(C,N),s){let j=0;!a&&!u||a&&!u&&d?j=Yt(v+P+D/E,s[1][1])*E:j=Ut(v+P+(a?b:-b)/E,s[0][1])*E,C=Math.max(C,j)}if(l){let j=0;!a&&!u||a&&!u&&d?j=Ut(v+D/E,l[1][1])*E:j=Yt(v+(a?b:-b)/E,l[0][1])*E,C=Math.max(C,j)}}if(c){const N=Si(T*E,w,k)/E;if(L=Math.max(L,N),s){let j=0;!a&&!u||u&&!a&&d?j=Yt(h+T*E+I,s[1][0])/E:j=Ut(h+(u?A:-A)*E+I,s[0][0])/E,L=Math.max(L,j)}if(l){let j=0;!a&&!u||u&&!a&&d?j=Ut(h+T*E,l[1][0])/E:j=Yt(h+(u?A:-A)*E,l[0][0])/E,L=Math.max(L,j)}}}A=A+(A<0?L:-L),b=b+(b<0?C:-C),o&&(d?D>T*E?A=(yf(a,u)?-b:b)/E:b=(yf(a,u)?-A:A)*E:p?(A=b/E,u=a):(b=A*E,a=u));const M=a?h+b:h,R=u?v+A:v;return{width:_+(a?-b:b),height:S+(u?-A:A),x:i[0]*b*(a?-1:1)+M,y:i[1]*A*(u?-1:1)+R}}const w0={width:0,height:0,x:0,y:0},hk={...w0,pointerX:0,pointerY:0,aspectRatio:1};function gk(e){return[[0,0],[e.measured.width,e.measured.height]]}function mk(e,t,n){const r=t.position.x+e.position.x,o=t.position.y+e.position.y,i=e.measured.width??0,s=e.measured.height??0,l=n[0]*i,a=n[1]*s;return[[r-l,o-a],[r+i-l,o+s-a]]}function yk({domNode:e,nodeId:t,getStoreItems:n,onChange:r,onEnd:o}){const i=We(e);let s={controlDirection:mf("bottom-right"),boundaries:{minWidth:0,minHeight:0,maxWidth:Number.MAX_VALUE,maxHeight:Number.MAX_VALUE},resizeDirection:void 0,keepAspectRatio:!1};function l({controlPosition:u,boundaries:p,keepAspectRatio:c,resizeDirection:d,onResizeStart:x,onResize:y,onResizeEnd:w,shouldResize:k}){let m={...w0},g={...hk};s={boundaries:p,resizeDirection:d,keepAspectRatio:c,controlDirection:mf(u)};let h,v=null,_=[],S,E,b,A=!1;const D=zg().on("start",T=>{const{nodeLookup:I,transform:P,snapGrid:C,snapToGrid:L,nodeOrigin:M,paneDomNode:R}=n();if(h=I.get(t),!h)return;v=(R==null?void 0:R.getBoundingClientRect())??null;const{xSnapped:N,ySnapped:j}=uo(T.sourceEvent,{transform:P,snapGrid:C,snapToGrid:L,containerBounds:v});m={width:h.measured.width??0,height:h.measured.height??0,x:h.position.x??0,y:h.position.y??0},g={...m,pointerX:N,pointerY:j,aspectRatio:m.width/m.height},S=void 0,h.parentId&&(h.extent==="parent"||h.expandParent)&&(S=I.get(h.parentId),E=S&&h.extent==="parent"?gk(S):void 0),_=[],b=void 0;for(const[$,O]of I)if(O.parentId===t&&(_.push({id:$,position:{...O.position},extent:O.extent}),O.extent==="parent"||O.expandParent)){const B=mk(O,h,O.origin??M);b?b=[[Math.min(B[0][0],b[0][0]),Math.min(B[0][1],b[0][1])],[Math.max(B[1][0],b[1][0]),Math.max(B[1][1],b[1][1])]]:b=B}x==null||x(T,{...m})}).on("drag",T=>{const{transform:I,snapGrid:P,snapToGrid:C,nodeOrigin:L}=n(),M=uo(T.sourceEvent,{transform:I,snapGrid:P,snapToGrid:C,containerBounds:v}),R=[];if(!h)return;const{x:N,y:j,width:$,height:O}=m,B={},W=h.origin??L,{width:V,height:Y,x:X,y:Q}=pk(g,s.controlDirection,M,s.boundaries,s.keepAspectRatio,W,E,b),H=V!==$,K=Y!==O,ee=X!==N&&H,G=Q!==j&&K;if(!ee&&!G&&!H&&!K)return;if((ee||G||W[0]===1||W[1]===1)&&(B.x=ee?X:m.x,B.y=G?Q:m.y,m.x=B.x,m.y=B.y,_.length>0)){const le=X-N,ie=Q-j;for(const je of _)je.position={x:je.position.x-le+W[0]*(V-$),y:je.position.y-ie+W[1]*(Y-O)},R.push(je)}if((H||K)&&(B.width=H&&(!s.resizeDirection||s.resizeDirection==="horizontal")?V:m.width,B.height=K&&(!s.resizeDirection||s.resizeDirection==="vertical")?Y:m.height,m.width=B.width,m.height=B.height),S&&h.expandParent){const le=W[0]*(B.width??0);B.x&&B.x{A&&(w==null||w(T,{...m}),o==null||o({...m}),A=!1)});i.call(D)}function a(){i.on(".drag",null)}return{update:l,destroy:a}}var S0={exports:{}},k0={},_0={exports:{}},E0={};/** - * @license React - * use-sync-external-store-shim.production.js - * - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */var Er=z;function xk(e,t){return e===t&&(e!==0||1/e===1/t)||e!==e&&t!==t}var vk=typeof Object.is=="function"?Object.is:xk,wk=Er.useState,Sk=Er.useEffect,kk=Er.useLayoutEffect,_k=Er.useDebugValue;function Ek(e,t){var n=t(),r=wk({inst:{value:n,getSnapshot:t}}),o=r[0].inst,i=r[1];return kk(function(){o.value=n,o.getSnapshot=t,Ol(o)&&i({inst:o})},[e,n,t]),Sk(function(){return Ol(o)&&i({inst:o}),e(function(){Ol(o)&&i({inst:o})})},[e]),_k(n),n}function Ol(e){var t=e.getSnapshot;e=e.value;try{var n=t();return!vk(e,n)}catch{return!0}}function Ck(e,t){return t()}var bk=typeof window>"u"||typeof window.document>"u"||typeof window.document.createElement>"u"?Ck:Ek;E0.useSyncExternalStore=Er.useSyncExternalStore!==void 0?Er.useSyncExternalStore:bk;_0.exports=E0;var Nk=_0.exports;/** - * @license React - * use-sync-external-store-shim/with-selector.production.js - * - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */var qs=z,jk=Nk;function Mk(e,t){return e===t&&(e!==0||1/e===1/t)||e!==e&&t!==t}var zk=typeof Object.is=="function"?Object.is:Mk,Pk=jk.useSyncExternalStore,Tk=qs.useRef,Ik=qs.useEffect,Rk=qs.useMemo,Lk=qs.useDebugValue;k0.useSyncExternalStoreWithSelector=function(e,t,n,r,o){var i=Tk(null);if(i.current===null){var s={hasValue:!1,value:null};i.current=s}else s=i.current;i=Rk(function(){function a(x){if(!u){if(u=!0,p=x,x=r(x),o!==void 0&&s.hasValue){var y=s.value;if(o(y,x))return c=y}return c=x}if(y=c,zk(p,x))return y;var w=r(x);return o!==void 0&&o(y,w)?(p=x,y):(p=x,c=w)}var u=!1,p,c,d=n===void 0?null:n;return[function(){return a(t())},d===null?void 0:function(){return a(d())}]},[t,n,r,o]);var l=Pk(e,i[0],i[1]);return Ik(function(){s.hasValue=!0,s.value=l},[l]),Lk(l),l};S0.exports=k0;var Ak=S0.exports;const $k=np(Ak),Dk={},xf=e=>{let t;const n=new Set,r=(p,c)=>{const d=typeof p=="function"?p(t):p;if(!Object.is(d,t)){const x=t;t=c??(typeof d!="object"||d===null)?d:Object.assign({},t,d),n.forEach(y=>y(t,x))}},o=()=>t,a={setState:r,getState:o,getInitialState:()=>u,subscribe:p=>(n.add(p),()=>n.delete(p)),destroy:()=>{(Dk?"production":void 0)!=="production"&&console.warn("[DEPRECATED] The `destroy` method will be unsupported in a future version. Instead use unsubscribe function returned by subscribe. Everything will be garbage-collected if store is garbage-collected."),n.clear()}},u=t=e(r,o,a);return a},Ok=e=>e?xf(e):xf,{useDebugValue:Bk}=pp,{useSyncExternalStoreWithSelector:Fk}=$k,Hk=e=>e;function C0(e,t=Hk,n){const r=Fk(e.subscribe,e.getState,e.getServerState||e.getInitialState,t,n);return Bk(r),r}const vf=(e,t)=>{const n=Ok(e),r=(o,i=t)=>C0(n,o,i);return Object.assign(r,n),r},Vk=(e,t)=>e?vf(e,t):vf;function fe(e,t){if(Object.is(e,t))return!0;if(typeof e!="object"||e===null||typeof t!="object"||t===null)return!1;if(e instanceof Map&&t instanceof Map){if(e.size!==t.size)return!1;for(const[r,o]of e)if(!Object.is(o,t.get(r)))return!1;return!0}if(e instanceof Set&&t instanceof Set){if(e.size!==t.size)return!1;for(const r of e)if(!t.has(r))return!1;return!0}const n=Object.keys(e);if(n.length!==Object.keys(t).length)return!1;for(const r of n)if(!Object.prototype.hasOwnProperty.call(t,r)||!Object.is(e[r],t[r]))return!1;return!0}const Js=z.createContext(null),Wk=Js.Provider,b0=bt.error001();function ne(e,t){const n=z.useContext(Js);if(n===null)throw new Error(b0);return C0(n,e,t)}function pe(){const e=z.useContext(Js);if(e===null)throw new Error(b0);return z.useMemo(()=>({getState:e.getState,setState:e.setState,subscribe:e.subscribe}),[e])}const wf={display:"none"},Uk={position:"absolute",width:1,height:1,margin:-1,border:0,padding:0,overflow:"hidden",clip:"rect(0px, 0px, 0px, 0px)",clipPath:"inset(100%)"},N0="react-flow__node-desc",j0="react-flow__edge-desc",Yk="react-flow__aria-live",Xk=e=>e.ariaLiveMessage,Qk=e=>e.ariaLabelConfig;function Gk({rfId:e}){const t=ne(Xk);return f.jsx("div",{id:`${Yk}-${e}`,"aria-live":"assertive","aria-atomic":"true",style:Uk,children:t})}function Kk({rfId:e,disableKeyboardA11y:t}){const n=ne(Qk);return f.jsxs(f.Fragment,{children:[f.jsx("div",{id:`${N0}-${e}`,style:wf,children:t?n["node.a11yDescription.default"]:n["node.a11yDescription.keyboardDisabled"]}),f.jsx("div",{id:`${j0}-${e}`,style:wf,children:n["edge.a11yDescription.default"]}),!t&&f.jsx(Gk,{rfId:e})]})}const el=z.forwardRef(({position:e="top-left",children:t,className:n,style:r,...o},i)=>{const s=`${e}`.split("-");return f.jsx("div",{className:we(["react-flow__panel",n,...s]),style:r,ref:i,...o,children:t})});el.displayName="Panel";function Zk({proOptions:e,position:t="bottom-right"}){return e!=null&&e.hideAttribution?null:f.jsx(el,{position:t,className:"react-flow__attribution","data-message":"Please only hide this attribution when you are subscribed to React Flow Pro: https://pro.reactflow.dev",children:f.jsx("a",{href:"https://reactflow.dev",target:"_blank",rel:"noopener noreferrer","aria-label":"React Flow attribution",children:"React Flow"})})}const qk=e=>{const t=[],n=[];for(const[,r]of e.nodeLookup)r.selected&&t.push(r.internals.userNode);for(const[,r]of e.edgeLookup)r.selected&&n.push(r);return{selectedNodes:t,selectedEdges:n}},ki=e=>e.id;function Jk(e,t){return fe(e.selectedNodes.map(ki),t.selectedNodes.map(ki))&&fe(e.selectedEdges.map(ki),t.selectedEdges.map(ki))}function e_({onSelectionChange:e}){const t=pe(),{selectedNodes:n,selectedEdges:r}=ne(qk,Jk);return z.useEffect(()=>{const o={nodes:n,edges:r};e==null||e(o),t.getState().onSelectionChangeHandlers.forEach(i=>i(o))},[n,r,e]),null}const t_=e=>!!e.onSelectionChangeHandlers;function n_({onSelectionChange:e}){const t=ne(t_);return e||t?f.jsx(e_,{onSelectionChange:e}):null}const M0=[0,0],r_={x:0,y:0,zoom:1},o_=["nodes","edges","defaultNodes","defaultEdges","onConnect","onConnectStart","onConnectEnd","onClickConnectStart","onClickConnectEnd","nodesDraggable","autoPanOnNodeFocus","nodesConnectable","nodesFocusable","edgesFocusable","edgesReconnectable","elevateNodesOnSelect","elevateEdgesOnSelect","minZoom","maxZoom","nodeExtent","onNodesChange","onEdgesChange","elementsSelectable","connectionMode","snapGrid","snapToGrid","translateExtent","connectOnClick","defaultEdgeOptions","fitView","fitViewOptions","onNodesDelete","onEdgesDelete","onDelete","onNodeDrag","onNodeDragStart","onNodeDragStop","onSelectionDrag","onSelectionDragStart","onSelectionDragStop","onMoveStart","onMove","onMoveEnd","noPanClassName","nodeOrigin","autoPanOnConnect","autoPanOnNodeDrag","onError","connectionRadius","isValidConnection","selectNodesOnDrag","nodeDragThreshold","connectionDragThreshold","onBeforeDelete","debug","autoPanSpeed","ariaLabelConfig","zIndexMode"],Sf=[...o_,"rfId"],i_=e=>({setNodes:e.setNodes,setEdges:e.setEdges,setMinZoom:e.setMinZoom,setMaxZoom:e.setMaxZoom,setTranslateExtent:e.setTranslateExtent,setNodeExtent:e.setNodeExtent,reset:e.reset,setDefaultNodesAndEdges:e.setDefaultNodesAndEdges}),kf={translateExtent:To,nodeOrigin:M0,minZoom:.5,maxZoom:2,elementsSelectable:!0,noPanClassName:"nopan",rfId:"1"};function s_(e){const{setNodes:t,setEdges:n,setMinZoom:r,setMaxZoom:o,setTranslateExtent:i,setNodeExtent:s,reset:l,setDefaultNodesAndEdges:a}=ne(i_,fe),u=pe();z.useEffect(()=>(a(e.defaultNodes,e.defaultEdges),()=>{p.current=kf,l()}),[]);const p=z.useRef(kf);return z.useEffect(()=>{for(const c of Sf){const d=e[c],x=p.current[c];d!==x&&(typeof e[c]>"u"||(c==="nodes"?t(d):c==="edges"?n(d):c==="minZoom"?r(d):c==="maxZoom"?o(d):c==="translateExtent"?i(d):c==="nodeExtent"?s(d):c==="ariaLabelConfig"?u.setState({ariaLabelConfig:NS(d)}):c==="fitView"?u.setState({fitViewQueued:d}):c==="fitViewOptions"?u.setState({fitViewOptions:d}):u.setState({[c]:d})))}p.current=e},Sf.map(c=>e[c])),null}function _f(){return typeof window>"u"||!window.matchMedia?null:window.matchMedia("(prefers-color-scheme: dark)")}function l_(e){var r;const[t,n]=z.useState(e==="system"?null:e);return z.useEffect(()=>{if(e!=="system"){n(e);return}const o=_f(),i=()=>n(o!=null&&o.matches?"dark":"light");return i(),o==null||o.addEventListener("change",i),()=>{o==null||o.removeEventListener("change",i)}},[e]),t!==null?t:(r=_f())!=null&&r.matches?"dark":"light"}const Ef=typeof document<"u"?document:null;function Ao(e=null,t={target:Ef,actInsideInputWithModifier:!0}){const[n,r]=z.useState(!1),o=z.useRef(!1),i=z.useRef(new Set([])),[s,l]=z.useMemo(()=>{if(e!==null){const u=(Array.isArray(e)?e:[e]).filter(c=>typeof c=="string").map(c=>c.replace("+",` -`).replace(` - -`,` -+`).split(` -`)),p=u.reduce((c,d)=>c.concat(...d),[]);return[u,p]}return[[],[]]},[e]);return z.useEffect(()=>{const a=(t==null?void 0:t.target)??Ef,u=(t==null?void 0:t.actInsideInputWithModifier)??!0;if(e!==null){const p=x=>{var k,m;if(o.current=x.ctrlKey||x.metaKey||x.shiftKey||x.altKey,(!o.current||o.current&&!u)&&o0(x))return!1;const w=bf(x.code,l);if(i.current.add(x[w]),Cf(s,i.current,!1)){const g=((m=(k=x.composedPath)==null?void 0:k.call(x))==null?void 0:m[0])||x.target,h=(g==null?void 0:g.nodeName)==="BUTTON"||(g==null?void 0:g.nodeName)==="A";t.preventDefault!==!1&&(o.current||!h)&&x.preventDefault(),r(!0)}},c=x=>{const y=bf(x.code,l);Cf(s,i.current,!0)?(r(!1),i.current.clear()):i.current.delete(x[y]),x.key==="Meta"&&i.current.clear(),o.current=!1},d=()=>{i.current.clear(),r(!1)};return a==null||a.addEventListener("keydown",p),a==null||a.addEventListener("keyup",c),window.addEventListener("blur",d),window.addEventListener("contextmenu",d),()=>{a==null||a.removeEventListener("keydown",p),a==null||a.removeEventListener("keyup",c),window.removeEventListener("blur",d),window.removeEventListener("contextmenu",d)}}},[e,r]),n}function Cf(e,t,n){return e.filter(r=>n||r.length===t.size).some(r=>r.every(o=>t.has(o)))}function bf(e,t){return t.includes(e)?"code":"key"}const a_=()=>{const e=pe();return z.useMemo(()=>({zoomIn:t=>{const{panZoom:n}=e.getState();return n?n.scaleBy(1.2,{duration:t==null?void 0:t.duration}):Promise.resolve(!1)},zoomOut:t=>{const{panZoom:n}=e.getState();return n?n.scaleBy(1/1.2,{duration:t==null?void 0:t.duration}):Promise.resolve(!1)},zoomTo:(t,n)=>{const{panZoom:r}=e.getState();return r?r.scaleTo(t,{duration:n==null?void 0:n.duration}):Promise.resolve(!1)},getZoom:()=>e.getState().transform[2],setViewport:async(t,n)=>{const{transform:[r,o,i],panZoom:s}=e.getState();return s?(await s.setViewport({x:t.x??r,y:t.y??o,zoom:t.zoom??i},n),Promise.resolve(!0)):Promise.resolve(!1)},getViewport:()=>{const[t,n,r]=e.getState().transform;return{x:t,y:n,zoom:r}},setCenter:async(t,n,r)=>e.getState().setCenter(t,n,r),fitBounds:async(t,n)=>{const{width:r,height:o,minZoom:i,maxZoom:s,panZoom:l}=e.getState(),a=dc(t,r,o,i,s,(n==null?void 0:n.padding)??.1);return l?(await l.setViewport(a,{duration:n==null?void 0:n.duration,ease:n==null?void 0:n.ease,interpolate:n==null?void 0:n.interpolate}),Promise.resolve(!0)):Promise.resolve(!1)},screenToFlowPosition:(t,n={})=>{const{transform:r,snapGrid:o,snapToGrid:i,domNode:s}=e.getState();if(!s)return t;const{x:l,y:a}=s.getBoundingClientRect(),u={x:t.x-l,y:t.y-a},p=n.snapGrid??o,c=n.snapToGrid??i;return Qo(u,r,c,p)},flowToScreenPosition:t=>{const{transform:n,domNode:r}=e.getState();if(!r)return t;const{x:o,y:i}=r.getBoundingClientRect(),s=bs(t,n);return{x:s.x+o,y:s.y+i}}}),[])};function z0(e,t){const n=[],r=new Map,o=[];for(const i of e)if(i.type==="add"){o.push(i);continue}else if(i.type==="remove"||i.type==="replace")r.set(i.id,[i]);else{const s=r.get(i.id);s?s.push(i):r.set(i.id,[i])}for(const i of t){const s=r.get(i.id);if(!s){n.push(i);continue}if(s[0].type==="remove")continue;if(s[0].type==="replace"){n.push({...s[0].item});continue}const l={...i};for(const a of s)u_(a,l);n.push(l)}return o.length&&o.forEach(i=>{i.index!==void 0?n.splice(i.index,0,{...i.item}):n.push({...i.item})}),n}function u_(e,t){switch(e.type){case"select":{t.selected=e.selected;break}case"position":{typeof e.position<"u"&&(t.position=e.position),typeof e.dragging<"u"&&(t.dragging=e.dragging);break}case"dimensions":{typeof e.dimensions<"u"&&(t.measured={...e.dimensions},e.setAttributes&&((e.setAttributes===!0||e.setAttributes==="width")&&(t.width=e.dimensions.width),(e.setAttributes===!0||e.setAttributes==="height")&&(t.height=e.dimensions.height))),typeof e.resizing=="boolean"&&(t.resizing=e.resizing);break}}}function P0(e,t){return z0(e,t)}function T0(e,t){return z0(e,t)}function xn(e,t){return{id:e,type:"select",selected:t}}function nr(e,t=new Set,n=!1){const r=[];for(const[o,i]of e){const s=t.has(o);!(i.selected===void 0&&!s)&&i.selected!==s&&(n&&(i.selected=s),r.push(xn(i.id,s)))}return r}function Nf({items:e=[],lookup:t}){var o;const n=[],r=new Map(e.map(i=>[i.id,i]));for(const[i,s]of e.entries()){const l=t.get(s.id),a=((o=l==null?void 0:l.internals)==null?void 0:o.userNode)??l;a!==void 0&&a!==s&&n.push({id:s.id,item:s,type:"replace"}),a===void 0&&n.push({item:s,type:"add",index:i})}for(const[i]of t)r.get(i)===void 0&&n.push({id:i,type:"remove"});return n}function jf(e){return{id:e.id,type:"remove"}}const Mf=e=>yS(e),c_=e=>Kg(e);function I0(e){return z.forwardRef(e)}const d_=typeof window<"u"?z.useLayoutEffect:z.useEffect;function zf(e){const[t,n]=z.useState(BigInt(0)),[r]=z.useState(()=>f_(()=>n(o=>o+BigInt(1))));return d_(()=>{const o=r.get();o.length&&(e(o),r.reset())},[t]),r}function f_(e){let t=[];return{get:()=>t,reset:()=>{t=[]},push:n=>{t.push(n),e()}}}const R0=z.createContext(null);function p_({children:e}){const t=pe(),n=z.useCallback(l=>{const{nodes:a=[],setNodes:u,hasDefaultNodes:p,onNodesChange:c,nodeLookup:d,fitViewQueued:x,onNodesChangeMiddlewareMap:y}=t.getState();let w=a;for(const m of l)w=typeof m=="function"?m(w):m;let k=Nf({items:w,lookup:d});for(const m of y.values())k=m(k);p&&u(w),k.length>0?c==null||c(k):x&&window.requestAnimationFrame(()=>{const{fitViewQueued:m,nodes:g,setNodes:h}=t.getState();m&&h(g)})},[]),r=zf(n),o=z.useCallback(l=>{const{edges:a=[],setEdges:u,hasDefaultEdges:p,onEdgesChange:c,edgeLookup:d}=t.getState();let x=a;for(const y of l)x=typeof y=="function"?y(x):y;p?u(x):c&&c(Nf({items:x,lookup:d}))},[]),i=zf(o),s=z.useMemo(()=>({nodeQueue:r,edgeQueue:i}),[]);return f.jsx(R0.Provider,{value:s,children:e})}function h_(){const e=z.useContext(R0);if(!e)throw new Error("useBatchContext must be used within a BatchProvider");return e}const g_=e=>!!e.panZoom;function xc(){const e=a_(),t=pe(),n=h_(),r=ne(g_),o=z.useMemo(()=>{const i=c=>t.getState().nodeLookup.get(c),s=c=>{n.nodeQueue.push(c)},l=c=>{n.edgeQueue.push(c)},a=c=>{var m,g;const{nodeLookup:d,nodeOrigin:x}=t.getState(),y=Mf(c)?c:d.get(c.id),w=y.parentId?n0(y.position,y.measured,y.parentId,d,x):y.position,k={...y,position:w,width:((m=y.measured)==null?void 0:m.width)??y.width,height:((g=y.measured)==null?void 0:g.height)??y.height};return kr(k)},u=(c,d,x={replace:!1})=>{s(y=>y.map(w=>{if(w.id===c){const k=typeof d=="function"?d(w):d;return x.replace&&Mf(k)?k:{...w,...k}}return w}))},p=(c,d,x={replace:!1})=>{l(y=>y.map(w=>{if(w.id===c){const k=typeof d=="function"?d(w):d;return x.replace&&c_(k)?k:{...w,...k}}return w}))};return{getNodes:()=>t.getState().nodes.map(c=>({...c})),getNode:c=>{var d;return(d=i(c))==null?void 0:d.internals.userNode},getInternalNode:i,getEdges:()=>{const{edges:c=[]}=t.getState();return c.map(d=>({...d}))},getEdge:c=>t.getState().edgeLookup.get(c),setNodes:s,setEdges:l,addNodes:c=>{const d=Array.isArray(c)?c:[c];n.nodeQueue.push(x=>[...x,...d])},addEdges:c=>{const d=Array.isArray(c)?c:[c];n.edgeQueue.push(x=>[...x,...d])},toObject:()=>{const{nodes:c=[],edges:d=[],transform:x}=t.getState(),[y,w,k]=x;return{nodes:c.map(m=>({...m})),edges:d.map(m=>({...m})),viewport:{x:y,y:w,zoom:k}}},deleteElements:async({nodes:c=[],edges:d=[]})=>{const{nodes:x,edges:y,onNodesDelete:w,onEdgesDelete:k,triggerNodeChanges:m,triggerEdgeChanges:g,onDelete:h,onBeforeDelete:v}=t.getState(),{nodes:_,edges:S}=await kS({nodesToRemove:c,edgesToRemove:d,nodes:x,edges:y,onBeforeDelete:v}),E=S.length>0,b=_.length>0;if(E){const A=S.map(jf);k==null||k(S),g(A)}if(b){const A=_.map(jf);w==null||w(_),m(A)}return(b||E)&&(h==null||h({nodes:_,edges:S})),{deletedNodes:_,deletedEdges:S}},getIntersectingNodes:(c,d=!0,x)=>{const y=of(c),w=y?c:a(c),k=x!==void 0;return w?(x||t.getState().nodes).filter(m=>{const g=t.getState().nodeLookup.get(m.id);if(g&&!y&&(m.id===c.id||!g.internals.positionAbsolute))return!1;const h=kr(k?m:g),v=Ro(h,w);return d&&v>0||v>=h.width*h.height||v>=w.width*w.height}):[]},isNodeIntersecting:(c,d,x=!0)=>{const w=of(c)?c:a(c);if(!w)return!1;const k=Ro(w,d);return x&&k>0||k>=d.width*d.height||k>=w.width*w.height},updateNode:u,updateNodeData:(c,d,x={replace:!1})=>{u(c,y=>{const w=typeof d=="function"?d(y):d;return x.replace?{...y,data:w}:{...y,data:{...y.data,...w}}},x)},updateEdge:p,updateEdgeData:(c,d,x={replace:!1})=>{p(c,y=>{const w=typeof d=="function"?d(y):d;return x.replace?{...y,data:w}:{...y,data:{...y.data,...w}}},x)},getNodesBounds:c=>{const{nodeLookup:d,nodeOrigin:x}=t.getState();return xS(c,{nodeLookup:d,nodeOrigin:x})},getHandleConnections:({type:c,id:d,nodeId:x})=>{var y;return Array.from(((y=t.getState().connectionLookup.get(`${x}-${c}${d?`-${d}`:""}`))==null?void 0:y.values())??[])},getNodeConnections:({type:c,handleId:d,nodeId:x})=>{var y;return Array.from(((y=t.getState().connectionLookup.get(`${x}${c?d?`-${c}-${d}`:`-${c}`:""}`))==null?void 0:y.values())??[])},fitView:async c=>{const d=t.getState().fitViewResolver??bS();return t.setState({fitViewQueued:!0,fitViewOptions:c,fitViewResolver:d}),n.nodeQueue.push(x=>[...x]),d.promise}}},[]);return z.useMemo(()=>({...o,...e,viewportInitialized:r}),[r])}const Pf=e=>e.selected,m_=typeof window<"u"?window:void 0;function y_({deleteKeyCode:e,multiSelectionKeyCode:t}){const n=pe(),{deleteElements:r}=xc(),o=Ao(e,{actInsideInputWithModifier:!1}),i=Ao(t,{target:m_});z.useEffect(()=>{if(o){const{edges:s,nodes:l}=n.getState();r({nodes:l.filter(Pf),edges:s.filter(Pf)}),n.setState({nodesSelectionActive:!1})}},[o]),z.useEffect(()=>{n.setState({multiSelectionActive:i})},[i])}function x_(e){const t=pe();z.useEffect(()=>{const n=()=>{var o,i,s,l;if(!e.current||!(((i=(o=e.current).checkVisibility)==null?void 0:i.call(o))??!0))return!1;const r=fc(e.current);(r.height===0||r.width===0)&&((l=(s=t.getState()).onError)==null||l.call(s,"004",bt.error004())),t.setState({width:r.width||500,height:r.height||500})};if(e.current){n(),window.addEventListener("resize",n);const r=new ResizeObserver(()=>n());return r.observe(e.current),()=>{window.removeEventListener("resize",n),r&&e.current&&r.unobserve(e.current)}}},[])}const tl={position:"absolute",width:"100%",height:"100%",top:0,left:0},v_=e=>({userSelectionActive:e.userSelectionActive,lib:e.lib,connectionInProgress:e.connection.inProgress});function w_({onPaneContextMenu:e,zoomOnScroll:t=!0,zoomOnPinch:n=!0,panOnScroll:r=!1,panOnScrollSpeed:o=.5,panOnScrollMode:i=bn.Free,zoomOnDoubleClick:s=!0,panOnDrag:l=!0,defaultViewport:a,translateExtent:u,minZoom:p,maxZoom:c,zoomActivationKeyCode:d,preventScrolling:x=!0,children:y,noWheelClassName:w,noPanClassName:k,onViewportChange:m,isControlledViewport:g,paneClickDistance:h,selectionOnDrag:v}){const _=pe(),S=z.useRef(null),{userSelectionActive:E,lib:b,connectionInProgress:A}=ne(v_,fe),D=Ao(d),T=z.useRef();x_(S);const I=z.useCallback(P=>{m==null||m({x:P[0],y:P[1],zoom:P[2]}),g||_.setState({transform:P})},[m,g]);return z.useEffect(()=>{if(S.current){T.current=uk({domNode:S.current,minZoom:p,maxZoom:c,translateExtent:u,viewport:a,onDraggingChange:M=>_.setState(R=>R.paneDragging===M?R:{paneDragging:M}),onPanZoomStart:(M,R)=>{const{onViewportChangeStart:N,onMoveStart:j}=_.getState();j==null||j(M,R),N==null||N(R)},onPanZoom:(M,R)=>{const{onViewportChange:N,onMove:j}=_.getState();j==null||j(M,R),N==null||N(R)},onPanZoomEnd:(M,R)=>{const{onViewportChangeEnd:N,onMoveEnd:j}=_.getState();j==null||j(M,R),N==null||N(R)}});const{x:P,y:C,zoom:L}=T.current.getViewport();return _.setState({panZoom:T.current,transform:[P,C,L],domNode:S.current.closest(".react-flow")}),()=>{var M;(M=T.current)==null||M.destroy()}}},[]),z.useEffect(()=>{var P;(P=T.current)==null||P.update({onPaneContextMenu:e,zoomOnScroll:t,zoomOnPinch:n,panOnScroll:r,panOnScrollSpeed:o,panOnScrollMode:i,zoomOnDoubleClick:s,panOnDrag:l,zoomActivationKeyPressed:D,preventScrolling:x,noPanClassName:k,userSelectionActive:E,noWheelClassName:w,lib:b,onTransformChange:I,connectionInProgress:A,selectionOnDrag:v,paneClickDistance:h})},[e,t,n,r,o,i,s,l,D,x,k,E,w,b,I,A,v,h]),f.jsx("div",{className:"react-flow__renderer",ref:S,style:tl,children:y})}const S_=e=>({userSelectionActive:e.userSelectionActive,userSelectionRect:e.userSelectionRect});function k_(){const{userSelectionActive:e,userSelectionRect:t}=ne(S_,fe);return e&&t?f.jsx("div",{className:"react-flow__selection react-flow__container",style:{width:t.width,height:t.height,transform:`translate(${t.x}px, ${t.y}px)`}}):null}const Bl=(e,t)=>n=>{n.target===t.current&&(e==null||e(n))},__=e=>({userSelectionActive:e.userSelectionActive,elementsSelectable:e.elementsSelectable,connectionInProgress:e.connection.inProgress,dragging:e.paneDragging});function E_({isSelecting:e,selectionKeyPressed:t,selectionMode:n=Io.Full,panOnDrag:r,paneClickDistance:o,selectionOnDrag:i,onSelectionStart:s,onSelectionEnd:l,onPaneClick:a,onPaneContextMenu:u,onPaneScroll:p,onPaneMouseEnter:c,onPaneMouseMove:d,onPaneMouseLeave:x,children:y}){const w=pe(),{userSelectionActive:k,elementsSelectable:m,dragging:g,connectionInProgress:h}=ne(__,fe),v=m&&(e||k),_=z.useRef(null),S=z.useRef(),E=z.useRef(new Set),b=z.useRef(new Set),A=z.useRef(!1),D=N=>{if(A.current||h){A.current=!1;return}a==null||a(N),w.getState().resetSelectedElements(),w.setState({nodesSelectionActive:!1})},T=N=>{if(Array.isArray(r)&&(r!=null&&r.includes(2))){N.preventDefault();return}u==null||u(N)},I=p?N=>p(N):void 0,P=N=>{A.current&&(N.stopPropagation(),A.current=!1)},C=N=>{var Y,X;const{domNode:j}=w.getState();if(S.current=j==null?void 0:j.getBoundingClientRect(),!S.current)return;const $=N.target===_.current;if(!$&&!!N.target.closest(".nokey")||!e||!(i&&$||t)||N.button!==0||!N.isPrimary)return;(X=(Y=N.target)==null?void 0:Y.setPointerCapture)==null||X.call(Y,N.pointerId),A.current=!1;const{x:W,y:V}=dt(N.nativeEvent,S.current);w.setState({userSelectionRect:{width:0,height:0,startX:W,startY:V,x:W,y:V}}),$||(N.stopPropagation(),N.preventDefault())},L=N=>{const{userSelectionRect:j,transform:$,nodeLookup:O,edgeLookup:B,connectionLookup:W,triggerNodeChanges:V,triggerEdgeChanges:Y,defaultEdgeOptions:X,resetSelectedElements:Q}=w.getState();if(!S.current||!j)return;const{x:H,y:K}=dt(N.nativeEvent,S.current),{startX:ee,startY:G}=j;if(!A.current){const ie=t?0:o;if(Math.hypot(H-ee,K-G)<=ie)return;Q(),s==null||s(N)}A.current=!0;const J={startX:ee,startY:G,x:Hie.id)),b.current=new Set;const le=(X==null?void 0:X.selectable)??!0;for(const ie of E.current){const je=W.get(ie);if(je)for(const{edgeId:Vt}of je.values()){const jt=B.get(Vt);jt&&(jt.selectable??le)&&b.current.add(Vt)}}if(!sf(Z,E.current)){const ie=nr(O,E.current,!0);V(ie)}if(!sf(re,b.current)){const ie=nr(B,b.current);Y(ie)}w.setState({userSelectionRect:J,userSelectionActive:!0,nodesSelectionActive:!1})},M=N=>{var j,$;N.button===0&&(($=(j=N.target)==null?void 0:j.releasePointerCapture)==null||$.call(j,N.pointerId),!k&&N.target===_.current&&w.getState().userSelectionRect&&(D==null||D(N)),w.setState({userSelectionActive:!1,userSelectionRect:null}),A.current&&(l==null||l(N),w.setState({nodesSelectionActive:E.current.size>0})))},R=r===!0||Array.isArray(r)&&r.includes(0);return f.jsxs("div",{className:we(["react-flow__pane",{draggable:R,dragging:g,selection:e}]),onClick:v?void 0:Bl(D,_),onContextMenu:Bl(T,_),onWheel:Bl(I,_),onPointerEnter:v?void 0:c,onPointerMove:v?L:d,onPointerUp:v?M:void 0,onPointerDownCapture:v?C:void 0,onClickCapture:v?P:void 0,onPointerLeave:x,ref:_,style:tl,children:[y,f.jsx(k_,{})]})}function ru({id:e,store:t,unselect:n=!1,nodeRef:r}){const{addSelectedNodes:o,unselectNodesAndEdges:i,multiSelectionActive:s,nodeLookup:l,onError:a}=t.getState(),u=l.get(e);if(!u){a==null||a("012",bt.error012(e));return}t.setState({nodesSelectionActive:!1}),u.selected?(n||u.selected&&s)&&(i({nodes:[u],edges:[]}),requestAnimationFrame(()=>{var p;return(p=r==null?void 0:r.current)==null?void 0:p.blur()})):o([e])}function L0({nodeRef:e,disabled:t=!1,noDragClassName:n,handleSelector:r,nodeId:o,isSelectable:i,nodeClickDistance:s}){const l=pe(),[a,u]=z.useState(!1),p=z.useRef();return z.useEffect(()=>{p.current=GS({getStoreItems:()=>l.getState(),onNodeMouseDown:c=>{ru({id:c,store:l,nodeRef:e})},onDragStart:()=>{u(!0)},onDragStop:()=>{u(!1)}})},[]),z.useEffect(()=>{if(!(t||!e.current||!p.current))return p.current.update({noDragClassName:n,handleSelector:r,domNode:e.current,isSelectable:i,nodeId:o,nodeClickDistance:s}),()=>{var c;(c=p.current)==null||c.destroy()}},[n,r,t,i,e,o,s]),a}const C_=e=>t=>t.selected&&(t.draggable||e&&typeof t.draggable>"u");function A0(){const e=pe();return z.useCallback(n=>{const{nodeExtent:r,snapToGrid:o,snapGrid:i,nodesDraggable:s,onError:l,updateNodePositions:a,nodeLookup:u,nodeOrigin:p}=e.getState(),c=new Map,d=C_(s),x=o?i[0]:5,y=o?i[1]:5,w=n.direction.x*x*n.factor,k=n.direction.y*y*n.factor;for(const[,m]of u){if(!d(m))continue;let g={x:m.internals.positionAbsolute.x+w,y:m.internals.positionAbsolute.y+k};o&&(g=Xo(g,i));const{position:h,positionAbsolute:v}=Zg({nodeId:m.id,nextPosition:g,nodeLookup:u,nodeExtent:r,nodeOrigin:p,onError:l});m.position=h,m.internals.positionAbsolute=v,c.set(m.id,m)}a(c)},[])}const vc=z.createContext(null),b_=vc.Provider;vc.Consumer;const $0=()=>z.useContext(vc),N_=e=>({connectOnClick:e.connectOnClick,noPanClassName:e.noPanClassName,rfId:e.rfId}),j_=(e,t,n)=>r=>{const{connectionClickStartHandle:o,connectionMode:i,connection:s}=r,{fromHandle:l,toHandle:a,isValid:u}=s,p=(a==null?void 0:a.nodeId)===e&&(a==null?void 0:a.id)===t&&(a==null?void 0:a.type)===n;return{connectingFrom:(l==null?void 0:l.nodeId)===e&&(l==null?void 0:l.id)===t&&(l==null?void 0:l.type)===n,connectingTo:p,clickConnecting:(o==null?void 0:o.nodeId)===e&&(o==null?void 0:o.id)===t&&(o==null?void 0:o.type)===n,isPossibleEndHandle:i===wr.Strict?(l==null?void 0:l.type)!==n:e!==(l==null?void 0:l.nodeId)||t!==(l==null?void 0:l.id),connectionInProcess:!!l,clickConnectionInProcess:!!o,valid:p&&u}};function M_({type:e="source",position:t=q.Top,isValidConnection:n,isConnectable:r=!0,isConnectableStart:o=!0,isConnectableEnd:i=!0,id:s,onConnect:l,children:a,className:u,onMouseDown:p,onTouchStart:c,...d},x){var L,M;const y=s||null,w=e==="target",k=pe(),m=$0(),{connectOnClick:g,noPanClassName:h,rfId:v}=ne(N_,fe),{connectingFrom:_,connectingTo:S,clickConnecting:E,isPossibleEndHandle:b,connectionInProcess:A,clickConnectionInProcess:D,valid:T}=ne(j_(m,y,e),fe);m||(M=(L=k.getState()).onError)==null||M.call(L,"010",bt.error010());const I=R=>{const{defaultEdgeOptions:N,onConnect:j,hasDefaultEdges:$}=k.getState(),O={...N,...R};if($){const{edges:B,setEdges:W}=k.getState();W(IS(O,B))}j==null||j(O),l==null||l(O)},P=R=>{if(!m)return;const N=i0(R.nativeEvent);if(o&&(N&&R.button===0||!N)){const j=k.getState();nu.onPointerDown(R.nativeEvent,{handleDomNode:R.currentTarget,autoPanOnConnect:j.autoPanOnConnect,connectionMode:j.connectionMode,connectionRadius:j.connectionRadius,domNode:j.domNode,nodeLookup:j.nodeLookup,lib:j.lib,isTarget:w,handleId:y,nodeId:m,flowId:j.rfId,panBy:j.panBy,cancelConnection:j.cancelConnection,onConnectStart:j.onConnectStart,onConnectEnd:(...$)=>{var O,B;return(B=(O=k.getState()).onConnectEnd)==null?void 0:B.call(O,...$)},updateConnection:j.updateConnection,onConnect:I,isValidConnection:n||((...$)=>{var O,B;return((B=(O=k.getState()).isValidConnection)==null?void 0:B.call(O,...$))??!0}),getTransform:()=>k.getState().transform,getFromHandle:()=>k.getState().connection.fromHandle,autoPanSpeed:j.autoPanSpeed,dragThreshold:j.connectionDragThreshold})}N?p==null||p(R):c==null||c(R)},C=R=>{const{onClickConnectStart:N,onClickConnectEnd:j,connectionClickStartHandle:$,connectionMode:O,isValidConnection:B,lib:W,rfId:V,nodeLookup:Y,connection:X}=k.getState();if(!m||!$&&!o)return;if(!$){N==null||N(R.nativeEvent,{nodeId:m,handleId:y,handleType:e}),k.setState({connectionClickStartHandle:{nodeId:m,type:e,id:y}});return}const Q=r0(R.target),H=n||B,{connection:K,isValid:ee}=nu.isValid(R.nativeEvent,{handle:{nodeId:m,id:y,type:e},connectionMode:O,fromNodeId:$.nodeId,fromHandleId:$.id||null,fromType:$.type,isValidConnection:H,flowId:V,doc:Q,lib:W,nodeLookup:Y});ee&&K&&I(K);const G=structuredClone(X);delete G.inProgress,G.toPosition=G.toHandle?G.toHandle.position:null,j==null||j(R,G),k.setState({connectionClickStartHandle:null})};return f.jsx("div",{"data-handleid":y,"data-nodeid":m,"data-handlepos":t,"data-id":`${v}-${m}-${y}-${e}`,className:we(["react-flow__handle",`react-flow__handle-${t}`,"nodrag",h,u,{source:!w,target:w,connectable:r,connectablestart:o,connectableend:i,clickconnecting:E,connectingfrom:_,connectingto:S,valid:T,connectionindicator:r&&(!A||b)&&(A||D?i:o)}]),onMouseDown:P,onTouchStart:P,onClick:g?C:void 0,ref:x,...d,children:a})}const Cr=z.memo(I0(M_));function z_({data:e,isConnectable:t,sourcePosition:n=q.Bottom}){return f.jsxs(f.Fragment,{children:[e==null?void 0:e.label,f.jsx(Cr,{type:"source",position:n,isConnectable:t})]})}function P_({data:e,isConnectable:t,targetPosition:n=q.Top,sourcePosition:r=q.Bottom}){return f.jsxs(f.Fragment,{children:[f.jsx(Cr,{type:"target",position:n,isConnectable:t}),e==null?void 0:e.label,f.jsx(Cr,{type:"source",position:r,isConnectable:t})]})}function T_(){return null}function I_({data:e,isConnectable:t,targetPosition:n=q.Top}){return f.jsxs(f.Fragment,{children:[f.jsx(Cr,{type:"target",position:n,isConnectable:t}),e==null?void 0:e.label]})}const Ns={ArrowUp:{x:0,y:-1},ArrowDown:{x:0,y:1},ArrowLeft:{x:-1,y:0},ArrowRight:{x:1,y:0}},Tf={input:z_,default:P_,output:I_,group:T_};function R_(e){var t,n,r,o;return e.internals.handleBounds===void 0?{width:e.width??e.initialWidth??((t=e.style)==null?void 0:t.width),height:e.height??e.initialHeight??((n=e.style)==null?void 0:n.height)}:{width:e.width??((r=e.style)==null?void 0:r.width),height:e.height??((o=e.style)==null?void 0:o.height)}}const L_=e=>{const{width:t,height:n,x:r,y:o}=Yo(e.nodeLookup,{filter:i=>!!i.selected});return{width:ct(t)?t:null,height:ct(n)?n:null,userSelectionActive:e.userSelectionActive,transformString:`translate(${e.transform[0]}px,${e.transform[1]}px) scale(${e.transform[2]}) translate(${r}px,${o}px)`}};function A_({onSelectionContextMenu:e,noPanClassName:t,disableKeyboardA11y:n}){const r=pe(),{width:o,height:i,transformString:s,userSelectionActive:l}=ne(L_,fe),a=A0(),u=z.useRef(null);z.useEffect(()=>{var x;n||(x=u.current)==null||x.focus({preventScroll:!0})},[n]);const p=!l&&o!==null&&i!==null;if(L0({nodeRef:u,disabled:!p}),!p)return null;const c=e?x=>{const y=r.getState().nodes.filter(w=>w.selected);e(x,y)}:void 0,d=x=>{Object.prototype.hasOwnProperty.call(Ns,x.key)&&(x.preventDefault(),a({direction:Ns[x.key],factor:x.shiftKey?4:1}))};return f.jsx("div",{className:we(["react-flow__nodesselection","react-flow__container",t]),style:{transform:s},children:f.jsx("div",{ref:u,className:"react-flow__nodesselection-rect",onContextMenu:c,tabIndex:n?void 0:-1,onKeyDown:n?void 0:d,style:{width:o,height:i}})})}const If=typeof window<"u"?window:void 0,$_=e=>({nodesSelectionActive:e.nodesSelectionActive,userSelectionActive:e.userSelectionActive});function D0({children:e,onPaneClick:t,onPaneMouseEnter:n,onPaneMouseMove:r,onPaneMouseLeave:o,onPaneContextMenu:i,onPaneScroll:s,paneClickDistance:l,deleteKeyCode:a,selectionKeyCode:u,selectionOnDrag:p,selectionMode:c,onSelectionStart:d,onSelectionEnd:x,multiSelectionKeyCode:y,panActivationKeyCode:w,zoomActivationKeyCode:k,elementsSelectable:m,zoomOnScroll:g,zoomOnPinch:h,panOnScroll:v,panOnScrollSpeed:_,panOnScrollMode:S,zoomOnDoubleClick:E,panOnDrag:b,defaultViewport:A,translateExtent:D,minZoom:T,maxZoom:I,preventScrolling:P,onSelectionContextMenu:C,noWheelClassName:L,noPanClassName:M,disableKeyboardA11y:R,onViewportChange:N,isControlledViewport:j}){const{nodesSelectionActive:$,userSelectionActive:O}=ne($_,fe),B=Ao(u,{target:If}),W=Ao(w,{target:If}),V=W||b,Y=W||v,X=p&&V!==!0,Q=B||O||X;return y_({deleteKeyCode:a,multiSelectionKeyCode:y}),f.jsx(w_,{onPaneContextMenu:i,elementsSelectable:m,zoomOnScroll:g,zoomOnPinch:h,panOnScroll:Y,panOnScrollSpeed:_,panOnScrollMode:S,zoomOnDoubleClick:E,panOnDrag:!B&&V,defaultViewport:A,translateExtent:D,minZoom:T,maxZoom:I,zoomActivationKeyCode:k,preventScrolling:P,noWheelClassName:L,noPanClassName:M,onViewportChange:N,isControlledViewport:j,paneClickDistance:l,selectionOnDrag:X,children:f.jsxs(E_,{onSelectionStart:d,onSelectionEnd:x,onPaneClick:t,onPaneMouseEnter:n,onPaneMouseMove:r,onPaneMouseLeave:o,onPaneContextMenu:i,onPaneScroll:s,panOnDrag:V,isSelecting:!!Q,selectionMode:c,selectionKeyPressed:B,paneClickDistance:l,selectionOnDrag:X,children:[e,$&&f.jsx(A_,{onSelectionContextMenu:C,noPanClassName:M,disableKeyboardA11y:R})]})})}D0.displayName="FlowRenderer";const D_=z.memo(D0),O_=e=>t=>e?cc(t.nodeLookup,{x:0,y:0,width:t.width,height:t.height},t.transform,!0).map(n=>n.id):Array.from(t.nodeLookup.keys());function B_(e){return ne(z.useCallback(O_(e),[e]),fe)}const F_=e=>e.updateNodeInternals;function H_(){const e=ne(F_),[t]=z.useState(()=>typeof ResizeObserver>"u"?null:new ResizeObserver(n=>{const r=new Map;n.forEach(o=>{const i=o.target.getAttribute("data-id");r.set(i,{id:i,nodeElement:o.target,force:!0})}),e(r)}));return z.useEffect(()=>()=>{t==null||t.disconnect()},[t]),t}function V_({node:e,nodeType:t,hasDimensions:n,resizeObserver:r}){const o=pe(),i=z.useRef(null),s=z.useRef(null),l=z.useRef(e.sourcePosition),a=z.useRef(e.targetPosition),u=z.useRef(t),p=n&&!!e.internals.handleBounds;return z.useEffect(()=>{i.current&&!e.hidden&&(!p||s.current!==i.current)&&(s.current&&(r==null||r.unobserve(s.current)),r==null||r.observe(i.current),s.current=i.current)},[p,e.hidden]),z.useEffect(()=>()=>{s.current&&(r==null||r.unobserve(s.current),s.current=null)},[]),z.useEffect(()=>{if(i.current){const c=u.current!==t,d=l.current!==e.sourcePosition,x=a.current!==e.targetPosition;(c||d||x)&&(u.current=t,l.current=e.sourcePosition,a.current=e.targetPosition,o.getState().updateNodeInternals(new Map([[e.id,{id:e.id,nodeElement:i.current,force:!0}]])))}},[e.id,t,e.sourcePosition,e.targetPosition]),i}function W_({id:e,onClick:t,onMouseEnter:n,onMouseMove:r,onMouseLeave:o,onContextMenu:i,onDoubleClick:s,nodesDraggable:l,elementsSelectable:a,nodesConnectable:u,nodesFocusable:p,resizeObserver:c,noDragClassName:d,noPanClassName:x,disableKeyboardA11y:y,rfId:w,nodeTypes:k,nodeClickDistance:m,onError:g}){const{node:h,internals:v,isParent:_}=ne(H=>{const K=H.nodeLookup.get(e),ee=H.parentLookup.has(e);return{node:K,internals:K.internals,isParent:ee}},fe);let S=h.type||"default",E=(k==null?void 0:k[S])||Tf[S];E===void 0&&(g==null||g("003",bt.error003(S)),S="default",E=(k==null?void 0:k.default)||Tf.default);const b=!!(h.draggable||l&&typeof h.draggable>"u"),A=!!(h.selectable||a&&typeof h.selectable>"u"),D=!!(h.connectable||u&&typeof h.connectable>"u"),T=!!(h.focusable||p&&typeof h.focusable>"u"),I=pe(),P=t0(h),C=V_({node:h,nodeType:S,hasDimensions:P,resizeObserver:c}),L=L0({nodeRef:C,disabled:h.hidden||!b,noDragClassName:d,handleSelector:h.dragHandle,nodeId:e,isSelectable:A,nodeClickDistance:m}),M=A0();if(h.hidden)return null;const R=Ht(h),N=R_(h),j=A||b||t||n||r||o,$=n?H=>n(H,{...v.userNode}):void 0,O=r?H=>r(H,{...v.userNode}):void 0,B=o?H=>o(H,{...v.userNode}):void 0,W=i?H=>i(H,{...v.userNode}):void 0,V=s?H=>s(H,{...v.userNode}):void 0,Y=H=>{const{selectNodesOnDrag:K,nodeDragThreshold:ee}=I.getState();A&&(!K||!b||ee>0)&&ru({id:e,store:I,nodeRef:C}),t&&t(H,{...v.userNode})},X=H=>{if(!(o0(H.nativeEvent)||y)){if(Yg.includes(H.key)&&A){const K=H.key==="Escape";ru({id:e,store:I,unselect:K,nodeRef:C})}else if(b&&h.selected&&Object.prototype.hasOwnProperty.call(Ns,H.key)){H.preventDefault();const{ariaLabelConfig:K}=I.getState();I.setState({ariaLiveMessage:K["node.a11yDescription.ariaLiveMessage"]({direction:H.key.replace("Arrow","").toLowerCase(),x:~~v.positionAbsolute.x,y:~~v.positionAbsolute.y})}),M({direction:Ns[H.key],factor:H.shiftKey?4:1})}}},Q=()=>{var re;if(y||!((re=C.current)!=null&&re.matches(":focus-visible")))return;const{transform:H,width:K,height:ee,autoPanOnNodeFocus:G,setCenter:J}=I.getState();if(!G)return;cc(new Map([[e,h]]),{x:0,y:0,width:K,height:ee},H,!0).length>0||J(h.position.x+R.width/2,h.position.y+R.height/2,{zoom:H[2]})};return f.jsx("div",{className:we(["react-flow__node",`react-flow__node-${S}`,{[x]:b},h.className,{selected:h.selected,selectable:A,parent:_,draggable:b,dragging:L}]),ref:C,style:{zIndex:v.z,transform:`translate(${v.positionAbsolute.x}px,${v.positionAbsolute.y}px)`,pointerEvents:j?"all":"none",visibility:P?"visible":"hidden",...h.style,...N},"data-id":e,"data-testid":`rf__node-${e}`,onMouseEnter:$,onMouseMove:O,onMouseLeave:B,onContextMenu:W,onClick:Y,onDoubleClick:V,onKeyDown:T?X:void 0,tabIndex:T?0:void 0,onFocus:T?Q:void 0,role:h.ariaRole??(T?"group":void 0),"aria-roledescription":"node","aria-describedby":y?void 0:`${N0}-${w}`,"aria-label":h.ariaLabel,...h.domAttributes,children:f.jsx(b_,{value:e,children:f.jsx(E,{id:e,data:h.data,type:S,positionAbsoluteX:v.positionAbsolute.x,positionAbsoluteY:v.positionAbsolute.y,selected:h.selected??!1,selectable:A,draggable:b,deletable:h.deletable??!0,isConnectable:D,sourcePosition:h.sourcePosition,targetPosition:h.targetPosition,dragging:L,dragHandle:h.dragHandle,zIndex:v.z,parentId:h.parentId,...R})})})}var U_=z.memo(W_);const Y_=e=>({nodesDraggable:e.nodesDraggable,nodesConnectable:e.nodesConnectable,nodesFocusable:e.nodesFocusable,elementsSelectable:e.elementsSelectable,onError:e.onError});function O0(e){const{nodesDraggable:t,nodesConnectable:n,nodesFocusable:r,elementsSelectable:o,onError:i}=ne(Y_,fe),s=B_(e.onlyRenderVisibleElements),l=H_();return f.jsx("div",{className:"react-flow__nodes",style:tl,children:s.map(a=>f.jsx(U_,{id:a,nodeTypes:e.nodeTypes,nodeExtent:e.nodeExtent,onClick:e.onNodeClick,onMouseEnter:e.onNodeMouseEnter,onMouseMove:e.onNodeMouseMove,onMouseLeave:e.onNodeMouseLeave,onContextMenu:e.onNodeContextMenu,onDoubleClick:e.onNodeDoubleClick,noDragClassName:e.noDragClassName,noPanClassName:e.noPanClassName,rfId:e.rfId,disableKeyboardA11y:e.disableKeyboardA11y,resizeObserver:l,nodesDraggable:t,nodesConnectable:n,nodesFocusable:r,elementsSelectable:o,nodeClickDistance:e.nodeClickDistance,onError:i},a))})}O0.displayName="NodeRenderer";const X_=z.memo(O0);function Q_(e){return ne(z.useCallback(n=>{if(!e)return n.edges.map(o=>o.id);const r=[];if(n.width&&n.height)for(const o of n.edges){const i=n.nodeLookup.get(o.source),s=n.nodeLookup.get(o.target);i&&s&&zS({sourceNode:i,targetNode:s,width:n.width,height:n.height,transform:n.transform})&&r.push(o.id)}return r},[e]),fe)}const G_=({color:e="none",strokeWidth:t=1})=>{const n={strokeWidth:t,...e&&{stroke:e}};return f.jsx("polyline",{className:"arrow",style:n,strokeLinecap:"round",fill:"none",strokeLinejoin:"round",points:"-5,-4 0,0 -5,4"})},K_=({color:e="none",strokeWidth:t=1})=>{const n={strokeWidth:t,...e&&{stroke:e,fill:e}};return f.jsx("polyline",{className:"arrowclosed",style:n,strokeLinecap:"round",strokeLinejoin:"round",points:"-5,-4 0,0 -5,4 -5,-4"})},Rf={[Es.Arrow]:G_,[Es.ArrowClosed]:K_};function Z_(e){const t=pe();return z.useMemo(()=>{var o,i;return Object.prototype.hasOwnProperty.call(Rf,e)?Rf[e]:((i=(o=t.getState()).onError)==null||i.call(o,"009",bt.error009(e)),null)},[e])}const q_=({id:e,type:t,color:n,width:r=12.5,height:o=12.5,markerUnits:i="strokeWidth",strokeWidth:s,orient:l="auto-start-reverse"})=>{const a=Z_(t);return a?f.jsx("marker",{className:"react-flow__arrowhead",id:e,markerWidth:`${r}`,markerHeight:`${o}`,viewBox:"-10 -10 20 20",markerUnits:i,orient:l,refX:"0",refY:"0",children:f.jsx(a,{color:n,strokeWidth:s})}):null},B0=({defaultColor:e,rfId:t})=>{const n=ne(i=>i.edges),r=ne(i=>i.defaultEdgeOptions),o=z.useMemo(()=>DS(n,{id:t,defaultColor:e,defaultMarkerStart:r==null?void 0:r.markerStart,defaultMarkerEnd:r==null?void 0:r.markerEnd}),[n,r,t,e]);return o.length?f.jsx("svg",{className:"react-flow__marker","aria-hidden":"true",children:f.jsx("defs",{children:o.map(i=>f.jsx(q_,{id:i.id,type:i.type,color:i.color,width:i.width,height:i.height,markerUnits:i.markerUnits,strokeWidth:i.strokeWidth,orient:i.orient},i.id))})}):null};B0.displayName="MarkerDefinitions";var J_=z.memo(B0);function F0({x:e,y:t,label:n,labelStyle:r,labelShowBg:o=!0,labelBgStyle:i,labelBgPadding:s=[2,4],labelBgBorderRadius:l=2,children:a,className:u,...p}){const[c,d]=z.useState({x:1,y:0,width:0,height:0}),x=we(["react-flow__edge-textwrapper",u]),y=z.useRef(null);return z.useEffect(()=>{if(y.current){const w=y.current.getBBox();d({x:w.x,y:w.y,width:w.width,height:w.height})}},[n]),n?f.jsxs("g",{transform:`translate(${e-c.width/2} ${t-c.height/2})`,className:x,visibility:c.width?"visible":"hidden",...p,children:[o&&f.jsx("rect",{width:c.width+2*s[0],x:-s[0],y:-s[1],height:c.height+2*s[1],className:"react-flow__edge-textbg",style:i,rx:l,ry:l}),f.jsx("text",{className:"react-flow__edge-text",y:c.height/2,dy:"0.3em",ref:y,style:r,children:n}),a]}):null}F0.displayName="EdgeText";const eE=z.memo(F0);function nl({path:e,labelX:t,labelY:n,label:r,labelStyle:o,labelShowBg:i,labelBgStyle:s,labelBgPadding:l,labelBgBorderRadius:a,interactionWidth:u=20,...p}){return f.jsxs(f.Fragment,{children:[f.jsx("path",{...p,d:e,fill:"none",className:we(["react-flow__edge-path",p.className])}),u?f.jsx("path",{d:e,fill:"none",strokeOpacity:0,strokeWidth:u,className:"react-flow__edge-interaction"}):null,r&&ct(t)&&ct(n)?f.jsx(eE,{x:t,y:n,label:r,labelStyle:o,labelShowBg:i,labelBgStyle:s,labelBgPadding:l,labelBgBorderRadius:a}):null]})}function Lf({pos:e,x1:t,y1:n,x2:r,y2:o}){return e===q.Left||e===q.Right?[.5*(t+r),n]:[t,.5*(n+o)]}function H0({sourceX:e,sourceY:t,sourcePosition:n=q.Bottom,targetX:r,targetY:o,targetPosition:i=q.Top}){const[s,l]=Lf({pos:n,x1:e,y1:t,x2:r,y2:o}),[a,u]=Lf({pos:i,x1:r,y1:o,x2:e,y2:t}),[p,c,d,x]=s0({sourceX:e,sourceY:t,targetX:r,targetY:o,sourceControlX:s,sourceControlY:l,targetControlX:a,targetControlY:u});return[`M${e},${t} C${s},${l} ${a},${u} ${r},${o}`,p,c,d,x]}function V0(e){return z.memo(({id:t,sourceX:n,sourceY:r,targetX:o,targetY:i,sourcePosition:s,targetPosition:l,label:a,labelStyle:u,labelShowBg:p,labelBgStyle:c,labelBgPadding:d,labelBgBorderRadius:x,style:y,markerEnd:w,markerStart:k,interactionWidth:m})=>{const[g,h,v]=H0({sourceX:n,sourceY:r,sourcePosition:s,targetX:o,targetY:i,targetPosition:l}),_=e.isInternal?void 0:t;return f.jsx(nl,{id:_,path:g,labelX:h,labelY:v,label:a,labelStyle:u,labelShowBg:p,labelBgStyle:c,labelBgPadding:d,labelBgBorderRadius:x,style:y,markerEnd:w,markerStart:k,interactionWidth:m})})}const tE=V0({isInternal:!1}),W0=V0({isInternal:!0});tE.displayName="SimpleBezierEdge";W0.displayName="SimpleBezierEdgeInternal";function U0(e){return z.memo(({id:t,sourceX:n,sourceY:r,targetX:o,targetY:i,label:s,labelStyle:l,labelShowBg:a,labelBgStyle:u,labelBgPadding:p,labelBgBorderRadius:c,style:d,sourcePosition:x=q.Bottom,targetPosition:y=q.Top,markerEnd:w,markerStart:k,pathOptions:m,interactionWidth:g})=>{const[h,v,_]=Ja({sourceX:n,sourceY:r,sourcePosition:x,targetX:o,targetY:i,targetPosition:y,borderRadius:m==null?void 0:m.borderRadius,offset:m==null?void 0:m.offset,stepPosition:m==null?void 0:m.stepPosition}),S=e.isInternal?void 0:t;return f.jsx(nl,{id:S,path:h,labelX:v,labelY:_,label:s,labelStyle:l,labelShowBg:a,labelBgStyle:u,labelBgPadding:p,labelBgBorderRadius:c,style:d,markerEnd:w,markerStart:k,interactionWidth:g})})}const Y0=U0({isInternal:!1}),X0=U0({isInternal:!0});Y0.displayName="SmoothStepEdge";X0.displayName="SmoothStepEdgeInternal";function Q0(e){return z.memo(({id:t,...n})=>{var o;const r=e.isInternal?void 0:t;return f.jsx(Y0,{...n,id:r,pathOptions:z.useMemo(()=>{var i;return{borderRadius:0,offset:(i=n.pathOptions)==null?void 0:i.offset}},[(o=n.pathOptions)==null?void 0:o.offset])})})}const nE=Q0({isInternal:!1}),G0=Q0({isInternal:!0});nE.displayName="StepEdge";G0.displayName="StepEdgeInternal";function K0(e){return z.memo(({id:t,sourceX:n,sourceY:r,targetX:o,targetY:i,label:s,labelStyle:l,labelShowBg:a,labelBgStyle:u,labelBgPadding:p,labelBgBorderRadius:c,style:d,markerEnd:x,markerStart:y,interactionWidth:w})=>{const[k,m,g]=u0({sourceX:n,sourceY:r,targetX:o,targetY:i}),h=e.isInternal?void 0:t;return f.jsx(nl,{id:h,path:k,labelX:m,labelY:g,label:s,labelStyle:l,labelShowBg:a,labelBgStyle:u,labelBgPadding:p,labelBgBorderRadius:c,style:d,markerEnd:x,markerStart:y,interactionWidth:w})})}const rE=K0({isInternal:!1}),Z0=K0({isInternal:!0});rE.displayName="StraightEdge";Z0.displayName="StraightEdgeInternal";function q0(e){return z.memo(({id:t,sourceX:n,sourceY:r,targetX:o,targetY:i,sourcePosition:s=q.Bottom,targetPosition:l=q.Top,label:a,labelStyle:u,labelShowBg:p,labelBgStyle:c,labelBgPadding:d,labelBgBorderRadius:x,style:y,markerEnd:w,markerStart:k,pathOptions:m,interactionWidth:g})=>{const[h,v,_]=l0({sourceX:n,sourceY:r,sourcePosition:s,targetX:o,targetY:i,targetPosition:l,curvature:m==null?void 0:m.curvature}),S=e.isInternal?void 0:t;return f.jsx(nl,{id:S,path:h,labelX:v,labelY:_,label:a,labelStyle:u,labelShowBg:p,labelBgStyle:c,labelBgPadding:d,labelBgBorderRadius:x,style:y,markerEnd:w,markerStart:k,interactionWidth:g})})}const oE=q0({isInternal:!1}),J0=q0({isInternal:!0});oE.displayName="BezierEdge";J0.displayName="BezierEdgeInternal";const Af={default:J0,straight:Z0,step:G0,smoothstep:X0,simplebezier:W0},$f={sourceX:null,sourceY:null,targetX:null,targetY:null,sourcePosition:null,targetPosition:null},iE=(e,t,n)=>n===q.Left?e-t:n===q.Right?e+t:e,sE=(e,t,n)=>n===q.Top?e-t:n===q.Bottom?e+t:e,Df="react-flow__edgeupdater";function Of({position:e,centerX:t,centerY:n,radius:r=10,onMouseDown:o,onMouseEnter:i,onMouseOut:s,type:l}){return f.jsx("circle",{onMouseDown:o,onMouseEnter:i,onMouseOut:s,className:we([Df,`${Df}-${l}`]),cx:iE(t,r,e),cy:sE(n,r,e),r,stroke:"transparent",fill:"transparent"})}function lE({isReconnectable:e,reconnectRadius:t,edge:n,sourceX:r,sourceY:o,targetX:i,targetY:s,sourcePosition:l,targetPosition:a,onReconnect:u,onReconnectStart:p,onReconnectEnd:c,setReconnecting:d,setUpdateHover:x}){const y=pe(),w=(v,_)=>{if(v.button!==0)return;const{autoPanOnConnect:S,domNode:E,connectionMode:b,connectionRadius:A,lib:D,onConnectStart:T,cancelConnection:I,nodeLookup:P,rfId:C,panBy:L,updateConnection:M}=y.getState(),R=_.type==="target",N=(O,B)=>{d(!1),c==null||c(O,n,_.type,B)},j=O=>u==null?void 0:u(n,O),$=(O,B)=>{d(!0),p==null||p(v,n,_.type),T==null||T(O,B)};nu.onPointerDown(v.nativeEvent,{autoPanOnConnect:S,connectionMode:b,connectionRadius:A,domNode:E,handleId:_.id,nodeId:_.nodeId,nodeLookup:P,isTarget:R,edgeUpdaterType:_.type,lib:D,flowId:C,cancelConnection:I,panBy:L,isValidConnection:(...O)=>{var B,W;return((W=(B=y.getState()).isValidConnection)==null?void 0:W.call(B,...O))??!0},onConnect:j,onConnectStart:$,onConnectEnd:(...O)=>{var B,W;return(W=(B=y.getState()).onConnectEnd)==null?void 0:W.call(B,...O)},onReconnectEnd:N,updateConnection:M,getTransform:()=>y.getState().transform,getFromHandle:()=>y.getState().connection.fromHandle,dragThreshold:y.getState().connectionDragThreshold,handleDomNode:v.currentTarget})},k=v=>w(v,{nodeId:n.target,id:n.targetHandle??null,type:"target"}),m=v=>w(v,{nodeId:n.source,id:n.sourceHandle??null,type:"source"}),g=()=>x(!0),h=()=>x(!1);return f.jsxs(f.Fragment,{children:[(e===!0||e==="source")&&f.jsx(Of,{position:l,centerX:r,centerY:o,radius:t,onMouseDown:k,onMouseEnter:g,onMouseOut:h,type:"source"}),(e===!0||e==="target")&&f.jsx(Of,{position:a,centerX:i,centerY:s,radius:t,onMouseDown:m,onMouseEnter:g,onMouseOut:h,type:"target"})]})}function aE({id:e,edgesFocusable:t,edgesReconnectable:n,elementsSelectable:r,onClick:o,onDoubleClick:i,onContextMenu:s,onMouseEnter:l,onMouseMove:a,onMouseLeave:u,reconnectRadius:p,onReconnect:c,onReconnectStart:d,onReconnectEnd:x,rfId:y,edgeTypes:w,noPanClassName:k,onError:m,disableKeyboardA11y:g}){let h=ne(J=>J.edgeLookup.get(e));const v=ne(J=>J.defaultEdgeOptions);h=v?{...v,...h}:h;let _=h.type||"default",S=(w==null?void 0:w[_])||Af[_];S===void 0&&(m==null||m("011",bt.error011(_)),_="default",S=(w==null?void 0:w.default)||Af.default);const E=!!(h.focusable||t&&typeof h.focusable>"u"),b=typeof c<"u"&&(h.reconnectable||n&&typeof h.reconnectable>"u"),A=!!(h.selectable||r&&typeof h.selectable>"u"),D=z.useRef(null),[T,I]=z.useState(!1),[P,C]=z.useState(!1),L=pe(),{zIndex:M,sourceX:R,sourceY:N,targetX:j,targetY:$,sourcePosition:O,targetPosition:B}=ne(z.useCallback(J=>{const Z=J.nodeLookup.get(h.source),re=J.nodeLookup.get(h.target);if(!Z||!re)return{zIndex:h.zIndex,...$f};const le=$S({id:e,sourceNode:Z,targetNode:re,sourceHandle:h.sourceHandle||null,targetHandle:h.targetHandle||null,connectionMode:J.connectionMode,onError:m});return{zIndex:MS({selected:h.selected,zIndex:h.zIndex,sourceNode:Z,targetNode:re,elevateOnSelect:J.elevateEdgesOnSelect,zIndexMode:J.zIndexMode}),...le||$f}},[h.source,h.target,h.sourceHandle,h.targetHandle,h.selected,h.zIndex]),fe),W=z.useMemo(()=>h.markerStart?`url('#${eu(h.markerStart,y)}')`:void 0,[h.markerStart,y]),V=z.useMemo(()=>h.markerEnd?`url('#${eu(h.markerEnd,y)}')`:void 0,[h.markerEnd,y]);if(h.hidden||R===null||N===null||j===null||$===null)return null;const Y=J=>{var ie;const{addSelectedEdges:Z,unselectNodesAndEdges:re,multiSelectionActive:le}=L.getState();A&&(L.setState({nodesSelectionActive:!1}),h.selected&&le?(re({nodes:[],edges:[h]}),(ie=D.current)==null||ie.blur()):Z([e])),o&&o(J,h)},X=i?J=>{i(J,{...h})}:void 0,Q=s?J=>{s(J,{...h})}:void 0,H=l?J=>{l(J,{...h})}:void 0,K=a?J=>{a(J,{...h})}:void 0,ee=u?J=>{u(J,{...h})}:void 0,G=J=>{var Z;if(!g&&Yg.includes(J.key)&&A){const{unselectNodesAndEdges:re,addSelectedEdges:le}=L.getState();J.key==="Escape"?((Z=D.current)==null||Z.blur(),re({edges:[h]})):le([e])}};return f.jsx("svg",{style:{zIndex:M},children:f.jsxs("g",{className:we(["react-flow__edge",`react-flow__edge-${_}`,h.className,k,{selected:h.selected,animated:h.animated,inactive:!A&&!o,updating:T,selectable:A}]),onClick:Y,onDoubleClick:X,onContextMenu:Q,onMouseEnter:H,onMouseMove:K,onMouseLeave:ee,onKeyDown:E?G:void 0,tabIndex:E?0:void 0,role:h.ariaRole??(E?"group":"img"),"aria-roledescription":"edge","data-id":e,"data-testid":`rf__edge-${e}`,"aria-label":h.ariaLabel===null?void 0:h.ariaLabel||`Edge from ${h.source} to ${h.target}`,"aria-describedby":E?`${j0}-${y}`:void 0,ref:D,...h.domAttributes,children:[!P&&f.jsx(S,{id:e,source:h.source,target:h.target,type:h.type,selected:h.selected,animated:h.animated,selectable:A,deletable:h.deletable??!0,label:h.label,labelStyle:h.labelStyle,labelShowBg:h.labelShowBg,labelBgStyle:h.labelBgStyle,labelBgPadding:h.labelBgPadding,labelBgBorderRadius:h.labelBgBorderRadius,sourceX:R,sourceY:N,targetX:j,targetY:$,sourcePosition:O,targetPosition:B,data:h.data,style:h.style,sourceHandleId:h.sourceHandle,targetHandleId:h.targetHandle,markerStart:W,markerEnd:V,pathOptions:"pathOptions"in h?h.pathOptions:void 0,interactionWidth:h.interactionWidth}),b&&f.jsx(lE,{edge:h,isReconnectable:b,reconnectRadius:p,onReconnect:c,onReconnectStart:d,onReconnectEnd:x,sourceX:R,sourceY:N,targetX:j,targetY:$,sourcePosition:O,targetPosition:B,setUpdateHover:I,setReconnecting:C})]})})}var uE=z.memo(aE);const cE=e=>({edgesFocusable:e.edgesFocusable,edgesReconnectable:e.edgesReconnectable,elementsSelectable:e.elementsSelectable,connectionMode:e.connectionMode,onError:e.onError});function em({defaultMarkerColor:e,onlyRenderVisibleElements:t,rfId:n,edgeTypes:r,noPanClassName:o,onReconnect:i,onEdgeContextMenu:s,onEdgeMouseEnter:l,onEdgeMouseMove:a,onEdgeMouseLeave:u,onEdgeClick:p,reconnectRadius:c,onEdgeDoubleClick:d,onReconnectStart:x,onReconnectEnd:y,disableKeyboardA11y:w}){const{edgesFocusable:k,edgesReconnectable:m,elementsSelectable:g,onError:h}=ne(cE,fe),v=Q_(t);return f.jsxs("div",{className:"react-flow__edges",children:[f.jsx(J_,{defaultColor:e,rfId:n}),v.map(_=>f.jsx(uE,{id:_,edgesFocusable:k,edgesReconnectable:m,elementsSelectable:g,noPanClassName:o,onReconnect:i,onContextMenu:s,onMouseEnter:l,onMouseMove:a,onMouseLeave:u,onClick:p,reconnectRadius:c,onDoubleClick:d,onReconnectStart:x,onReconnectEnd:y,rfId:n,onError:h,edgeTypes:r,disableKeyboardA11y:w},_))]})}em.displayName="EdgeRenderer";const dE=z.memo(em),fE=e=>`translate(${e.transform[0]}px,${e.transform[1]}px) scale(${e.transform[2]})`;function pE({children:e}){const t=ne(fE);return f.jsx("div",{className:"react-flow__viewport xyflow__viewport react-flow__container",style:{transform:t},children:e})}function hE(e){const t=xc(),n=z.useRef(!1);z.useEffect(()=>{!n.current&&t.viewportInitialized&&e&&(setTimeout(()=>e(t),1),n.current=!0)},[e,t.viewportInitialized])}const gE=e=>{var t;return(t=e.panZoom)==null?void 0:t.syncViewport};function mE(e){const t=ne(gE),n=pe();return z.useEffect(()=>{e&&(t==null||t(e),n.setState({transform:[e.x,e.y,e.zoom]}))},[e,t]),null}function yE(e){return e.connection.inProgress?{...e.connection,to:Qo(e.connection.to,e.transform)}:{...e.connection}}function xE(e){return yE}function vE(e){const t=xE();return ne(t,fe)}const wE=e=>({nodesConnectable:e.nodesConnectable,isValid:e.connection.isValid,inProgress:e.connection.inProgress,width:e.width,height:e.height});function SE({containerStyle:e,style:t,type:n,component:r}){const{nodesConnectable:o,width:i,height:s,isValid:l,inProgress:a}=ne(wE,fe);return!(i&&o&&a)?null:f.jsx("svg",{style:e,width:i,height:s,className:"react-flow__connectionline react-flow__container",children:f.jsx("g",{className:we(["react-flow__connection",Gg(l)]),children:f.jsx(tm,{style:t,type:n,CustomComponent:r,isValid:l})})})}const tm=({style:e,type:t=Zt.Bezier,CustomComponent:n,isValid:r})=>{const{inProgress:o,from:i,fromNode:s,fromHandle:l,fromPosition:a,to:u,toNode:p,toHandle:c,toPosition:d,pointer:x}=vE();if(!o)return;if(n)return f.jsx(n,{connectionLineType:t,connectionLineStyle:e,fromNode:s,fromHandle:l,fromX:i.x,fromY:i.y,toX:u.x,toY:u.y,fromPosition:a,toPosition:d,connectionStatus:Gg(r),toNode:p,toHandle:c,pointer:x});let y="";const w={sourceX:i.x,sourceY:i.y,sourcePosition:a,targetX:u.x,targetY:u.y,targetPosition:d};switch(t){case Zt.Bezier:[y]=l0(w);break;case Zt.SimpleBezier:[y]=H0(w);break;case Zt.Step:[y]=Ja({...w,borderRadius:0});break;case Zt.SmoothStep:[y]=Ja(w);break;default:[y]=u0(w)}return f.jsx("path",{d:y,fill:"none",className:"react-flow__connection-path",style:e})};tm.displayName="ConnectionLine";const kE={};function Bf(e=kE){z.useRef(e),pe(),z.useEffect(()=>{},[e])}function _E(){pe(),z.useRef(!1),z.useEffect(()=>{},[])}function nm({nodeTypes:e,edgeTypes:t,onInit:n,onNodeClick:r,onEdgeClick:o,onNodeDoubleClick:i,onEdgeDoubleClick:s,onNodeMouseEnter:l,onNodeMouseMove:a,onNodeMouseLeave:u,onNodeContextMenu:p,onSelectionContextMenu:c,onSelectionStart:d,onSelectionEnd:x,connectionLineType:y,connectionLineStyle:w,connectionLineComponent:k,connectionLineContainerStyle:m,selectionKeyCode:g,selectionOnDrag:h,selectionMode:v,multiSelectionKeyCode:_,panActivationKeyCode:S,zoomActivationKeyCode:E,deleteKeyCode:b,onlyRenderVisibleElements:A,elementsSelectable:D,defaultViewport:T,translateExtent:I,minZoom:P,maxZoom:C,preventScrolling:L,defaultMarkerColor:M,zoomOnScroll:R,zoomOnPinch:N,panOnScroll:j,panOnScrollSpeed:$,panOnScrollMode:O,zoomOnDoubleClick:B,panOnDrag:W,onPaneClick:V,onPaneMouseEnter:Y,onPaneMouseMove:X,onPaneMouseLeave:Q,onPaneScroll:H,onPaneContextMenu:K,paneClickDistance:ee,nodeClickDistance:G,onEdgeContextMenu:J,onEdgeMouseEnter:Z,onEdgeMouseMove:re,onEdgeMouseLeave:le,reconnectRadius:ie,onReconnect:je,onReconnectStart:Vt,onReconnectEnd:jt,noDragClassName:gn,noWheelClassName:Mr,noPanClassName:zr,disableKeyboardA11y:Pr,nodeExtent:rl,rfId:Ko,viewport:On,onViewportChange:Tr}){return Bf(e),Bf(t),_E(),hE(n),mE(On),f.jsx(D_,{onPaneClick:V,onPaneMouseEnter:Y,onPaneMouseMove:X,onPaneMouseLeave:Q,onPaneContextMenu:K,onPaneScroll:H,paneClickDistance:ee,deleteKeyCode:b,selectionKeyCode:g,selectionOnDrag:h,selectionMode:v,onSelectionStart:d,onSelectionEnd:x,multiSelectionKeyCode:_,panActivationKeyCode:S,zoomActivationKeyCode:E,elementsSelectable:D,zoomOnScroll:R,zoomOnPinch:N,zoomOnDoubleClick:B,panOnScroll:j,panOnScrollSpeed:$,panOnScrollMode:O,panOnDrag:W,defaultViewport:T,translateExtent:I,minZoom:P,maxZoom:C,onSelectionContextMenu:c,preventScrolling:L,noDragClassName:gn,noWheelClassName:Mr,noPanClassName:zr,disableKeyboardA11y:Pr,onViewportChange:Tr,isControlledViewport:!!On,children:f.jsxs(pE,{children:[f.jsx(dE,{edgeTypes:t,onEdgeClick:o,onEdgeDoubleClick:s,onReconnect:je,onReconnectStart:Vt,onReconnectEnd:jt,onlyRenderVisibleElements:A,onEdgeContextMenu:J,onEdgeMouseEnter:Z,onEdgeMouseMove:re,onEdgeMouseLeave:le,reconnectRadius:ie,defaultMarkerColor:M,noPanClassName:zr,disableKeyboardA11y:Pr,rfId:Ko}),f.jsx(SE,{style:w,type:y,component:k,containerStyle:m}),f.jsx("div",{className:"react-flow__edgelabel-renderer"}),f.jsx(X_,{nodeTypes:e,onNodeClick:r,onNodeDoubleClick:i,onNodeMouseEnter:l,onNodeMouseMove:a,onNodeMouseLeave:u,onNodeContextMenu:p,nodeClickDistance:G,onlyRenderVisibleElements:A,noPanClassName:zr,noDragClassName:gn,disableKeyboardA11y:Pr,nodeExtent:rl,rfId:Ko}),f.jsx("div",{className:"react-flow__viewport-portal"})]})})}nm.displayName="GraphView";const EE=z.memo(nm),Ff=({nodes:e,edges:t,defaultNodes:n,defaultEdges:r,width:o,height:i,fitView:s,fitViewOptions:l,minZoom:a=.5,maxZoom:u=2,nodeOrigin:p,nodeExtent:c,zIndexMode:d="basic"}={})=>{const x=new Map,y=new Map,w=new Map,k=new Map,m=r??t??[],g=n??e??[],h=p??[0,0],v=c??To;f0(w,k,m);const _=tu(g,x,y,{nodeOrigin:h,nodeExtent:v,zIndexMode:d});let S=[0,0,1];if(s&&o&&i){const E=Yo(x,{filter:T=>!!((T.width||T.initialWidth)&&(T.height||T.initialHeight))}),{x:b,y:A,zoom:D}=dc(E,o,i,a,u,(l==null?void 0:l.padding)??.1);S=[b,A,D]}return{rfId:"1",width:o??0,height:i??0,transform:S,nodes:g,nodesInitialized:_,nodeLookup:x,parentLookup:y,edges:m,edgeLookup:k,connectionLookup:w,onNodesChange:null,onEdgesChange:null,hasDefaultNodes:n!==void 0,hasDefaultEdges:r!==void 0,panZoom:null,minZoom:a,maxZoom:u,translateExtent:To,nodeExtent:v,nodesSelectionActive:!1,userSelectionActive:!1,userSelectionRect:null,connectionMode:wr.Strict,domNode:null,paneDragging:!1,noPanClassName:"nopan",nodeOrigin:h,nodeDragThreshold:1,connectionDragThreshold:1,snapGrid:[15,15],snapToGrid:!1,nodesDraggable:!0,nodesConnectable:!0,nodesFocusable:!0,edgesFocusable:!0,edgesReconnectable:!0,elementsSelectable:!0,elevateNodesOnSelect:!0,elevateEdgesOnSelect:!0,selectNodesOnDrag:!0,multiSelectionActive:!1,fitViewQueued:s??!1,fitViewOptions:l,fitViewResolver:null,connection:{...Qg},connectionClickStartHandle:null,connectOnClick:!0,ariaLiveMessage:"",autoPanOnConnect:!0,autoPanOnNodeDrag:!0,autoPanOnNodeFocus:!0,autoPanSpeed:15,connectionRadius:20,onError:_S,isValidConnection:void 0,onSelectionChangeHandlers:[],lib:"react",debug:!1,ariaLabelConfig:Xg,zIndexMode:d,onNodesChangeMiddlewareMap:new Map,onEdgesChangeMiddlewareMap:new Map}},CE=({nodes:e,edges:t,defaultNodes:n,defaultEdges:r,width:o,height:i,fitView:s,fitViewOptions:l,minZoom:a,maxZoom:u,nodeOrigin:p,nodeExtent:c,zIndexMode:d})=>Vk((x,y)=>{async function w(){const{nodeLookup:k,panZoom:m,fitViewOptions:g,fitViewResolver:h,width:v,height:_,minZoom:S,maxZoom:E}=y();m&&(await SS({nodes:k,width:v,height:_,panZoom:m,minZoom:S,maxZoom:E},g),h==null||h.resolve(!0),x({fitViewResolver:null}))}return{...Ff({nodes:e,edges:t,width:o,height:i,fitView:s,fitViewOptions:l,minZoom:a,maxZoom:u,nodeOrigin:p,nodeExtent:c,defaultNodes:n,defaultEdges:r,zIndexMode:d}),setNodes:k=>{const{nodeLookup:m,parentLookup:g,nodeOrigin:h,elevateNodesOnSelect:v,fitViewQueued:_,zIndexMode:S}=y(),E=tu(k,m,g,{nodeOrigin:h,nodeExtent:c,elevateNodesOnSelect:v,checkEquality:!0,zIndexMode:S});_&&E?(w(),x({nodes:k,nodesInitialized:E,fitViewQueued:!1,fitViewOptions:void 0})):x({nodes:k,nodesInitialized:E})},setEdges:k=>{const{connectionLookup:m,edgeLookup:g}=y();f0(m,g,k),x({edges:k})},setDefaultNodesAndEdges:(k,m)=>{if(k){const{setNodes:g}=y();g(k),x({hasDefaultNodes:!0})}if(m){const{setEdges:g}=y();g(m),x({hasDefaultEdges:!0})}},updateNodeInternals:k=>{const{triggerNodeChanges:m,nodeLookup:g,parentLookup:h,domNode:v,nodeOrigin:_,nodeExtent:S,debug:E,fitViewQueued:b,zIndexMode:A}=y(),{changes:D,updatedInternals:T}=US(k,g,h,v,_,S,A);T&&(FS(g,h,{nodeOrigin:_,nodeExtent:S,zIndexMode:A}),b?(w(),x({fitViewQueued:!1,fitViewOptions:void 0})):x({}),(D==null?void 0:D.length)>0&&(E&&console.log("React Flow: trigger node changes",D),m==null||m(D)))},updateNodePositions:(k,m=!1)=>{const g=[];let h=[];const{nodeLookup:v,triggerNodeChanges:_,connection:S,updateConnection:E,onNodesChangeMiddlewareMap:b}=y();for(const[A,D]of k){const T=v.get(A),I=!!(T!=null&&T.expandParent&&(T!=null&&T.parentId)&&(D!=null&&D.position)),P={id:A,type:"position",position:I?{x:Math.max(0,D.position.x),y:Math.max(0,D.position.y)}:D.position,dragging:m};if(T&&S.inProgress&&S.fromNode.id===T.id){const C=Ln(T,S.fromHandle,q.Left,!0);E({...S,from:C})}I&&T.parentId&&g.push({id:A,parentId:T.parentId,rect:{...D.internals.positionAbsolute,width:D.measured.width??0,height:D.measured.height??0}}),h.push(P)}if(g.length>0){const{parentLookup:A,nodeOrigin:D}=y(),T=yc(g,v,A,D);h.push(...T)}for(const A of b.values())h=A(h);_(h)},triggerNodeChanges:k=>{const{onNodesChange:m,setNodes:g,nodes:h,hasDefaultNodes:v,debug:_}=y();if(k!=null&&k.length){if(v){const S=P0(k,h);g(S)}_&&console.log("React Flow: trigger node changes",k),m==null||m(k)}},triggerEdgeChanges:k=>{const{onEdgesChange:m,setEdges:g,edges:h,hasDefaultEdges:v,debug:_}=y();if(k!=null&&k.length){if(v){const S=T0(k,h);g(S)}_&&console.log("React Flow: trigger edge changes",k),m==null||m(k)}},addSelectedNodes:k=>{const{multiSelectionActive:m,edgeLookup:g,nodeLookup:h,triggerNodeChanges:v,triggerEdgeChanges:_}=y();if(m){const S=k.map(E=>xn(E,!0));v(S);return}v(nr(h,new Set([...k]),!0)),_(nr(g))},addSelectedEdges:k=>{const{multiSelectionActive:m,edgeLookup:g,nodeLookup:h,triggerNodeChanges:v,triggerEdgeChanges:_}=y();if(m){const S=k.map(E=>xn(E,!0));_(S);return}_(nr(g,new Set([...k]))),v(nr(h,new Set,!0))},unselectNodesAndEdges:({nodes:k,edges:m}={})=>{const{edges:g,nodes:h,nodeLookup:v,triggerNodeChanges:_,triggerEdgeChanges:S}=y(),E=k||h,b=m||g,A=[];for(const T of E){if(!T.selected)continue;const I=v.get(T.id);I&&(I.selected=!1),A.push(xn(T.id,!1))}const D=[];for(const T of b)T.selected&&D.push(xn(T.id,!1));_(A),S(D)},setMinZoom:k=>{const{panZoom:m,maxZoom:g}=y();m==null||m.setScaleExtent([k,g]),x({minZoom:k})},setMaxZoom:k=>{const{panZoom:m,minZoom:g}=y();m==null||m.setScaleExtent([g,k]),x({maxZoom:k})},setTranslateExtent:k=>{var m;(m=y().panZoom)==null||m.setTranslateExtent(k),x({translateExtent:k})},resetSelectedElements:()=>{const{edges:k,nodes:m,triggerNodeChanges:g,triggerEdgeChanges:h,elementsSelectable:v}=y();if(!v)return;const _=m.reduce((E,b)=>b.selected?[...E,xn(b.id,!1)]:E,[]),S=k.reduce((E,b)=>b.selected?[...E,xn(b.id,!1)]:E,[]);g(_),h(S)},setNodeExtent:k=>{const{nodes:m,nodeLookup:g,parentLookup:h,nodeOrigin:v,elevateNodesOnSelect:_,nodeExtent:S,zIndexMode:E}=y();k[0][0]===S[0][0]&&k[0][1]===S[0][1]&&k[1][0]===S[1][0]&&k[1][1]===S[1][1]||(tu(m,g,h,{nodeOrigin:v,nodeExtent:k,elevateNodesOnSelect:_,checkEquality:!1,zIndexMode:E}),x({nodeExtent:k}))},panBy:k=>{const{transform:m,width:g,height:h,panZoom:v,translateExtent:_}=y();return YS({delta:k,panZoom:v,transform:m,translateExtent:_,width:g,height:h})},setCenter:async(k,m,g)=>{const{width:h,height:v,maxZoom:_,panZoom:S}=y();if(!S)return Promise.resolve(!1);const E=typeof(g==null?void 0:g.zoom)<"u"?g.zoom:_;return await S.setViewport({x:h/2-k*E,y:v/2-m*E,zoom:E},{duration:g==null?void 0:g.duration,ease:g==null?void 0:g.ease,interpolate:g==null?void 0:g.interpolate}),Promise.resolve(!0)},cancelConnection:()=>{x({connection:{...Qg}})},updateConnection:k=>{x({connection:k})},reset:()=>x({...Ff()})}},Object.is);function bE({initialNodes:e,initialEdges:t,defaultNodes:n,defaultEdges:r,initialWidth:o,initialHeight:i,initialMinZoom:s,initialMaxZoom:l,initialFitViewOptions:a,fitView:u,nodeOrigin:p,nodeExtent:c,zIndexMode:d,children:x}){const[y]=z.useState(()=>CE({nodes:e,edges:t,defaultNodes:n,defaultEdges:r,width:o,height:i,fitView:u,minZoom:s,maxZoom:l,fitViewOptions:a,nodeOrigin:p,nodeExtent:c,zIndexMode:d}));return f.jsx(Wk,{value:y,children:f.jsx(p_,{children:x})})}function NE({children:e,nodes:t,edges:n,defaultNodes:r,defaultEdges:o,width:i,height:s,fitView:l,fitViewOptions:a,minZoom:u,maxZoom:p,nodeOrigin:c,nodeExtent:d,zIndexMode:x}){return z.useContext(Js)?f.jsx(f.Fragment,{children:e}):f.jsx(bE,{initialNodes:t,initialEdges:n,defaultNodes:r,defaultEdges:o,initialWidth:i,initialHeight:s,fitView:l,initialFitViewOptions:a,initialMinZoom:u,initialMaxZoom:p,nodeOrigin:c,nodeExtent:d,zIndexMode:x,children:e})}const jE={width:"100%",height:"100%",overflow:"hidden",position:"relative",zIndex:0};function ME({nodes:e,edges:t,defaultNodes:n,defaultEdges:r,className:o,nodeTypes:i,edgeTypes:s,onNodeClick:l,onEdgeClick:a,onInit:u,onMove:p,onMoveStart:c,onMoveEnd:d,onConnect:x,onConnectStart:y,onConnectEnd:w,onClickConnectStart:k,onClickConnectEnd:m,onNodeMouseEnter:g,onNodeMouseMove:h,onNodeMouseLeave:v,onNodeContextMenu:_,onNodeDoubleClick:S,onNodeDragStart:E,onNodeDrag:b,onNodeDragStop:A,onNodesDelete:D,onEdgesDelete:T,onDelete:I,onSelectionChange:P,onSelectionDragStart:C,onSelectionDrag:L,onSelectionDragStop:M,onSelectionContextMenu:R,onSelectionStart:N,onSelectionEnd:j,onBeforeDelete:$,connectionMode:O,connectionLineType:B=Zt.Bezier,connectionLineStyle:W,connectionLineComponent:V,connectionLineContainerStyle:Y,deleteKeyCode:X="Backspace",selectionKeyCode:Q="Shift",selectionOnDrag:H=!1,selectionMode:K=Io.Full,panActivationKeyCode:ee="Space",multiSelectionKeyCode:G=Lo()?"Meta":"Control",zoomActivationKeyCode:J=Lo()?"Meta":"Control",snapToGrid:Z,snapGrid:re,onlyRenderVisibleElements:le=!1,selectNodesOnDrag:ie,nodesDraggable:je,autoPanOnNodeFocus:Vt,nodesConnectable:jt,nodesFocusable:gn,nodeOrigin:Mr=M0,edgesFocusable:zr,edgesReconnectable:Pr,elementsSelectable:rl=!0,defaultViewport:Ko=r_,minZoom:On=.5,maxZoom:Tr=2,translateExtent:kc=To,preventScrolling:um=!0,nodeExtent:ol,defaultMarkerColor:cm="#b1b1b7",zoomOnScroll:dm=!0,zoomOnPinch:fm=!0,panOnScroll:pm=!1,panOnScrollSpeed:hm=.5,panOnScrollMode:gm=bn.Free,zoomOnDoubleClick:mm=!0,panOnDrag:ym=!0,onPaneClick:xm,onPaneMouseEnter:vm,onPaneMouseMove:wm,onPaneMouseLeave:Sm,onPaneScroll:km,onPaneContextMenu:_m,paneClickDistance:Em=1,nodeClickDistance:Cm=0,children:bm,onReconnect:Nm,onReconnectStart:jm,onReconnectEnd:Mm,onEdgeContextMenu:zm,onEdgeDoubleClick:Pm,onEdgeMouseEnter:Tm,onEdgeMouseMove:Im,onEdgeMouseLeave:Rm,reconnectRadius:Lm=10,onNodesChange:Am,onEdgesChange:$m,noDragClassName:Dm="nodrag",noWheelClassName:Om="nowheel",noPanClassName:_c="nopan",fitView:Ec,fitViewOptions:Cc,connectOnClick:Bm,attributionPosition:Fm,proOptions:Hm,defaultEdgeOptions:Vm,elevateNodesOnSelect:Wm=!0,elevateEdgesOnSelect:Um=!1,disableKeyboardA11y:bc=!1,autoPanOnConnect:Ym,autoPanOnNodeDrag:Xm,autoPanSpeed:Qm,connectionRadius:Gm,isValidConnection:Km,onError:Zm,style:qm,id:Nc,nodeDragThreshold:Jm,connectionDragThreshold:ey,viewport:ty,onViewportChange:ny,width:ry,height:oy,colorMode:iy="light",debug:sy,onScroll:Zo,ariaLabelConfig:ly,zIndexMode:jc="basic",...ay},uy){const il=Nc||"1",cy=l_(iy),dy=z.useCallback(Mc=>{Mc.currentTarget.scrollTo({top:0,left:0,behavior:"instant"}),Zo==null||Zo(Mc)},[Zo]);return f.jsx("div",{"data-testid":"rf__wrapper",...ay,onScroll:dy,style:{...qm,...jE},ref:uy,className:we(["react-flow",o,cy]),id:Nc,role:"application",children:f.jsxs(NE,{nodes:e,edges:t,width:ry,height:oy,fitView:Ec,fitViewOptions:Cc,minZoom:On,maxZoom:Tr,nodeOrigin:Mr,nodeExtent:ol,zIndexMode:jc,children:[f.jsx(EE,{onInit:u,onNodeClick:l,onEdgeClick:a,onNodeMouseEnter:g,onNodeMouseMove:h,onNodeMouseLeave:v,onNodeContextMenu:_,onNodeDoubleClick:S,nodeTypes:i,edgeTypes:s,connectionLineType:B,connectionLineStyle:W,connectionLineComponent:V,connectionLineContainerStyle:Y,selectionKeyCode:Q,selectionOnDrag:H,selectionMode:K,deleteKeyCode:X,multiSelectionKeyCode:G,panActivationKeyCode:ee,zoomActivationKeyCode:J,onlyRenderVisibleElements:le,defaultViewport:Ko,translateExtent:kc,minZoom:On,maxZoom:Tr,preventScrolling:um,zoomOnScroll:dm,zoomOnPinch:fm,zoomOnDoubleClick:mm,panOnScroll:pm,panOnScrollSpeed:hm,panOnScrollMode:gm,panOnDrag:ym,onPaneClick:xm,onPaneMouseEnter:vm,onPaneMouseMove:wm,onPaneMouseLeave:Sm,onPaneScroll:km,onPaneContextMenu:_m,paneClickDistance:Em,nodeClickDistance:Cm,onSelectionContextMenu:R,onSelectionStart:N,onSelectionEnd:j,onReconnect:Nm,onReconnectStart:jm,onReconnectEnd:Mm,onEdgeContextMenu:zm,onEdgeDoubleClick:Pm,onEdgeMouseEnter:Tm,onEdgeMouseMove:Im,onEdgeMouseLeave:Rm,reconnectRadius:Lm,defaultMarkerColor:cm,noDragClassName:Dm,noWheelClassName:Om,noPanClassName:_c,rfId:il,disableKeyboardA11y:bc,nodeExtent:ol,viewport:ty,onViewportChange:ny}),f.jsx(s_,{nodes:e,edges:t,defaultNodes:n,defaultEdges:r,onConnect:x,onConnectStart:y,onConnectEnd:w,onClickConnectStart:k,onClickConnectEnd:m,nodesDraggable:je,autoPanOnNodeFocus:Vt,nodesConnectable:jt,nodesFocusable:gn,edgesFocusable:zr,edgesReconnectable:Pr,elementsSelectable:rl,elevateNodesOnSelect:Wm,elevateEdgesOnSelect:Um,minZoom:On,maxZoom:Tr,nodeExtent:ol,onNodesChange:Am,onEdgesChange:$m,snapToGrid:Z,snapGrid:re,connectionMode:O,translateExtent:kc,connectOnClick:Bm,defaultEdgeOptions:Vm,fitView:Ec,fitViewOptions:Cc,onNodesDelete:D,onEdgesDelete:T,onDelete:I,onNodeDragStart:E,onNodeDrag:b,onNodeDragStop:A,onSelectionDrag:L,onSelectionDragStart:C,onSelectionDragStop:M,onMove:p,onMoveStart:c,onMoveEnd:d,noPanClassName:_c,nodeOrigin:Mr,rfId:il,autoPanOnConnect:Ym,autoPanOnNodeDrag:Xm,autoPanSpeed:Qm,onError:Zm,connectionRadius:Gm,isValidConnection:Km,selectNodesOnDrag:ie,nodeDragThreshold:Jm,connectionDragThreshold:ey,onBeforeDelete:$,debug:sy,ariaLabelConfig:ly,zIndexMode:jc}),f.jsx(n_,{onSelectionChange:P}),bm,f.jsx(Zk,{proOptions:Hm,position:Fm}),f.jsx(Kk,{rfId:il,disableKeyboardA11y:bc})]})})}var zE=I0(ME);function PE(e){const[t,n]=z.useState(e),r=z.useCallback(o=>n(i=>P0(o,i)),[]);return[t,n,r]}function TE(e){const[t,n]=z.useState(e),r=z.useCallback(o=>n(i=>T0(o,i)),[]);return[t,n,r]}function IE({dimensions:e,lineWidth:t,variant:n,className:r}){return f.jsx("path",{strokeWidth:t,d:`M${e[0]/2} 0 V${e[1]} M0 ${e[1]/2} H${e[0]}`,className:we(["react-flow__background-pattern",n,r])})}function RE({radius:e,className:t}){return f.jsx("circle",{cx:e,cy:e,r:e,className:we(["react-flow__background-pattern","dots",t])})}var un;(function(e){e.Lines="lines",e.Dots="dots",e.Cross="cross"})(un||(un={}));const LE={[un.Dots]:1,[un.Lines]:1,[un.Cross]:6},AE=e=>({transform:e.transform,patternId:`pattern-${e.rfId}`});function rm({id:e,variant:t=un.Dots,gap:n=20,size:r,lineWidth:o=1,offset:i=0,color:s,bgColor:l,style:a,className:u,patternClassName:p}){const c=z.useRef(null),{transform:d,patternId:x}=ne(AE,fe),y=r||LE[t],w=t===un.Dots,k=t===un.Cross,m=Array.isArray(n)?n:[n,n],g=[m[0]*d[2]||1,m[1]*d[2]||1],h=y*d[2],v=Array.isArray(i)?i:[i,i],_=k?[h,h]:g,S=[v[0]*d[2]||1+_[0]/2,v[1]*d[2]||1+_[1]/2],E=`${x}${e||""}`;return f.jsxs("svg",{className:we(["react-flow__background",u]),style:{...a,...tl,"--xy-background-color-props":l,"--xy-background-pattern-color-props":s},ref:c,"data-testid":"rf__background",children:[f.jsx("pattern",{id:E,x:d[0]%g[0],y:d[1]%g[1],width:g[0],height:g[1],patternUnits:"userSpaceOnUse",patternTransform:`translate(-${S[0]},-${S[1]})`,children:w?f.jsx(RE,{radius:h/2,className:p}):f.jsx(IE,{dimensions:_,lineWidth:o,variant:t,className:p})}),f.jsx("rect",{x:"0",y:"0",width:"100%",height:"100%",fill:`url(#${E})`})]})}rm.displayName="Background";const $E=z.memo(rm);function DE(){return f.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 32",children:f.jsx("path",{d:"M32 18.133H18.133V32h-4.266V18.133H0v-4.266h13.867V0h4.266v13.867H32z"})})}function OE(){return f.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 5",children:f.jsx("path",{d:"M0 0h32v4.2H0z"})})}function BE(){return f.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 30",children:f.jsx("path",{d:"M3.692 4.63c0-.53.4-.938.939-.938h5.215V0H4.708C2.13 0 0 2.054 0 4.63v5.216h3.692V4.631zM27.354 0h-5.2v3.692h5.17c.53 0 .984.4.984.939v5.215H32V4.631A4.624 4.624 0 0027.354 0zm.954 24.83c0 .532-.4.94-.939.94h-5.215v3.768h5.215c2.577 0 4.631-2.13 4.631-4.707v-5.139h-3.692v5.139zm-23.677.94c-.531 0-.939-.4-.939-.94v-5.138H0v5.139c0 2.577 2.13 4.707 4.708 4.707h5.138V25.77H4.631z"})})}function FE(){return f.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 25 32",children:f.jsx("path",{d:"M21.333 10.667H19.81V7.619C19.81 3.429 16.38 0 12.19 0 8 0 4.571 3.429 4.571 7.619v3.048H3.048A3.056 3.056 0 000 13.714v15.238A3.056 3.056 0 003.048 32h18.285a3.056 3.056 0 003.048-3.048V13.714a3.056 3.056 0 00-3.048-3.047zM12.19 24.533a3.056 3.056 0 01-3.047-3.047 3.056 3.056 0 013.047-3.048 3.056 3.056 0 013.048 3.048 3.056 3.056 0 01-3.048 3.047zm4.724-13.866H7.467V7.619c0-2.59 2.133-4.724 4.723-4.724 2.591 0 4.724 2.133 4.724 4.724v3.048z"})})}function HE(){return f.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 25 32",children:f.jsx("path",{d:"M21.333 10.667H19.81V7.619C19.81 3.429 16.38 0 12.19 0c-4.114 1.828-1.37 2.133.305 2.438 1.676.305 4.42 2.59 4.42 5.181v3.048H3.047A3.056 3.056 0 000 13.714v15.238A3.056 3.056 0 003.048 32h18.285a3.056 3.056 0 003.048-3.048V13.714a3.056 3.056 0 00-3.048-3.047zM12.19 24.533a3.056 3.056 0 01-3.047-3.047 3.056 3.056 0 013.047-3.048 3.056 3.056 0 013.048 3.048 3.056 3.056 0 01-3.048 3.047z"})})}function _i({children:e,className:t,...n}){return f.jsx("button",{type:"button",className:we(["react-flow__controls-button",t]),...n,children:e})}const VE=e=>({isInteractive:e.nodesDraggable||e.nodesConnectable||e.elementsSelectable,minZoomReached:e.transform[2]<=e.minZoom,maxZoomReached:e.transform[2]>=e.maxZoom,ariaLabelConfig:e.ariaLabelConfig});function om({style:e,showZoom:t=!0,showFitView:n=!0,showInteractive:r=!0,fitViewOptions:o,onZoomIn:i,onZoomOut:s,onFitView:l,onInteractiveChange:a,className:u,children:p,position:c="bottom-left",orientation:d="vertical","aria-label":x}){const y=pe(),{isInteractive:w,minZoomReached:k,maxZoomReached:m,ariaLabelConfig:g}=ne(VE,fe),{zoomIn:h,zoomOut:v,fitView:_}=xc(),S=()=>{h(),i==null||i()},E=()=>{v(),s==null||s()},b=()=>{_(o),l==null||l()},A=()=>{y.setState({nodesDraggable:!w,nodesConnectable:!w,elementsSelectable:!w}),a==null||a(!w)},D=d==="horizontal"?"horizontal":"vertical";return f.jsxs(el,{className:we(["react-flow__controls",D,u]),position:c,style:e,"data-testid":"rf__controls","aria-label":x??g["controls.ariaLabel"],children:[t&&f.jsxs(f.Fragment,{children:[f.jsx(_i,{onClick:S,className:"react-flow__controls-zoomin",title:g["controls.zoomIn.ariaLabel"],"aria-label":g["controls.zoomIn.ariaLabel"],disabled:m,children:f.jsx(DE,{})}),f.jsx(_i,{onClick:E,className:"react-flow__controls-zoomout",title:g["controls.zoomOut.ariaLabel"],"aria-label":g["controls.zoomOut.ariaLabel"],disabled:k,children:f.jsx(OE,{})})]}),n&&f.jsx(_i,{className:"react-flow__controls-fitview",onClick:b,title:g["controls.fitView.ariaLabel"],"aria-label":g["controls.fitView.ariaLabel"],children:f.jsx(BE,{})}),r&&f.jsx(_i,{className:"react-flow__controls-interactive",onClick:A,title:g["controls.interactive.ariaLabel"],"aria-label":g["controls.interactive.ariaLabel"],children:w?f.jsx(HE,{}):f.jsx(FE,{})}),p]})}om.displayName="Controls";const WE=z.memo(om);function UE({id:e,x:t,y:n,width:r,height:o,style:i,color:s,strokeColor:l,strokeWidth:a,className:u,borderRadius:p,shapeRendering:c,selected:d,onClick:x}){const{background:y,backgroundColor:w}=i||{},k=s||y||w;return f.jsx("rect",{className:we(["react-flow__minimap-node",{selected:d},u]),x:t,y:n,rx:p,ry:p,width:r,height:o,style:{fill:k,stroke:l,strokeWidth:a},shapeRendering:c,onClick:x?m=>x(m,e):void 0})}const YE=z.memo(UE),XE=e=>e.nodes.map(t=>t.id),Fl=e=>e instanceof Function?e:()=>e;function QE({nodeStrokeColor:e,nodeColor:t,nodeClassName:n="",nodeBorderRadius:r=5,nodeStrokeWidth:o,nodeComponent:i=YE,onClick:s}){const l=ne(XE,fe),a=Fl(t),u=Fl(e),p=Fl(n),c=typeof window>"u"||window.chrome?"crispEdges":"geometricPrecision";return f.jsx(f.Fragment,{children:l.map(d=>f.jsx(KE,{id:d,nodeColorFunc:a,nodeStrokeColorFunc:u,nodeClassNameFunc:p,nodeBorderRadius:r,nodeStrokeWidth:o,NodeComponent:i,onClick:s,shapeRendering:c},d))})}function GE({id:e,nodeColorFunc:t,nodeStrokeColorFunc:n,nodeClassNameFunc:r,nodeBorderRadius:o,nodeStrokeWidth:i,shapeRendering:s,NodeComponent:l,onClick:a}){const{node:u,x:p,y:c,width:d,height:x}=ne(y=>{const w=y.nodeLookup.get(e);if(!w)return{node:void 0,x:0,y:0,width:0,height:0};const k=w.internals.userNode,{x:m,y:g}=w.internals.positionAbsolute,{width:h,height:v}=Ht(k);return{node:k,x:m,y:g,width:h,height:v}},fe);return!u||u.hidden||!t0(u)?null:f.jsx(l,{x:p,y:c,width:d,height:x,style:u.style,selected:!!u.selected,className:r(u),color:t(u),borderRadius:o,strokeColor:n(u),strokeWidth:i,shapeRendering:s,onClick:a,id:u.id})}const KE=z.memo(GE);var ZE=z.memo(QE);const qE=200,JE=150,eC=e=>!e.hidden,tC=e=>{const t={x:-e.transform[0]/e.transform[2],y:-e.transform[1]/e.transform[2],width:e.width/e.transform[2],height:e.height/e.transform[2]};return{viewBB:t,boundingRect:e.nodeLookup.size>0?e0(Yo(e.nodeLookup,{filter:eC}),t):t,rfId:e.rfId,panZoom:e.panZoom,translateExtent:e.translateExtent,flowWidth:e.width,flowHeight:e.height,ariaLabelConfig:e.ariaLabelConfig}},nC="react-flow__minimap-desc";function im({style:e,className:t,nodeStrokeColor:n,nodeColor:r,nodeClassName:o="",nodeBorderRadius:i=5,nodeStrokeWidth:s,nodeComponent:l,bgColor:a,maskColor:u,maskStrokeColor:p,maskStrokeWidth:c,position:d="bottom-right",onClick:x,onNodeClick:y,pannable:w=!1,zoomable:k=!1,ariaLabel:m,inversePan:g,zoomStep:h=1,offsetScale:v=5}){const _=pe(),S=z.useRef(null),{boundingRect:E,viewBB:b,rfId:A,panZoom:D,translateExtent:T,flowWidth:I,flowHeight:P,ariaLabelConfig:C}=ne(tC,fe),L=(e==null?void 0:e.width)??qE,M=(e==null?void 0:e.height)??JE,R=E.width/L,N=E.height/M,j=Math.max(R,N),$=j*L,O=j*M,B=v*j,W=E.x-($-E.width)/2-B,V=E.y-(O-E.height)/2-B,Y=$+B*2,X=O+B*2,Q=`${nC}-${A}`,H=z.useRef(0),K=z.useRef();H.current=j,z.useEffect(()=>{if(S.current&&D)return K.current=tk({domNode:S.current,panZoom:D,getTransform:()=>_.getState().transform,getViewScale:()=>H.current}),()=>{var Z;(Z=K.current)==null||Z.destroy()}},[D]),z.useEffect(()=>{var Z;(Z=K.current)==null||Z.update({translateExtent:T,width:I,height:P,inversePan:g,pannable:w,zoomStep:h,zoomable:k})},[w,k,g,h,T,I,P]);const ee=x?Z=>{var ie;const[re,le]=((ie=K.current)==null?void 0:ie.pointer(Z))||[0,0];x(Z,{x:re,y:le})}:void 0,G=y?z.useCallback((Z,re)=>{const le=_.getState().nodeLookup.get(re).internals.userNode;y(Z,le)},[]):void 0,J=m??C["minimap.ariaLabel"];return f.jsx(el,{position:d,style:{...e,"--xy-minimap-background-color-props":typeof a=="string"?a:void 0,"--xy-minimap-mask-background-color-props":typeof u=="string"?u:void 0,"--xy-minimap-mask-stroke-color-props":typeof p=="string"?p:void 0,"--xy-minimap-mask-stroke-width-props":typeof c=="number"?c*j:void 0,"--xy-minimap-node-background-color-props":typeof r=="string"?r:void 0,"--xy-minimap-node-stroke-color-props":typeof n=="string"?n:void 0,"--xy-minimap-node-stroke-width-props":typeof s=="number"?s:void 0},className:we(["react-flow__minimap",t]),"data-testid":"rf__minimap",children:f.jsxs("svg",{width:L,height:M,viewBox:`${W} ${V} ${Y} ${X}`,className:"react-flow__minimap-svg",role:"img","aria-labelledby":Q,ref:S,onClick:ee,children:[J&&f.jsx("title",{id:Q,children:J}),f.jsx(ZE,{onClick:G,nodeColor:r,nodeStrokeColor:n,nodeBorderRadius:i,nodeClassName:o,nodeStrokeWidth:s,nodeComponent:l}),f.jsx("path",{className:"react-flow__minimap-mask",d:`M${W-B},${V-B}h${Y+B*2}v${X+B*2}h${-Y-B*2}z - M${b.x},${b.y}h${b.width}v${b.height}h${-b.width}z`,fillRule:"evenodd",pointerEvents:"none"})]})})}im.displayName="MiniMap";z.memo(im);const rC=e=>t=>e?`${Math.max(1/t.transform[2],1)}`:void 0,oC={[An.Line]:"right",[An.Handle]:"bottom-right"};function iC({nodeId:e,position:t,variant:n=An.Handle,className:r,style:o=void 0,children:i,color:s,minWidth:l=10,minHeight:a=10,maxWidth:u=Number.MAX_VALUE,maxHeight:p=Number.MAX_VALUE,keepAspectRatio:c=!1,resizeDirection:d,autoScale:x=!0,shouldResize:y,onResizeStart:w,onResize:k,onResizeEnd:m}){const g=$0(),h=typeof e=="string"?e:g,v=pe(),_=z.useRef(null),S=n===An.Handle,E=ne(z.useCallback(rC(S&&x),[S,x]),fe),b=z.useRef(null),A=t??oC[n];z.useEffect(()=>{if(!(!_.current||!h))return b.current||(b.current=yk({domNode:_.current,nodeId:h,getStoreItems:()=>{const{nodeLookup:T,transform:I,snapGrid:P,snapToGrid:C,nodeOrigin:L,domNode:M}=v.getState();return{nodeLookup:T,transform:I,snapGrid:P,snapToGrid:C,nodeOrigin:L,paneDomNode:M}},onChange:(T,I)=>{const{triggerNodeChanges:P,nodeLookup:C,parentLookup:L,nodeOrigin:M}=v.getState(),R=[],N={x:T.x,y:T.y},j=C.get(h);if(j&&j.expandParent&&j.parentId){const $=j.origin??M,O=T.width??j.measured.width??0,B=T.height??j.measured.height??0,W={id:j.id,parentId:j.parentId,rect:{width:O,height:B,...n0({x:T.x??j.position.x,y:T.y??j.position.y},{width:O,height:B},j.parentId,C,$)}},V=yc([W],C,L,M);R.push(...V),N.x=T.x?Math.max($[0]*O,T.x):void 0,N.y=T.y?Math.max($[1]*B,T.y):void 0}if(N.x!==void 0&&N.y!==void 0){const $={id:h,type:"position",position:{...N}};R.push($)}if(T.width!==void 0&&T.height!==void 0){const O={id:h,type:"dimensions",resizing:!0,setAttributes:d?d==="horizontal"?"width":"height":!0,dimensions:{width:T.width,height:T.height}};R.push(O)}for(const $ of I){const O={...$,type:"position"};R.push(O)}P(R)},onEnd:({width:T,height:I})=>{const P={id:h,type:"dimensions",resizing:!1,dimensions:{width:T,height:I}};v.getState().triggerNodeChanges([P])}})),b.current.update({controlPosition:A,boundaries:{minWidth:l,minHeight:a,maxWidth:u,maxHeight:p},keepAspectRatio:c,resizeDirection:d,onResizeStart:w,onResize:k,onResizeEnd:m,shouldResize:y}),()=>{var T;(T=b.current)==null||T.destroy()}},[A,l,a,u,p,c,w,k,m,y]);const D=A.split("-");return f.jsx("div",{className:we(["react-flow__resize-control","nodrag",...D,n,r]),ref:_,style:{...o,scale:E,...s&&{[S?"backgroundColor":"borderColor"]:s}},children:i})}const Hf=z.memo(iC);function sC({nodeId:e,isVisible:t=!0,handleClassName:n,handleStyle:r,lineClassName:o,lineStyle:i,color:s,minWidth:l=10,minHeight:a=10,maxWidth:u=Number.MAX_VALUE,maxHeight:p=Number.MAX_VALUE,keepAspectRatio:c=!1,autoScale:d=!0,shouldResize:x,onResizeStart:y,onResize:w,onResizeEnd:k}){return t?f.jsxs(f.Fragment,{children:[dk.map(m=>f.jsx(Hf,{className:o,style:i,nodeId:e,position:m,variant:An.Line,color:s,minWidth:l,minHeight:a,maxWidth:u,maxHeight:p,onResizeStart:y,keepAspectRatio:c,autoScale:d,shouldResize:x,onResize:w,onResizeEnd:k},m)),ck.map(m=>f.jsx(Hf,{className:n,style:r,nodeId:e,position:m,color:s,minWidth:l,minHeight:a,maxWidth:u,maxHeight:p,onResizeStart:y,keepAspectRatio:c,autoScale:d,shouldResize:x,onResize:w,onResizeEnd:k},m))]}):null}const ou={compute:"#10b981",database:"#8b5cf6",storage:"#6366f1",network:"#3b82f6",security:"#ef4444",serverless:"#f59e0b",cache:"#8b5cf6",queue:"#f97316",cdn:"#3b82f6",monitoring:"#06b6d4",ml:"#ec4899",analytics:"#a855f7",containers:"#14b8a6",streaming:"#f97316",orchestration:"#a78bfa"},lC={ec2:"compute",ecs:"compute",eks:"compute",emr:"compute",fargate:"compute",codepipeline:"compute",codecommit:"storage",codebuild:"compute",dms:"compute",migration_hub:"compute",compute_engine:"compute",gke:"containers",app_engine:"serverless",cloud_build:"compute",virtual_machines:"compute",aks:"containers",container_apps:"containers",azure_devops:"compute",azure_migrate:"compute",rds:"database",aurora:"database",dynamodb:"database",cloud_sql:"database",azure_sql:"database",cosmos_db:"database",redshift:"database",bigquery:"database",firestore:"database",spanner:"database",alloydb:"database",s3:"storage",cloud_storage:"storage",blob_storage:"storage",ebs:"storage",ecr:"storage",fsx:"storage",efs:"storage",artifact_registry:"storage",alb:"network",nlb:"network",route53:"network",cloud_load_balancing:"network",app_gateway:"network",cloud_dns:"network",direct_connect:"network",vpn:"network",azure_lb:"network",azure_dns:"network",cloud_interconnect:"network",api_management:"network",cloudfront:"cdn",cloud_cdn:"cdn",azure_cdn:"cdn",waf:"security",cognito:"security",kms:"security",cloudtrail:"security",guardduty:"security",shield:"security",security_hub:"security",config:"security",inspector:"security",cloud_armor:"security",firebase_auth:"security",azure_waf:"security",azure_ad:"security",azure_firewall:"security",azure_sentinel:"security",azure_policy:"security",lambda:"serverless",api_gateway:"serverless",cloud_functions:"serverless",cloud_run:"serverless",azure_functions:"serverless",step_functions:"serverless",glue:"serverless",app_service:"serverless",elasticache:"cache",memorystore:"cache",azure_cache:"cache",sqs:"queue",sns:"queue",pub_sub:"queue",service_bus:"queue",kinesis:"queue",eventbridge:"queue",cloudwatch:"monitoring",cloud_logging:"monitoring",azure_monitor:"monitoring",sagemaker:"ml",vertex_ai:"ml",azure_ml:"ml",athena:"analytics",dataproc:"analytics",data_factory:"analytics",synapse:"analytics",dataflow:"streaming",event_hubs:"streaming",cloud_composer:"orchestration",logic_apps:"orchestration",databricks_sql_warehouse:"analytics",databricks_cluster:"compute",databricks_job:"orchestration",databricks_pipeline:"streaming",databricks_model_serving:"ml",databricks_unity_catalog:"security",databricks_vector_search:"database",databricks_genie:"analytics",databricks_notebook:"compute",databricks_secret_scope:"security",databricks_dashboard:"analytics",databricks_volume:"storage"},Vf={compute:"M5 12H3l9-9 9 9h-2M5 12v7a2 2 0 002 2h10a2 2 0 002-2v-7",database:"M12 2C6.48 2 2 4.24 2 7v10c0 2.76 4.48 5 10 5s10-2.24 10-5V7c0-2.76-4.48-5-10-5zM2 12c0 2.76 4.48 5 10 5s10-2.24 10-5",storage:"M20 7H4a1 1 0 00-1 1v8a1 1 0 001 1h16a1 1 0 001-1V8a1 1 0 00-1-1zM4 12h16",network:"M12 2a10 10 0 100 20 10 10 0 000-20zm0 0a14.5 14.5 0 014 10 14.5 14.5 0 01-4 10 14.5 14.5 0 01-4-10A14.5 14.5 0 0112 2zM2 12h20",security:"M12 2l7 4v5c0 5.25-3.5 10.74-7 12-3.5-1.26-7-6.75-7-12V6l7-4z",serverless:"M13 2L3 14h9l-1 8 10-12h-9l1-8z",cache:"M4 4h16v4H4zM4 10h16v4H4zM4 16h16v4H4z",queue:"M4 6h16M4 12h16M4 18h16",cdn:"M12 2a10 10 0 100 20 10 10 0 000-20zm-1 17.93A8 8 0 013 12a8 8 0 018-7.93M12 2v20M2 12h20M4.22 7h15.56M4.22 17h15.56",monitoring:"M3 3v18h18M7 16l4-8 4 4 4-6",ml:"M12 2a4 4 0 014 4c0 1.95-1.4 3.57-3.24 3.9L12 14l-.76-4.1A4 4 0 018 6a4 4 0 014-4zM8 14h8M6 18h12M9 22h6",analytics:"M18 20V10M12 20V4M6 20v-6",containers:"M21 16V8a2 2 0 00-1-1.73l-7-4a2 2 0 00-2 0l-7 4A2 2 0 003 8v8a2 2 0 001 1.73l7 4a2 2 0 002 0l7-4A2 2 0 0021 16zM3.27 6.96L12 12l8.73-5.04M12 22.08V12",streaming:"M2 12c2-3 4-3 6 0s4 3 6 0 4-3 6 0 4 3 6 0",orchestration:"M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83"};function wc(e){return lC[e]||"compute"}function sm(e){return ou[e]||"#94a3b8"}function Sc(e){return Vf[e]||Vf.compute}function aC({data:e}){const t=e,n=wc(t.service),r=sm(n),o=Sc(n);return f.jsxs("div",{style:{background:"#ffffff",border:`2px solid ${r}`,borderRadius:10,padding:"8px 12px",color:"#0f172a",minWidth:160,position:"relative",boxShadow:"0 1px 3px rgba(0,0,0,0.08)"},children:[f.jsx(Cr,{type:"target",position:q.Top,style:{background:r}}),f.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6,marginBottom:4},children:[f.jsx("svg",{width:16,height:16,viewBox:"0 0 24 24",fill:"none",stroke:r,strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round",style:{display:"block",width:28,height:28,padding:5,borderRadius:6,background:`${r}22`},children:f.jsx("path",{d:o})}),f.jsx("span",{style:{fontSize:9,color:"#64748b",textTransform:"uppercase",letterSpacing:1},children:n})]}),f.jsx("div",{style:{fontWeight:600,fontSize:13,marginBottom:2,color:"#0f172a"},children:t.label}),f.jsxs("div",{style:{fontSize:11,color:"#64748b"},children:[t.service,f.jsx("span",{style:{marginLeft:6,padding:"1px 4px",borderRadius:3,background:"#e2e8f0",color:"#475569",fontSize:9,textTransform:"uppercase"},children:t.provider})]}),t.monthlyCost!=null&&t.monthlyCost>0&&f.jsxs("div",{style:{fontSize:10,color:"#2563eb",marginTop:4},children:["$",t.monthlyCost.toFixed(0),"/mo"]}),f.jsx(Cr,{type:"source",position:q.Bottom,style:{background:r}})]})}const uC=z.memo(aC);function cC({data:e,selected:t}){return f.jsxs(f.Fragment,{children:[f.jsx(sC,{color:e.dotColor,isVisible:t??!1,minWidth:200,minHeight:100,lineStyle:{borderWidth:1.5},handleStyle:{width:8,height:8,borderRadius:2}}),f.jsxs("div",{style:{position:"absolute",top:6,left:8,display:"inline-flex",alignItems:"center",gap:5,padding:"3px 10px 3px 7px",borderRadius:5,background:e.labelBg,border:`1px solid ${e.dotColor}30`,boxShadow:"0 1px 2px rgba(0,0,0,0.04)",pointerEvents:"none"},children:[f.jsx("span",{style:{width:7,height:7,borderRadius:"50%",background:e.dotColor,flexShrink:0}}),f.jsx("span",{style:{color:e.labelColor,fontSize:11,fontWeight:600,letterSpacing:"0.02em",whiteSpace:"nowrap",lineHeight:1},children:e.label})]})]})}function dC({components:e}){const[t,n]=z.useState(!1),r=z.useMemo(()=>{if(!e||e.length===0)return Object.keys(ou).map(i=>({category:i,count:0}));const o={};for(const i of e){const s=wc(i.service);o[s]=(o[s]||0)+1}return Object.entries(o).sort(([,i],[,s])=>s-i).map(([i,s])=>({category:i,count:s}))},[e]);return f.jsxs("div",{style:{position:"absolute",bottom:16,left:16,zIndex:10,background:"#ffffff",border:"1px solid #e2e8f0",borderRadius:8,padding:"8px 12px",fontSize:11,color:"#64748b",boxShadow:"0 1px 4px rgba(0,0,0,0.08)",maxHeight:t?"auto":260,overflowY:t?"visible":"auto"},children:[f.jsxs("div",{onClick:()=>n(o=>!o),style:{fontWeight:600,marginBottom:t?0:4,color:"#0f172a",cursor:"pointer",userSelect:"none",display:"flex",alignItems:"center",justifyContent:"space-between",gap:8},children:["Legend",f.jsx("span",{style:{fontSize:10,color:"#94a3b8"},children:t?"+":"-"})]}),!t&&r.map(({category:o,count:i})=>{const s=ou[o]||"#94a3b8",l=Sc(o);return f.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6,marginBottom:2},children:[f.jsx("svg",{width:12,height:12,viewBox:"0 0 24 24",fill:"none",stroke:s,strokeWidth:2.5,strokeLinecap:"round",strokeLinejoin:"round",style:{flexShrink:0},children:f.jsx("path",{d:l})}),f.jsx("span",{style:{textTransform:"capitalize"},children:o}),i>0&&f.jsxs("span",{style:{color:"#94a3b8",fontSize:10},children:["(",i,")"]})]},o)})]})}function fC({onExportSvg:e,onExportPng:t,showBoundaries:n,onToggleBoundaries:r}){const o={padding:"4px 10px",borderRadius:4,border:"1px solid #e2e8f0",background:"#ffffff",color:"#475569",cursor:"pointer",fontSize:11};return f.jsxs("div",{style:{position:"absolute",top:16,right:16,zIndex:10,display:"flex",gap:4,background:"#ffffff",padding:4,border:"1px solid #e2e8f0",borderRadius:8,boxShadow:"0 1px 4px rgba(0,0,0,0.08)"},children:[e&&f.jsx("button",{style:o,onClick:e,children:"Export SVG"}),t&&f.jsx("button",{style:o,onClick:t,children:"Export PNG"}),f.jsxs("button",{style:{...o,background:n?"#f1f5f9":"#ffffff"},onClick:r,children:[n?"Hide":"Show"," Boundaries"]})]})}const Wf={borderTop:"1px solid #e2e8f0",margin:"12px 0"},Ei={fontSize:11,fontWeight:600,color:"#64748b",textTransform:"uppercase",letterSpacing:"0.05em",marginBottom:8},Hl={display:"block",fontSize:12,fontWeight:600,color:"#64748b",marginBottom:5},Vr={width:"100%",boxSizing:"border-box",border:"1px solid #cbd5e1",borderRadius:6,padding:"8px 10px",color:"#0f172a",fontSize:13,outline:"none",background:"#ffffff"},Vl={display:"flex",justifyContent:"space-between",alignItems:"center",gap:10,color:"#475569",fontSize:13,marginBottom:7};function lm(e){return typeof e=="boolean"?e?"true":"false":e==null?"":String(e)}function pC(e,t){return Object.entries(e??{}).filter(([n,r])=>r!=null&&n!=="tags").map(([n,r])=>`${n}=${lm(r)}`).join(` -`)}function hC(e){const t=e==null?void 0:e.tags;return!t||typeof t!="object"||Array.isArray(t)?"":Object.entries(t).map(([n,r])=>`${n}=${lm(r)}`).join(` -`)}function gC(e){const t=e.trim();return t==="true"?!0:t==="false"?!1:t!==""&&!Number.isNaN(Number(t))?Number(t):e}function Uf(e){const t={};for(const n of e.split(` -`)){const r=n.trim();if(!r)continue;const o=r.indexOf("=");if(o===-1){t[r]=!0;continue}const i=r.slice(0,o).trim();i&&(t[i]=gC(r.slice(o+1)))}return t}function mC({component:e,cost:t,onClose:n,onApply:r,onDelete:o}){var S;const i=e!==null,[s,l]=z.useState(""),[a,u]=z.useState(""),[p,c]=z.useState("2"),[d,x]=z.useState(""),[y,w]=z.useState("");z.useEffect(()=>{e&&(l(e.label),u(e.description??""),c(String(e.tier??2)),x(pC(e.config)),w(hC(e.config)))},[e]);const k=e?wc(e.service):"compute",m=sm(k),g=Sc(k),h=(t==null?void 0:t.monthly)??null,v=z.useMemo(()=>{const E=Number(p);return Number.isFinite(E)?E:2},[p]),_=()=>{if(!e)return;const E=Uf(d),b=Uf(y);Object.keys(b).length>0&&(E.tags=b),r({...e,label:s.trim()||e.label,description:a,tier:v,config:E})};return f.jsxs("div",{style:{position:"absolute",top:0,right:0,width:340,height:"100%",background:"#ffffff",borderLeft:"1px solid #e2e8f0",transform:i?"translateX(0)":"translateX(100%)",transition:"transform 0.2s ease",zIndex:20,display:"flex",flexDirection:"column",overflow:"hidden",boxShadow:"-2px 0 8px rgba(0,0,0,0.06)"},children:[f.jsxs("div",{style:{padding:"16px 16px 12px",borderBottom:"1px solid #e2e8f0"},children:[f.jsxs("div",{style:{display:"flex",alignItems:"center",gap:10,marginBottom:8},children:[f.jsx("div",{style:{width:36,height:36,borderRadius:8,background:`${m}22`,border:`1.5px solid ${m}`,display:"flex",alignItems:"center",justifyContent:"center",flexShrink:0},children:f.jsx("svg",{width:20,height:20,viewBox:"0 0 24 24",fill:"none",stroke:m,strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round",style:{display:"block"},children:f.jsx("path",{d:g})})}),f.jsx("span",{style:{fontSize:16,fontWeight:700,color:"#0f172a",flex:1,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:(e==null?void 0:e.label)??"Resource"}),f.jsx("button",{onClick:n,style:{background:"none",border:"none",color:"#94a3b8",cursor:"pointer",fontSize:18,lineHeight:1,padding:"2px 4px",flexShrink:0},"aria-label":"Close panel",children:"x"})]}),f.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8},children:[f.jsx("span",{style:{background:"#f1f5f9",color:"#475569",borderRadius:4,fontSize:11,fontWeight:600,padding:"2px 8px",textTransform:"uppercase"},children:e==null?void 0:e.provider}),f.jsx("span",{style:{color:"#64748b",fontSize:12},children:e==null?void 0:e.service})]})]}),f.jsxs("div",{style:{flex:1,overflowY:"auto",padding:"12px 16px"},children:[f.jsx("div",{style:Ei,children:"Overview"}),f.jsx("label",{style:Hl,htmlFor:"resource-label",children:"Label"}),f.jsx("input",{id:"resource-label","aria-label":"Label",value:s,onChange:E=>l(E.target.value),style:{...Vr,marginBottom:10}}),f.jsx("label",{style:Hl,htmlFor:"resource-description",children:"Description"}),f.jsx("textarea",{id:"resource-description","aria-label":"Description",value:a,onChange:E=>u(E.target.value),rows:3,style:{...Vr,marginBottom:10,resize:"vertical",minHeight:72}}),f.jsx("label",{style:Hl,htmlFor:"resource-tier",children:"Tier"}),f.jsx("input",{id:"resource-tier","aria-label":"Tier",type:"number",value:p,onChange:E=>c(E.target.value),style:{...Vr,marginBottom:10}}),f.jsxs("div",{style:Vl,children:[f.jsx("span",{children:"Service"}),f.jsx("strong",{style:{color:"#0f172a"},children:e==null?void 0:e.service})]}),f.jsxs("div",{style:Vl,children:[f.jsx("span",{children:"Provider"}),f.jsx("strong",{style:{color:"#0f172a"},children:(S=e==null?void 0:e.provider)==null?void 0:S.toUpperCase()})]}),f.jsx("div",{style:Wf}),f.jsx("div",{style:Ei,children:"Cost"}),h!==null?f.jsxs("div",{style:Vl,children:[f.jsx("span",{children:"Monthly"}),f.jsxs("strong",{style:{color:"#2563eb"},children:["$",h.toLocaleString(void 0,{minimumFractionDigits:2,maximumFractionDigits:2})]})]}):f.jsx("p",{style:{color:"#94a3b8",fontSize:13},children:"No cost data"}),f.jsx("div",{style:Wf}),f.jsx("div",{style:Ei,children:"Configuration"}),f.jsx("textarea",{"aria-label":"Configuration",value:d,onChange:E=>x(E.target.value),rows:7,style:{...Vr,resize:"vertical",minHeight:140,fontFamily:"ui-monospace, SFMono-Regular, Menlo, monospace"}}),f.jsx("div",{style:{...Ei,marginTop:16},children:"Tags"}),f.jsx("textarea",{"aria-label":"Tags",value:y,onChange:E=>w(E.target.value),rows:5,style:{...Vr,resize:"vertical",minHeight:110,fontFamily:"ui-monospace, SFMono-Regular, Menlo, monospace"}})]}),f.jsxs("div",{style:{padding:12,borderTop:"1px solid #e2e8f0",display:"flex",gap:8},children:[f.jsx("button",{onClick:_,disabled:!e,style:{flex:1,border:"none",borderRadius:6,padding:"10px 12px",background:"#2563eb",color:"#ffffff",cursor:e?"pointer":"not-allowed",fontSize:14,fontWeight:700},children:"Apply"}),f.jsx("button",{onClick:()=>e&&o(e.id),disabled:!e,style:{border:"1px solid #fecaca",borderRadius:6,padding:"10px 12px",background:"#fef2f2",color:"#b91c1c",cursor:e?"pointer":"not-allowed",fontSize:14,fontWeight:700},children:"Delete"})]})]})}const Yf="/api",Wl={border:"1px solid #cbd5e1",background:"#ffffff",color:"#0f172a",borderRadius:6,padding:"7px 10px",cursor:"pointer",fontSize:12,fontWeight:600};function yC({provider:e,standardsResult:t,onAddResource:n,onAddModule:r,onCheckStandards:o}){const i=(e||"aws").toLowerCase(),[s,l]=z.useState(!0),[a,u]=z.useState("resources"),[p,c]=z.useState(""),[d,x]=z.useState([]),[y,w]=z.useState([]);z.useEffect(()=>{fetch(`${Yf}/catalog/services?provider=${encodeURIComponent(i)}`).then(g=>g.ok?g.json():null).then(g=>x((g==null?void 0:g.services)??[])).catch(()=>x([]))},[i]),z.useEffect(()=>{fetch(`${Yf}/modules`).then(g=>g.ok?g.json():null).then(g=>w((g==null?void 0:g.modules)??[])).catch(()=>w([]))},[]);const k=z.useMemo(()=>{const g=p.trim().toLowerCase();return g?d.filter(h=>[h.name,h.service_key,h.category,h.description??""].some(v=>v.toLowerCase().includes(g))):d},[d,p]),m=z.useMemo(()=>{const g=p.trim().toLowerCase(),h=y.filter(v=>v.provider.toLowerCase()===i);return g?h.filter(v=>[v.name,v.id,v.category,v.description??"",...v.tags??[]].some(_=>_.toLowerCase().includes(g))):h},[y,i,p]);return s?f.jsxs("div",{style:{position:"absolute",top:0,left:0,width:320,height:"100%",zIndex:14,background:"#ffffff",borderRight:"1px solid #e2e8f0",boxShadow:"2px 0 8px rgba(0,0,0,0.06)",display:"flex",flexDirection:"column"},children:[f.jsxs("div",{style:{padding:14,borderBottom:"1px solid #e2e8f0"},children:[f.jsxs("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:10},children:[f.jsx("div",{style:{fontSize:15,fontWeight:700,color:"#0f172a"},children:"Catalog"}),f.jsx("button",{onClick:()=>l(!1),style:{border:"none",background:"transparent",color:"#64748b",cursor:"pointer",fontSize:18},"aria-label":"Close catalog",children:"x"})]}),f.jsx("div",{style:{display:"grid",gridTemplateColumns:"1fr 1fr 1fr",gap:4,marginBottom:10},children:["resources","modules","standards"].map(g=>f.jsx("button",{onClick:()=>u(g),style:{...Wl,padding:"6px 4px",borderColor:a===g?"#2563eb":"#cbd5e1",color:a===g?"#2563eb":"#475569",background:a===g?"#eff6ff":"#ffffff",textTransform:"capitalize"},children:g},g))}),a!=="standards"&&f.jsx("input",{value:p,onChange:g=>c(g.target.value),placeholder:"Search",style:{width:"100%",boxSizing:"border-box",border:"1px solid #cbd5e1",borderRadius:6,padding:"8px 10px",color:"#0f172a",fontSize:13,outline:"none"}})]}),f.jsxs("div",{style:{flex:1,overflowY:"auto",padding:12},children:[a==="resources"&&k.map(g=>f.jsxs("button",{onClick:()=>n(g),style:{width:"100%",textAlign:"left",border:"1px solid #e2e8f0",background:"#ffffff",borderRadius:8,padding:10,marginBottom:8,cursor:"pointer"},children:[f.jsxs("div",{style:{display:"flex",justifyContent:"space-between",gap:8},children:[f.jsx("span",{style:{color:"#0f172a",fontSize:13,fontWeight:700},children:g.name}),f.jsx("span",{style:{color:"#64748b",fontSize:10,textTransform:"uppercase"},children:g.category.replace(/_/g," ")})]}),f.jsx("div",{style:{color:"#64748b",fontSize:11,marginTop:4},children:g.service_key})]},`${g.provider}:${g.service_key}`)),a==="resources"&&k.length===0&&f.jsxs("p",{style:{color:"#64748b",fontSize:13},children:["No resources found for ",i.toUpperCase(),"."]}),a==="modules"&&m.map(g=>f.jsxs("button",{onClick:()=>r(g.id),style:{width:"100%",textAlign:"left",border:"1px solid #bfdbfe",background:"#eff6ff",borderRadius:8,padding:10,marginBottom:8,cursor:"pointer"},children:[f.jsx("div",{style:{color:"#0f172a",fontSize:13,fontWeight:700},children:g.name}),f.jsx("div",{style:{color:"#475569",fontSize:12,marginTop:4,lineHeight:1.35},children:g.description}),f.jsx("div",{style:{color:"#2563eb",fontSize:11,marginTop:6,textTransform:"uppercase"},children:g.category})]},g.id)),a==="modules"&&m.length===0&&f.jsxs("p",{style:{color:"#64748b",fontSize:13},children:["No approved modules found for ",i.toUpperCase(),"."]}),a==="standards"&&f.jsxs(f.Fragment,{children:[f.jsx("button",{onClick:o,style:{...Wl,width:"100%",marginBottom:12},children:"Check Standards"}),!t&&f.jsx("p",{style:{color:"#64748b",fontSize:13},children:"No standards check has run."}),(t==null?void 0:t.passed)&&f.jsx("div",{style:{color:"#166534",background:"#dcfce7",borderRadius:8,padding:10,fontSize:13},children:"Standards passed."}),t&&!t.passed&&f.jsx("div",{children:t.violations.map((g,h)=>f.jsxs("div",{style:{border:"1px solid #fecaca",background:"#fef2f2",borderRadius:8,padding:10,marginBottom:8},children:[f.jsx("div",{style:{color:"#991b1b",fontSize:12,fontWeight:700},children:g.code.replace(/_/g," ")}),f.jsx("div",{style:{color:"#7f1d1d",fontSize:12,marginTop:4,lineHeight:1.4},children:g.message})]},`${g.code}:${h}`))})]})]})]}):f.jsx("button",{onClick:()=>l(!0),style:{...Wl,position:"absolute",left:16,top:16,zIndex:15,boxShadow:"0 1px 4px rgba(0,0,0,0.08)"},children:"Add Resource"})}const Xf=200,Ci=90,Qf=300,xC=240,yt=32,vC=36,Wr=4,Ul="/api",wC={0:"Edge / CDN",1:"Network / Ingress",2:"Application",3:"Data Layer",4:"Platform Services",5:"Platform Services"},SC={0:"edge",1:"subnet",2:"subnet",3:"subnet"},Yl={0:{border:"#60a5fa",bg:"rgba(219, 234, 254, 0.18)",labelColor:"#1d4ed8",labelBg:"rgba(219, 234, 254, 0.92)",dot:"#3b82f6"},1:{border:"#34d399",bg:"rgba(209, 250, 229, 0.18)",labelColor:"#047857",labelBg:"rgba(209, 250, 229, 0.92)",dot:"#10b981"},2:{border:"#fb923c",bg:"rgba(255, 237, 213, 0.18)",labelColor:"#9a3412",labelBg:"rgba(255, 237, 213, 0.92)",dot:"#f97316"},3:{border:"#a78bfa",bg:"rgba(237, 233, 254, 0.18)",labelColor:"#5b21b6",labelBg:"rgba(237, 233, 254, 0.92)",dot:"#8b5cf6"},4:{border:"#2dd4bf",bg:"rgba(204, 251, 241, 0.18)",labelColor:"#0f766e",labelBg:"rgba(204, 251, 241, 0.92)",dot:"#14b8a6"},5:{border:"#2dd4bf",bg:"rgba(204, 251, 241, 0.18)",labelColor:"#0f766e",labelBg:"rgba(204, 251, 241, 0.92)",dot:"#14b8a6"}},Hn={border:"#94a3b8",bg:"rgba(241, 245, 249, 0.35)",labelColor:"#475569",labelBg:"rgba(241, 245, 249, 0.92)",dot:"#94a3b8"},kC={cloudService:uC,boundaryGroup:cC};function iu(e){return JSON.parse(JSON.stringify(e))}function bi(e){return iu(e??{})}function Ni(e,t="resource"){let n=e.trim().toLowerCase().replace(/[^a-z0-9_-]+/g,"_").replace(/^[_-]+|[_-]+$/g,"");return n||(n=t),/^[a-z_]/.test(n)||(n=`${t}_${n}`),n}function Xl(e,t){let n=e,r=2;for(;t.has(n);)n=`${e}-${r}`,r+=1;return t.add(n),n}function _C(e){const t=e.toLowerCase();return t.includes("cdn")||t.includes("edge")?0:t.includes("network")||t.includes("security")?1:t.includes("database")||t.includes("cache")?3:t.includes("storage")||t.includes("analytics")||t.includes("data")?4:2}function Gf(e){return{x:360+e%3*260,y:80+Math.floor(e/3)*150}}function EC(e,t){if(t==="vpc")return Hn;const n=e.match(/^tier-(\d+)$/);return n&&Yl[parseInt(n[1])]||Yl[2]}function CC(e){const t={};for(const i of e){const s=i.tier??2;t[s]||(t[s]=[]),t[s].push(i.id)}const n=Object.keys(t).map(Number).sort(),r=[];for(const i of n)r.push({id:`tier-${i}`,kind:SC[i]||"subnet",label:wC[i]||`Tier ${i}`,component_ids:t[i]});const o=r.filter(i=>i.id!=="tier-0").flatMap(i=>i.component_ids);return o.length>=2&&r.unshift({id:"vpc",kind:"vpc",label:"VPC / Virtual Network",component_ids:o}),r}function bC(e,t,n){var y,w,k,m;const r=[],o=e.boundaries||[],i=o.length>0?o:CC(e.components),s=((w=(y=e.metadata)==null?void 0:y.canvas)==null?void 0:w.nodes)??{},l={};if(t){for(const g of i)if(g.kind!=="vpc")for(const h of g.component_ids)l[h]||(l[h]=g.id)}const a={};for(const g of e.components){const h=g.tier??2;a[h]||(a[h]=[]),a[h].push(g)}const u=Object.keys(a).map(Number).sort(),p={};let c=40;const d={};for(const g of u){d[g]=c;const h=Math.ceil(a[g].length/Wr);c+=xC+(h-1)*(Ci+60)}for(const g of u){const h=a[g],v=d[g];for(let _=0;_0){const g=i.find(v=>v.kind==="vpc");let h;if(g&&g.component_ids.length>0){const v=g.component_ids.map(D=>{var T;return((T=p[D])==null?void 0:T.x)??0}),_=g.component_ids.map(D=>{var T;return((T=p[D])==null?void 0:T.y)??0}),S=Math.min(...v)-yt,E=Math.min(..._)-yt-24-vC,b=Math.max(...v)+Xf+yt,A=Math.max(..._)+Ci+yt;h=`boundary-${g.id}`,x[g.id]={x:S,y:E},r.push({id:h,type:"boundaryGroup",position:{x:S,y:E},data:{label:g.label||g.id,labelColor:Hn.labelColor,labelBg:Hn.labelBg,dotColor:Hn.dot},style:{background:Hn.bg,border:`2px dashed ${Hn.border}`,borderRadius:16,padding:yt,width:b-S,height:A-E},zIndex:-2})}for(const v of i){if(v.kind==="vpc"||v.component_ids.length===0)continue;const _=v.component_ids.map(P=>{var C;return((C=p[P])==null?void 0:C.x)??0}),S=v.component_ids.map(P=>{var C;return((C=p[P])==null?void 0:C.y)??0}),E=Math.min(..._)-yt,b=Math.min(...S)-yt-24,A=Math.max(..._)+Xf+yt,D=Math.max(...S)+Ci+yt;x[v.id]={x:E,y:b};const T=EC(v.id,v.kind),I=!!(h&&g&&v.component_ids.some(P=>g.component_ids.includes(P)));r.push({id:`boundary-${v.id}`,type:"boundaryGroup",position:I?{x:E-x[g.id].x,y:b-x[g.id].y}:{x:E,y:b},data:{label:v.label||v.id,labelColor:T.labelColor,labelBg:T.labelBg,dotColor:T.dot},style:{background:T.bg,border:`1.5px solid ${T.border}`,borderRadius:10,padding:yt,width:A-E,height:D-b},zIndex:-1,parentId:I?h:void 0})}}for(const g of u){const h=a[g];for(const v of h){const _=l[v.id],S=t&&_&&x[_];let E=((k=p[v.id])==null?void 0:k.x)??0,b=((m=p[v.id])==null?void 0:m.y)??0;S&&(E-=x[_].x,b-=x[_].y),r.push({id:v.id,type:"cloudService",position:{x:E,y:b},data:{label:v.label,service:v.service,provider:v.provider,description:v.description,tier:v.tier,config:v.config||{},monthlyCost:n[v.id]},parentId:S?`boundary-${_}`:void 0,extent:S?"parent":void 0})}}return r}function am(e,t){return`edge:${e.source}:${e.target}:${t}`}function Kf(e){return e.connections.map((t,n)=>{let r=t.label||"";return t.protocol&&!r.includes(t.protocol)&&(r=t.protocol+(t.port?`:${t.port}`:"")),{id:am(t,n),source:t.source,target:t.target,label:r,style:{stroke:"#94a3b8"},labelStyle:{fill:"#64748b",fontSize:11},animated:!0}})}function NC(e,t){return e&&e.map(n=>({...n,component_ids:n.component_ids.filter(r=>r!==t)}))}function jC({spec:e,onSpecChange:t}){const[n,r]=z.useState(!0),[o,i]=z.useState(null),[s,l]=z.useState(null),a=z.useCallback(P=>{l(null),t(P)},[t]),u=z.useCallback(async P=>{try{const C=await fetch(`${Ul}/export`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({spec:e,format:P})});if(!C.ok)return;const L=await C.blob(),M=URL.createObjectURL(L),R=document.createElement("a");R.href=M,R.download=`architecture.${P}`,R.click(),URL.revokeObjectURL(M)}catch{}},[e]),p=z.useMemo(()=>{var C;const P={};for(const L of((C=e.cost_estimate)==null?void 0:C.breakdown)??[])P[L.component_id]=L.monthly;return P},[e.cost_estimate]),c=z.useMemo(()=>o?e.components.find(P=>P.id===o)??null:null,[o,e.components]),d=z.useMemo(()=>{var P;return o?((P=e.cost_estimate)==null?void 0:P.breakdown.find(C=>C.component_id===o))??null:null},[o,e.cost_estimate]),[x,y,w]=PE([]),[k,m,g]=TE([]);z.useEffect(()=>{y(bC(e,n,p)),m(Kf(e))},[e,n,p,y,m]);const h=z.useCallback((P,C)=>{C.id.startsWith("boundary-")||i(C.id)},[]),v=z.useCallback(()=>{i(null)},[]),_=z.useCallback((P,C)=>{if(C.id.startsWith("boundary-"))return;const L=bi(e.metadata),M=L.canvas??{},R={...M.nodes??{}},N=x.find($=>$.id===C.parentId),j=N?{x:N.position.x+C.position.x,y:N.position.y+C.position.y}:{x:C.position.x,y:C.position.y};R[C.id]=j,L.canvas={...M,nodes:R},a({...e,metadata:L})},[a,x,e]),S=z.useCallback(P=>{!P.source||!P.target||P.source===P.target||e.connections.some(L=>L.source===P.source&&L.target===P.target)||a({...e,connections:[...e.connections,{source:P.source,target:P.target,label:"HTTPS",protocol:"HTTPS",port:443}]})},[a,e]),E=z.useCallback(P=>{if(P.length===0)return;if(!window.confirm(`Delete ${P.length===1?"this connection":"these connections"}?`)){m(Kf(e));return}const C=new Set(P.map(L=>L.id));a({...e,connections:e.connections.filter((L,M)=>!C.has(am(L,M)))})},[a,m,e]),b=z.useCallback(P=>{a({...e,components:e.components.map(C=>C.id===P.id?P:C)})},[a,e]),A=z.useCallback(P=>{var R,N;const C=e.components.find(j=>j.id===P);if(!C||!window.confirm(`Delete ${C.label||C.id} and its connections?`))return;const L=bi(e.metadata);(R=L.canvas)!=null&&R.nodes&&delete L.canvas.nodes[P];const M=((N=L.modules)==null?void 0:N.instances)??{};for(const j of Object.values(M))j.component_ids.includes(P)&&(j.component_ids=j.component_ids.filter($=>$!==P),j.partial=!0,j.approved=!1,delete j.terraform);L.modules&&(L.modules.instances=M),a({...e,components:e.components.filter(j=>j.id!==P),connections:e.connections.filter(j=>j.source!==P&&j.target!==P),boundaries:NC(e.boundaries,P),metadata:L}),i(null)},[a,e]),D=z.useCallback(P=>{const C=new Set(e.components.map($=>$.id)),L=Xl(Ni(P.service_key),C),M=bi(e.metadata),R=M.canvas??{},N={...R.nodes??{}};N[L]=Gf(Object.keys(N).length+e.components.length),M.canvas={...R,nodes:N};const j={id:L,service:P.service_key,provider:P.provider.toLowerCase(),label:P.name,description:P.description??"",tier:_C(P.category),config:iu(P.default_config??{})};a({...e,components:[...e.components,j],metadata:M}),i(L)},[a,e]),T=z.useCallback(async P=>{var C;try{const L=await fetch(`${Ul}/modules/${encodeURIComponent(P)}`);if(!L.ok)return;const R=(await L.json()).module,N=new Set(e.components.map(G=>G.id)),j=bi(e.metadata),$=j.modules??{},O={...$.instances??{}},B=new Set(Object.keys(O)),W=Xl(Ni(R.id,"module"),B),V=Ni(R.naming.component_id_prefix,W),Y={};for(const G of R.fragment.components)Y[G.id]=Xl(Ni(`${V}_${G.id}`,V),N);const X=j.canvas??{},Q={...X.nodes??{}},H=Object.keys(Q).length+e.components.length,K=R.fragment.components.map((G,J)=>{const Z=iu(G.config??{}),re={...R.default_tags??{},...typeof Z.tags=="object"&&Z.tags!==null?Z.tags:{}};Z.tags=re;const le=Y[G.id];return Q[le]=Gf(H+J),{...G,id:le,provider:G.provider.toLowerCase(),config:Z}}),ee=R.fragment.connections.map(G=>({...G,source:Y[G.source],target:Y[G.target]}));O[W]={module_id:R.id,module_version:R.terraform.version,component_ids:K.map(G=>G.id),expected_component_count:K.length,required_tags:[...R.required_tags],naming_prefix:V,approved:R.approved,terraform:{...R.terraform}},j.canvas={...X,nodes:Q},j.modules={...$,instances:O},a({...e,components:[...e.components,...K],connections:[...e.connections,...ee],metadata:j}),i(((C=K[0])==null?void 0:C.id)??null)}catch{}},[a,e]),I=z.useCallback(async()=>{try{const P=await fetch(`${Ul}/canvas/validate`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({spec:e})});if(!P.ok)return;l(await P.json())}catch{l({passed:!1,violations:[{code:"request_failed",severity:"error",message:"Standards check failed."}]})}},[e]);return f.jsxs("div",{style:{width:"100%",height:"100%",position:"relative"},children:[f.jsx(yC,{provider:e.provider||"aws",standardsResult:s,onAddResource:D,onAddModule:T,onCheckStandards:I}),f.jsxs(zE,{nodes:x,edges:k,nodeTypes:kC,onNodesChange:w,onEdgesChange:g,onEdgesDelete:E,onConnect:S,onNodeDragStop:_,fitView:!0,proOptions:{hideAttribution:!0},style:{background:"#f8fafc"},onNodeClick:h,onPaneClick:v,children:[f.jsx($E,{color:"#e2e8f0",gap:20}),f.jsx(WE,{style:{background:"#ffffff",border:"1px solid #e2e8f0",borderRadius:8}})]}),f.jsx(dC,{components:e.components}),f.jsx(fC,{showBoundaries:n,onToggleBoundaries:()=>r(P=>!P),onExportSvg:()=>u("svg"),onExportPng:()=>u("png")}),f.jsx(mC,{component:c??null,cost:d,onClose:()=>i(null),onApply:P=>b({...P,description:P.description??"",config:P.config??{}}),onDelete:A})]})}function MC({estimate:e}){return f.jsxs("div",{style:{padding:32},children:[f.jsx("h2",{style:{fontSize:18,marginBottom:16,color:"#0f172a"},children:"Cost Breakdown"}),f.jsxs("table",{style:{width:"100%",maxWidth:700,borderCollapse:"collapse",fontSize:14},children:[f.jsx("thead",{children:f.jsxs("tr",{style:{borderBottom:"2px solid #e2e8f0",background:"#f8fafc"},children:[f.jsx("th",{style:{textAlign:"left",padding:"10px 12px",color:"#475569"},children:"Component"}),f.jsx("th",{style:{textAlign:"left",padding:"10px 12px",color:"#475569"},children:"Service"}),f.jsx("th",{style:{textAlign:"right",padding:"10px 12px",color:"#475569"},children:"Monthly"}),f.jsx("th",{style:{textAlign:"left",padding:"10px 12px",color:"#475569"},children:"Notes"})]})}),f.jsx("tbody",{children:e.breakdown.map(t=>f.jsxs("tr",{style:{borderBottom:"1px solid #f1f5f9"},children:[f.jsx("td",{style:{padding:"10px 12px",color:"#0f172a"},children:t.component_id}),f.jsx("td",{style:{padding:"10px 12px",color:"#475569"},children:t.service}),f.jsxs("td",{style:{padding:"10px 12px",textAlign:"right",fontFamily:"monospace",color:"#0f172a"},children:["$",t.monthly.toFixed(2)]}),f.jsx("td",{style:{padding:"10px 12px",color:"#64748b",fontSize:12},children:t.notes})]},t.component_id))}),f.jsx("tfoot",{children:f.jsxs("tr",{style:{borderTop:"2px solid #e2e8f0",background:"#f0f9ff"},children:[f.jsx("td",{style:{padding:"12px",fontWeight:700,fontSize:15,color:"#0f172a"},colSpan:2,children:"Total"}),f.jsxs("td",{style:{padding:"12px",textAlign:"right",fontWeight:700,fontSize:15,fontFamily:"monospace",color:"#2563eb"},children:["$",e.monthly_total.toFixed(2)]}),f.jsxs("td",{style:{padding:"12px",color:"#64748b",fontSize:12},children:[e.currency,"/month"]})]})})]})]})}function zC({spec:e,onDownloadTerraform:t,onDownloadYaml:n,validationSummary:r,usage:o}){var s,l;if(!e)return null;const i=[];return o!=null&&o.model&&i.push(o.model.replace("claude-","").replace("anthropic.","")),(o==null?void 0:o.input_tokens)!=null&&(o==null?void 0:o.output_tokens)!=null&&i.push(`${((o.input_tokens+o.output_tokens)/1e3).toFixed(1)}k tokens`),(o==null?void 0:o.cost_usd)!=null&&i.push(`$${o.cost_usd.toFixed(4)}`),(o==null?void 0:o.latency_ms)!=null&&i.push(`${(o.latency_ms/1e3).toFixed(1)}s`),f.jsxs("div",{style:{display:"flex",alignItems:"center",gap:"1rem",padding:"0.5rem 1rem",background:"#ffffff",borderRadius:"0.375rem",marginBottom:"0.5rem",fontSize:"0.875rem",borderBottom:"1px solid #e2e8f0"},children:[f.jsxs("span",{style:{color:"#64748b"},children:["Components: ",f.jsx("strong",{style:{color:"#334155"},children:((s=e.components)==null?void 0:s.length)||0})]}),e.cost_estimate&&f.jsxs("span",{style:{color:"#64748b"},children:["Est. ",f.jsxs("strong",{style:{color:"#2563eb"},children:["$",(l=e.cost_estimate.monthly_total)==null?void 0:l.toFixed(0),"/mo"]})]}),f.jsxs("span",{style:{color:"#64748b"},children:[(e.provider||"aws").toUpperCase()," / ",e.region||"us-east-1"]}),r&&f.jsxs("span",{style:{padding:"0.125rem 0.5rem",borderRadius:"0.25rem",fontSize:"0.75rem",fontWeight:600,background:r.passed===r.total?"#d1fae5":"#fee2e2",color:r.passed===r.total?"#065f46":"#991b1b"},children:["WA: ",r.passed,"/",r.total]}),i.length>0&&f.jsx("span",{style:{color:"#94a3b8",fontSize:"0.75rem"},children:i.join(" · ")}),f.jsxs("div",{style:{marginLeft:"auto",display:"flex",gap:"0.5rem"},children:[t&&f.jsx("button",{onClick:t,style:{padding:"0.25rem 0.75rem",background:"#2563eb",color:"white",border:"none",borderRadius:"0.25rem",cursor:"pointer",fontSize:"0.75rem"},children:"Download Terraform"}),n&&f.jsx("button",{onClick:n,style:{padding:"0.25rem 0.75rem",background:"#f8fafc",color:"#475569",border:"1px solid #e2e8f0",borderRadius:"0.25rem",cursor:"pointer",fontSize:"0.75rem"},children:"Download YAML"})]})]})}async function Go(e){if(e.status===429){const t=e.headers.get("Retry-After"),n=t?` Retry after ${t}s.`:"";try{const r=await e.json();return`${r.message||r.detail||"Rate limited"}${n}`}catch{return`Rate limited.${n}`}}try{const t=await e.json();return su(t,e.statusText)}catch{return e.statusText||"Request failed"}}function su(e,t="Request failed"){const n=e.message||e.detail||t;return e.suggestion?`${n} — ${e.suggestion}`:n}const PC=[{key:"hipaa",label:"HIPAA"},{key:"pci-dss",label:"PCI-DSS"},{key:"soc2",label:"SOC 2"},{key:"fedramp",label:"FedRAMP"},{key:"gdpr",label:"GDPR"},{key:"well-architected",label:"Well-Architected"}],ji={critical:0,high:1,medium:2,low:3},$o={critical:{bg:"#fef2f2",text:"#991b1b",border:"#fca5a5"},high:{bg:"#fff7ed",text:"#9a3412",border:"#fdba74"},medium:{bg:"#fffbeb",text:"#92400e",border:"#fcd34d"},low:{bg:"#f0fdf4",text:"#166534",border:"#86efac"}},TC={data_protection:"Data Protection",monitoring:"Monitoring & Logging",identity:"Identity & Access",network_security:"Network Security",reliability:"Reliability",compliance:"Compliance",operations:"Operations",security:"Security",cost:"Cost Optimization"};function IC({score:e,passed:t}){const n=Math.round(e*100),r=54,o=8,i=2*Math.PI*r,s=i*(1-e),l=t?"#16a34a":n>=70?"#f59e0b":"#dc2626";return f.jsxs("div",{style:{display:"flex",flexDirection:"column",alignItems:"center",gap:6},children:[f.jsxs("svg",{width:136,height:136,viewBox:"0 0 136 136",children:[f.jsx("circle",{cx:68,cy:68,r,fill:"none",stroke:"#f1f5f9",strokeWidth:o}),f.jsx("circle",{cx:68,cy:68,r,fill:"none",stroke:l,strokeWidth:o,strokeDasharray:i,strokeDashoffset:s,strokeLinecap:"round",transform:"rotate(-90 68 68)",style:{transition:"stroke-dashoffset 0.6s ease"}}),f.jsxs("text",{x:68,y:62,textAnchor:"middle",fontSize:28,fontWeight:700,fill:"#0f172a",children:[n,"%"]}),f.jsx("text",{x:68,y:82,textAnchor:"middle",fontSize:11,fill:"#64748b",children:"compliance"})]}),f.jsx("span",{style:{display:"inline-block",padding:"3px 12px",borderRadius:4,fontSize:12,fontWeight:600,background:t?"#dcfce7":"#fee2e2",color:t?"#166534":"#991b1b"},children:t?"PASSED":"FAILED"})]})}function RC({severity:e}){const t=$o[e]||$o.medium;return f.jsx("span",{style:{display:"inline-block",padding:"1px 8px",borderRadius:4,fontSize:11,fontWeight:600,background:t.bg,color:t.text,border:`1px solid ${t.border}`,textTransform:"uppercase",letterSpacing:"0.02em"},children:e})}function Zf({check:e,expanded:t,onToggle:n}){const r=$o[e.severity]||$o.medium;return f.jsxs("div",{style:{borderLeft:`3px solid ${e.passed?"#86efac":r.border}`,background:"#ffffff",borderRadius:"0 6px 6px 0",marginBottom:6,cursor:"pointer",transition:"box-shadow 0.15s ease"},onClick:n,onMouseEnter:o=>{o.currentTarget.style.boxShadow="0 1px 4px rgba(0,0,0,0.06)"},onMouseLeave:o=>{o.currentTarget.style.boxShadow="none"},children:[f.jsxs("div",{style:{display:"flex",alignItems:"center",gap:10,padding:"10px 14px"},children:[f.jsx("span",{style:{fontSize:14,flexShrink:0,width:18,textAlign:"center"},children:e.passed?f.jsx("span",{style:{color:"#16a34a"},children:"✓"}):f.jsx("span",{style:{color:"#dc2626",fontWeight:700},children:"✕"})}),f.jsx("span",{style:{flex:1,fontSize:13,color:"#0f172a",fontWeight:500},children:e.name.replace(/_/g," ").replace(/\b\w/g,o=>o.toUpperCase())}),f.jsx(RC,{severity:e.severity}),f.jsx("span",{style:{fontSize:11,color:"#94a3b8",transform:t?"rotate(180deg)":"rotate(0deg)",transition:"transform 0.15s ease",flexShrink:0},children:"▼"})]}),t&&f.jsxs("div",{style:{padding:"0 14px 12px 42px",fontSize:12,lineHeight:1.6},children:[f.jsx("div",{style:{color:"#475569",marginBottom:4},children:e.detail}),e.recommendation&&f.jsxs("div",{style:{marginTop:6,padding:"8px 12px",background:"#f8fafc",borderRadius:4,border:"1px solid #e2e8f0",color:"#334155"},children:[f.jsx("span",{style:{fontWeight:600,color:"#475569",fontSize:11},children:"Recommendation: "}),e.recommendation]})]})]})}function LC({spec:e,apiBase:t}){const[n,r]=z.useState(null),[o,i]=z.useState(null),[s,l]=z.useState(!1),[a,u]=z.useState(null),[p,c]=z.useState(new Set),[d,x]=z.useState(!1),y=z.useCallback(async _=>{i(_),l(!0),u(null),c(new Set),x(!1);try{const S=_==="well-architected",E=await fetch(`${t}/validate`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({spec:e,compliance:S?[]:[_],well_architected:S})});if(!E.ok)throw new Error(await Go(E));const b=await E.json();r(b.results)}catch(S){u(S instanceof Error?S.message:"Validation failed"),r(null)}finally{l(!1)}},[e,t]),w=z.useCallback(_=>{c(S=>{const E=new Set(S);return E.has(_)?E.delete(_):E.add(_),E})},[]),k=(n==null?void 0:n[0])??null,m=k?k.checks.filter(_=>!_.passed).sort((_,S)=>(ji[_.severity]??9)-(ji[S.severity]??9)):[],g=k?k.checks.filter(_=>_.passed).sort((_,S)=>(ji[_.severity]??9)-(ji[S.severity]??9)):[],h={};for(const _ of m){const S=_.category;h[S]||(h[S]=[]),h[S].push(_)}const v=k?k.checks.reduce((_,S)=>(S.passed||(_[S.severity]=(_[S.severity]||0)+1),_),{}):{};return f.jsxs("div",{style:{padding:32,maxWidth:900},children:[f.jsx("h2",{style:{fontSize:18,marginBottom:16,color:"#0f172a",fontWeight:700},children:"Validate Architecture"}),f.jsx("div",{style:{display:"flex",gap:8,marginBottom:24},children:PC.map(_=>{const S=o===_.key;return f.jsx("button",{onClick:()=>y(_.key),disabled:s,style:{padding:"8px 18px",borderRadius:6,border:S?"1.5px solid #2563eb":"1px solid #e2e8f0",background:S?"#eff6ff":"#ffffff",color:S?"#1d4ed8":"#475569",cursor:s?"wait":"pointer",fontSize:13,fontWeight:S?600:500,transition:"all 0.15s ease",opacity:s&&!S?.6:1},children:_.label},_.key)})}),s&&f.jsxs("div",{style:{display:"flex",alignItems:"center",gap:10,padding:24,color:"#64748b",fontSize:14},children:[f.jsx("span",{style:{display:"inline-block",width:16,height:16,border:"2px solid #e2e8f0",borderTopColor:"#2563eb",borderRadius:"50%",animation:"spin 0.6s linear infinite"}}),"Running ",o==null?void 0:o.toUpperCase()," validation...",f.jsx("style",{children:"@keyframes spin { to { transform: rotate(360deg); } }"})]}),a&&f.jsx("div",{style:{padding:"12px 16px",background:"#fef2f2",border:"1px solid #fca5a5",borderRadius:8,color:"#991b1b",fontSize:13},children:a}),k&&!s&&f.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:24},children:[f.jsxs("div",{style:{display:"flex",gap:24,alignItems:"flex-start",padding:20,background:"#ffffff",border:"1px solid #e2e8f0",borderRadius:10},children:[f.jsx(IC,{score:k.score,passed:k.passed}),f.jsxs("div",{style:{flex:1},children:[f.jsx("div",{style:{fontSize:16,fontWeight:700,color:"#0f172a",marginBottom:4},children:k.framework}),f.jsxs("div",{style:{fontSize:13,color:"#64748b",marginBottom:14},children:[k.checks.length," checks evaluated ·"," ",g.length," passed ·"," ",m.length," failed"]}),f.jsx("div",{style:{display:"flex",gap:10,flexWrap:"wrap"},children:["critical","high","medium","low"].map(_=>{const S=v[_]||0,E=$o[_];return f.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,padding:"6px 12px",borderRadius:6,background:S>0?E.bg:"#f8fafc",border:`1px solid ${S>0?E.border:"#e2e8f0"}`,minWidth:100},children:[f.jsx("span",{style:{fontSize:18,fontWeight:700,color:S>0?E.text:"#cbd5e1",lineHeight:1},children:S}),f.jsx("span",{style:{fontSize:11,fontWeight:600,color:S>0?E.text:"#94a3b8",textTransform:"uppercase",letterSpacing:"0.03em"},children:_})]},_)})})]})]}),m.length>0&&f.jsxs("div",{children:[f.jsxs("h3",{style:{fontSize:14,fontWeight:600,color:"#0f172a",marginBottom:12,display:"flex",alignItems:"center",gap:8},children:[f.jsx("span",{style:{color:"#dc2626"},children:"✕"}),"Failed Checks (",m.length,")"]}),Object.entries(h).map(([_,S])=>f.jsxs("div",{style:{marginBottom:16},children:[f.jsx("div",{style:{fontSize:11,fontWeight:600,color:"#64748b",textTransform:"uppercase",letterSpacing:"0.05em",marginBottom:6,paddingLeft:4},children:TC[_]||_.replace(/_/g," ")}),S.map(E=>{const b=`${_}-${E.name}`;return f.jsx(Zf,{check:E,expanded:p.has(b),onToggle:()=>w(b)},b)})]},_))]}),g.length>0&&f.jsxs("div",{children:[f.jsxs("button",{onClick:()=>x(_=>!_),style:{display:"flex",alignItems:"center",gap:8,background:"none",border:"none",cursor:"pointer",padding:"4px 0",fontSize:14,fontWeight:600,color:"#0f172a"},children:[f.jsx("span",{style:{color:"#16a34a"},children:"✓"}),"Passed Checks (",g.length,")",f.jsx("span",{style:{fontSize:11,color:"#94a3b8",transform:d?"rotate(180deg)":"rotate(0deg)",transition:"transform 0.15s ease"},children:"▼"})]}),d&&f.jsx("div",{style:{marginTop:8},children:g.map(_=>{const S=`passed-${_.category}-${_.name}`;return f.jsx(Zf,{check:_,expanded:p.has(S),onToggle:()=>w(S)},S)})})]}),f.jsxs("div",{style:{fontSize:11,color:"#94a3b8",borderTop:"1px solid #f1f5f9",paddingTop:12,lineHeight:1.5},children:["Score = percentage of checks passed. A framework is marked FAILED if any critical-severity check fails, regardless of overall score. Checks are defined in the Cloudwright Validator based on ",k.framework," control requirements."]})]}),!k&&!s&&!a&&f.jsx("div",{style:{padding:40,textAlign:"center",color:"#94a3b8",fontSize:14,background:"#f8fafc",borderRadius:8,border:"1px dashed #e2e8f0"},children:"Select a compliance framework above to validate your architecture."})]})}const AC=[{key:"hipaa",label:"HIPAA"},{key:"soc2",label:"SOC 2"},{key:"pci-dss",label:"PCI-DSS"},{key:"fedramp",label:"FedRAMP"},{key:"gdpr",label:"GDPR"},{key:"iso27001",label:"ISO 27001"},{key:"nist",label:"NIST 800-53"}],qf={critical:{bg:"#fef2f2",text:"#991b1b",border:"#fca5a5"},high:{bg:"#fff7ed",text:"#9a3412",border:"#fdba74"},medium:{bg:"#fffbeb",text:"#92400e",border:"#fcd34d"},low:{bg:"#f0fdf4",text:"#166534",border:"#86efac"}};function $C({spec:e,apiBase:t}){const[n,r]=z.useState(["hipaa","soc2","fedramp"]),[o,i]=z.useState(null),[s,l]=z.useState(!1),[a,u]=z.useState(null),p=d=>r(x=>x.includes(d)?x.filter(y=>y!==d):[...x,d]),c=z.useCallback(async()=>{l(!0),u(null);try{const d=await fetch(`${t}/compliance`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({spec:e,frameworks:n})});if(!d.ok)throw new Error(await Go(d));i(await d.json())}catch(d){u(d instanceof Error?d.message:"Compliance scan failed")}finally{l(!1)}},[e,t,n]);return f.jsxs("div",{style:{padding:24,maxWidth:920},children:[f.jsx("h2",{style:{fontSize:18,marginBottom:6,color:"#0f172a"},children:"Compliance Control Mapping"}),f.jsx("p",{style:{fontSize:13,color:"#64748b",marginBottom:16},children:"Every design-stage finding mapped to the framework control it violates — before any infrastructure exists. Folds in a Checkov deep scan when available."}),f.jsx("div",{style:{display:"flex",flexWrap:"wrap",gap:8,marginBottom:16},children:AC.map(d=>f.jsx("button",{onClick:()=>p(d.key),style:{padding:"6px 14px",borderRadius:999,border:`1px solid ${n.includes(d.key)?"#2563eb":"#cbd5e1"}`,background:n.includes(d.key)?"#2563eb":"#ffffff",color:n.includes(d.key)?"#ffffff":"#475569",fontSize:13,cursor:"pointer"},children:d.label},d.key))}),f.jsx("button",{onClick:c,disabled:s||n.length===0,style:{padding:"10px 22px",borderRadius:8,border:"none",background:s?"#94a3b8":"#0f172a",color:"#ffffff",fontSize:14,fontWeight:600,cursor:s?"default":"pointer"},children:s?"Scanning…":"Run compliance scan"}),a&&f.jsx("div",{style:{marginTop:16,padding:12,background:"#fef2f2",border:"1px solid #fca5a5",borderRadius:8,color:"#991b1b",fontSize:13},children:a}),o&&f.jsxs("div",{style:{marginTop:24},children:[f.jsxs("div",{style:{fontSize:12,color:"#64748b",marginBottom:8},children:["Scanner: ",f.jsx("strong",{children:o.scanner}),o.checkov_used?" (Checkov deep scan included)":""]}),f.jsxs("table",{style:{width:"100%",borderCollapse:"collapse",marginBottom:24},children:[f.jsx("thead",{children:f.jsxs("tr",{style:{background:"#f8fafc",textAlign:"left"},children:[f.jsx("th",{style:Ur,children:"Framework"}),f.jsx("th",{style:Ur,children:"Controls satisfied"}),f.jsx("th",{style:Ur,children:"Violated"}),f.jsx("th",{style:Ur,children:"Findings"}),f.jsx("th",{style:Ur,children:"Status"})]})}),f.jsx("tbody",{children:o.frameworks.map(d=>f.jsxs("tr",{style:{borderTop:"1px solid #e2e8f0"},children:[f.jsx("td",{style:Yr,children:f.jsx("strong",{children:d.framework})}),f.jsxs("td",{style:Yr,children:[d.controls_satisfied,"/",d.controls_total]}),f.jsx("td",{style:{...Yr,color:"#991b1b"},children:d.controls_violated.length?d.controls_violated.join(", "):"—"}),f.jsx("td",{style:Yr,children:d.findings}),f.jsx("td",{style:Yr,children:f.jsx("span",{style:{padding:"2px 10px",borderRadius:999,fontSize:12,fontWeight:600,background:d.status==="pass"?"#dcfce7":"#fee2e2",color:d.status==="pass"?"#166534":"#991b1b"},children:d.status.toUpperCase()})})]},d.framework))})]}),f.jsxs("h3",{style:{fontSize:15,color:"#0f172a",marginBottom:12},children:["Findings (",o.findings.length,")"]}),o.findings.map((d,x)=>{const y=qf[d.severity]||qf.low;return f.jsxs("div",{style:{border:`1px solid ${y.border}`,background:y.bg,borderRadius:8,padding:14,marginBottom:10},children:[f.jsxs("div",{style:{display:"flex",gap:8,alignItems:"center"},children:[f.jsxs("span",{style:{fontSize:11,fontWeight:700,color:y.text,textTransform:"uppercase"},children:["[",d.severity,"]"]}),f.jsx("span",{style:{fontSize:14,color:"#0f172a"},children:d.message}),f.jsxs("span",{style:{fontSize:11,color:"#64748b"},children:["(",d.source,")"]})]}),d.controls.length>0&&f.jsx("div",{style:{display:"flex",flexWrap:"wrap",gap:6,marginTop:8},children:d.controls.map((w,k)=>f.jsxs("span",{title:w.title,style:{fontSize:11,padding:"2px 8px",borderRadius:4,background:"#e0e7ff",color:"#3730a3",fontFamily:"monospace"},children:[w.framework," ",w.control_id]},k))}),f.jsx("div",{style:{fontSize:12,color:"#475569",marginTop:8},children:d.remediation})]},x)})]})]})}const Ur={padding:"10px 12px",fontSize:12,color:"#475569",fontWeight:600},Yr={padding:"10px 12px",fontSize:13,color:"#0f172a"},DC=[{key:"terraform",label:"Terraform"},{key:"pulumi-python",label:"Pulumi (Python)"},{key:"pulumi-ts",label:"Pulumi (TS)"}];function OC({spec:e,apiBase:t}){const[n,r]=z.useState("terraform"),[o,i]=z.useState(null),[s,l]=z.useState(!1),[a,u]=z.useState(null),p=z.useCallback(async()=>{l(!0),u(null),i(null);try{const c=await fetch(`${t}/plan`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({spec:e,target:n,run_plan:!0})});if(!c.ok)throw new Error(await Go(c));i(await c.json())}catch(c){u(c instanceof Error?c.message:"Plan failed")}finally{l(!1)}},[e,t,n]);return f.jsxs("div",{style:{padding:24,maxWidth:920},children:[f.jsx("h2",{style:{fontSize:18,marginBottom:6,color:"#0f172a"},children:"Plan / Preview — prove it deploys"}),f.jsxs("p",{style:{fontSize:13,color:"#64748b",marginBottom:16},children:["Runs ",f.jsx("code",{children:"terraform validate/plan"})," or ",f.jsx("code",{children:"pulumi preview"})," against the exported artifact. Read-only — nothing is applied. Validation needs no credentials and is the offline proof of deployability."]}),f.jsx("div",{style:{display:"flex",gap:8,marginBottom:16},children:DC.map(c=>f.jsx("button",{onClick:()=>r(c.key),style:{padding:"6px 14px",borderRadius:8,border:`1px solid ${n===c.key?"#2563eb":"#cbd5e1"}`,background:n===c.key?"#2563eb":"#ffffff",color:n===c.key?"#ffffff":"#475569",fontSize:13,cursor:"pointer"},children:c.label},c.key))}),f.jsx("button",{onClick:p,disabled:s,style:{padding:"10px 22px",borderRadius:8,border:"none",background:s?"#94a3b8":"#0f172a",color:"#ffffff",fontSize:14,fontWeight:600,cursor:s?"default":"pointer"},children:s?"Running plan…":"Run plan"}),a&&f.jsx("div",{style:{marginTop:16,padding:12,background:"#fef2f2",border:"1px solid #fca5a5",borderRadius:8,color:"#991b1b",fontSize:13},children:a}),o&&f.jsxs("div",{style:{marginTop:24},children:[f.jsxs("div",{style:{display:"inline-block",padding:"8px 18px",borderRadius:8,fontSize:15,fontWeight:700,background:o.ok?"#dcfce7":"#fee2e2",color:o.ok?"#166534":"#991b1b",marginBottom:16},children:[o.ok?"DEPLOYABLE":"NOT DEPLOYABLE",o.ok&&!o.plan_ran?" (validate only — no credentials)":""]}),o.summary&&f.jsxs("div",{style:{fontSize:14,marginBottom:16},children:["Resource diff:"," ",f.jsxs("span",{style:{color:"#166534"},children:["+",o.summary.add]})," ",f.jsxs("span",{style:{color:"#92400e"},children:["~",o.summary.change]})," ",f.jsxs("span",{style:{color:"#991b1b"},children:["-",o.summary.destroy]})]}),f.jsx("ul",{style:{fontSize:13,color:"#334155",marginBottom:16,paddingLeft:18},children:o.messages.map((c,d)=>f.jsx("li",{style:{marginBottom:4},children:c},d))}),o.output_tail&&f.jsx("pre",{style:{background:"#0f172a",color:"#e2e8f0",padding:14,borderRadius:8,fontSize:12,overflowX:"auto",maxHeight:280},children:o.output_tail})]})]})}const Ql=[{key:"terraform",label:"Terraform",ext:"tf",lang:"hcl",desc:"HashiCorp Configuration Language"},{key:"cloudformation",label:"CloudFormation",ext:"yaml",lang:"yaml",desc:"AWS CloudFormation template"},{key:"mermaid",label:"Mermaid",ext:"mmd",lang:"mermaid",desc:"Mermaid diagram markup"},{key:"d2",label:"D2",ext:"d2",lang:"d2",desc:"D2 diagram language"},{key:"sbom",label:"SBOM",ext:"json",lang:"json",desc:"CycloneDX Software BOM"},{key:"aibom",label:"AIBOM",ext:"json",lang:"json",desc:"OWASP AI Bill of Materials"},{key:"html",label:"HTML Report",ext:"html",lang:"html",desc:"Self-contained shareable report"}];function Jf({format:e}){const t={terraform:"HCL",cloudformation:"CFN",mermaid:"MMD",d2:"D2",sbom:"BOM",aibom:"AI"},n={terraform:"#7c3aed",cloudformation:"#ea580c",mermaid:"#0891b2",d2:"#4f46e5",sbom:"#059669",aibom:"#2563eb"};return f.jsx("span",{style:{display:"inline-flex",alignItems:"center",justifyContent:"center",width:32,height:20,borderRadius:4,fontSize:10,fontWeight:700,background:`${n[e]||"#64748b"}14`,color:n[e]||"#64748b",letterSpacing:"0.02em",flexShrink:0},children:t[e]||e.slice(0,3).toUpperCase()})}function BC({spec:e,apiBase:t}){const[n,r]=z.useState(null),[o,i]=z.useState(""),[s,l]=z.useState(!1),[a,u]=z.useState(null),[p,c]=z.useState(!1),d=z.useRef(null),x=z.useCallback(async g=>{r(g),l(!0),u(null),c(!1);try{const h=await fetch(`${t}/export`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({spec:e,format:g})});if(!h.ok)throw new Error(await Go(h));const v=await h.json();i(v.content||JSON.stringify(v,null,2))}catch(h){u(h instanceof Error?h.message:"Export failed"),i("")}finally{l(!1)}},[e,t]),y=z.useCallback(async()=>{var g,h;try{await navigator.clipboard.writeText(o),c(!0),setTimeout(()=>c(!1),2e3)}catch{const v=d.current;if(v){const _=document.createRange();_.selectNodeContents(v),(g=window.getSelection())==null||g.removeAllRanges(),(h=window.getSelection())==null||h.addRange(_)}}},[o]),w=z.useCallback(()=>{if(!o||!n)return;const g=Ql.find(S=>S.key===n),h=new Blob([o],{type:"text/plain"}),v=URL.createObjectURL(h),_=document.createElement("a");_.href=v,_.download=`architecture.${(g==null?void 0:g.ext)||"txt"}`,_.click(),URL.revokeObjectURL(v)},[o,n]),k=o?o.split(` -`).length:0,m=Ql.find(g=>g.key===n);return f.jsxs("div",{style:{padding:32,maxWidth:960},children:[f.jsx("h2",{style:{fontSize:18,marginBottom:16,color:"#0f172a",fontWeight:700},children:"Export Architecture"}),f.jsx("div",{style:{display:"grid",gridTemplateColumns:"repeat(3, 1fr)",gap:10,marginBottom:24},children:Ql.map(g=>{const h=n===g.key;return f.jsxs("button",{onClick:()=>x(g.key),disabled:s,style:{display:"flex",alignItems:"center",gap:10,padding:"10px 14px",borderRadius:8,border:h?"1.5px solid #2563eb":"1px solid #e2e8f0",background:h?"#eff6ff":"#ffffff",cursor:s?"wait":"pointer",textAlign:"left",transition:"all 0.15s ease",opacity:s&&!h?.6:1},children:[f.jsx(Jf,{format:g.key}),f.jsxs("div",{children:[f.jsx("div",{style:{fontSize:13,fontWeight:h?600:500,color:h?"#1d4ed8":"#0f172a"},children:g.label}),f.jsx("div",{style:{fontSize:11,color:"#94a3b8"},children:g.desc})]})]},g.key)})}),s&&f.jsxs("div",{style:{display:"flex",alignItems:"center",gap:10,padding:24,color:"#64748b",fontSize:14},children:[f.jsx("span",{style:{display:"inline-block",width:16,height:16,border:"2px solid #e2e8f0",borderTopColor:"#2563eb",borderRadius:"50%",animation:"spin 0.6s linear infinite"}}),"Generating ",(m==null?void 0:m.label)||n,"...",f.jsx("style",{children:"@keyframes spin { to { transform: rotate(360deg); } }"})]}),a&&f.jsx("div",{style:{padding:"12px 16px",background:"#fef2f2",border:"1px solid #fca5a5",borderRadius:8,color:"#991b1b",fontSize:13},children:a}),o&&!s&&f.jsxs("div",{style:{border:"1px solid #e2e8f0",borderRadius:10,overflow:"hidden"},children:[f.jsxs("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",padding:"8px 14px",background:"#f8fafc",borderBottom:"1px solid #e2e8f0"},children:[f.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8},children:[f.jsx(Jf,{format:n||""}),f.jsxs("span",{style:{fontSize:12,color:"#64748b"},children:["architecture.",(m==null?void 0:m.ext)||"txt"]}),f.jsxs("span",{style:{fontSize:11,color:"#cbd5e1"},children:[k," lines"]})]}),f.jsxs("div",{style:{display:"flex",gap:6},children:[f.jsx("button",{onClick:y,style:{padding:"4px 12px",borderRadius:4,border:"1px solid #e2e8f0",background:p?"#dcfce7":"#ffffff",color:p?"#166534":"#475569",cursor:"pointer",fontSize:12,fontWeight:500,transition:"all 0.15s ease"},children:p?"Copied":"Copy"}),f.jsx("button",{onClick:w,style:{padding:"4px 12px",borderRadius:4,border:"1px solid #e2e8f0",background:"#ffffff",color:"#475569",cursor:"pointer",fontSize:12,fontWeight:500},children:"Download"})]})]}),f.jsx("div",{style:{maxHeight:560,overflow:"auto"},children:f.jsx("pre",{ref:d,style:{margin:0,padding:16,fontSize:12,lineHeight:1.7,color:"#334155",background:"#ffffff",fontFamily:"'SF Mono', 'Cascadia Code', 'Fira Code', Menlo, monospace",counterReset:"line",whiteSpace:"pre-wrap",wordBreak:"break-word"},children:o})})]}),!o&&!s&&!a&&f.jsx("div",{style:{padding:40,textAlign:"center",color:"#94a3b8",fontSize:14,background:"#f8fafc",borderRadius:8,border:"1px dashed #e2e8f0"},children:"Select an export format above to generate infrastructure code."})]})}const FC={0:"Edge / CDN",1:"Load Balancing",2:"Compute",3:"Data",4:"Supporting"};function Gl(e){if(e===null)return"null";if(typeof e=="number"||typeof e=="boolean")return String(e);const t=String(e);return/^[A-Za-z0-9_./:@-]+$/.test(t)?t:JSON.stringify(t)}function lu(e,t=0){const n=" ".repeat(t);if(Array.isArray(e))return e.length===0?"[]":e.map(r=>{if(r&&typeof r=="object"){const o=lu(r,t+2);return`${n}- ${o.trimStart()}`}return`${n}- ${Gl(r)}`}).join(` -`);if(e&&typeof e=="object"){const r=Object.entries(e).filter(([,o])=>o!==void 0);return r.length===0?"{}":r.map(([o,i])=>{if(i&&typeof i=="object"){const s=lu(i,t+2);return`${n}${o}: -${s}`}return`${n}${o}: ${Gl(i)}`}).join(` -`)}return Gl(e)}function Mi({label:e,value:t,sub:n}){return f.jsxs("div",{style:{padding:"14px 16px",background:"#ffffff",border:"1px solid #e2e8f0",borderRadius:8,flex:1,minWidth:120},children:[f.jsx("div",{style:{fontSize:22,fontWeight:700,color:"#0f172a",lineHeight:1.2},children:t}),f.jsx("div",{style:{fontSize:12,color:"#64748b",marginTop:2},children:e}),n&&f.jsx("div",{style:{fontSize:11,color:"#94a3b8",marginTop:2},children:n})]})}function HC({spec:e,yaml:t}){var x;const[n,r]=z.useState("overview"),[o,i]=z.useState(!1),s=z.useRef(null),l=z.useMemo(()=>lu(e)||t||"",[e,t]),a=z.useMemo(()=>{const y=new Set(e.components.map(w=>w.provider));return Array.from(y)},[e.components]),u=z.useMemo(()=>{const y=new Set(e.components.map(w=>w.service));return Array.from(y)},[e.components]),p=z.useMemo(()=>{const y={};for(const w of e.components){const k=w.tier??2;y[k]||(y[k]=[]),y[k].push(w)}return y},[e.components]),c=z.useCallback(async()=>{var y,w;try{await navigator.clipboard.writeText(l),i(!0),setTimeout(()=>i(!1),2e3)}catch{const k=s.current;if(k){const m=document.createRange();m.selectNodeContents(k),(y=window.getSelection())==null||y.removeAllRanges(),(w=window.getSelection())==null||w.addRange(m)}}},[l]),d=z.useCallback(()=>{var m;const y=new Blob([l],{type:"text/yaml"}),w=URL.createObjectURL(y),k=document.createElement("a");k.href=w,k.download=`${((m=e.name)==null?void 0:m.replace(/\s+/g,"-").toLowerCase())||"architecture"}.yaml`,k.click(),URL.revokeObjectURL(w)},[l,e.name]);return f.jsxs("div",{style:{padding:32,maxWidth:960},children:[f.jsxs("div",{style:{display:"flex",alignItems:"baseline",gap:12,marginBottom:20},children:[f.jsx("h2",{style:{fontSize:18,color:"#0f172a",fontWeight:700,margin:0},children:e.name||"Architecture Spec"}),e.provider&&f.jsx("span",{style:{fontSize:12,fontWeight:600,color:"#475569",background:"#f1f5f9",padding:"2px 8px",borderRadius:4},children:e.provider.toUpperCase()}),e.region&&f.jsx("span",{style:{fontSize:12,color:"#94a3b8"},children:e.region})]}),f.jsx("div",{style:{display:"flex",gap:0,marginBottom:20,borderBottom:"1px solid #e2e8f0"},children:["overview","yaml"].map(y=>f.jsx("button",{onClick:()=>r(y),style:{padding:"8px 18px",background:"none",border:"none",borderBottom:n===y?"2px solid #2563eb":"2px solid transparent",color:n===y?"#1d4ed8":"#64748b",fontWeight:n===y?600:500,fontSize:13,cursor:"pointer",transition:"all 0.15s ease"},children:y==="overview"?"Overview":"YAML Source"},y))}),n==="overview"&&f.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:20},children:[f.jsxs("div",{style:{display:"flex",gap:12},children:[f.jsx(Mi,{label:"Components",value:e.components.length}),f.jsx(Mi,{label:"Connections",value:e.connections.length}),f.jsx(Mi,{label:"Services",value:u.length,sub:a.join(", ")}),e.cost_estimate&&f.jsx(Mi,{label:"Monthly Cost",value:`$${e.cost_estimate.monthly_total.toLocaleString()}`,sub:e.cost_estimate.currency})]}),f.jsx("div",{style:{border:"1px solid #e2e8f0",borderRadius:10,overflow:"hidden"},children:f.jsxs("table",{style:{width:"100%",borderCollapse:"collapse",fontSize:13},children:[f.jsx("thead",{children:f.jsxs("tr",{style:{background:"#f8fafc"},children:[f.jsx("th",{style:xt,children:"Component"}),f.jsx("th",{style:xt,children:"Service"}),f.jsx("th",{style:xt,children:"Provider"}),f.jsx("th",{style:xt,children:"Tier"}),f.jsx("th",{style:xt,children:"Description"})]})}),f.jsx("tbody",{children:Object.keys(p).map(Number).sort().flatMap(y=>p[y].map(w=>f.jsxs("tr",{style:{borderBottom:"1px solid #f1f5f9"},children:[f.jsxs("td",{style:vt,children:[f.jsx("span",{style:{fontWeight:600,color:"#0f172a"},children:w.label}),f.jsx("div",{style:{fontSize:11,color:"#94a3b8"},children:w.id})]}),f.jsx("td",{style:vt,children:f.jsx("code",{style:{fontSize:12,background:"#f1f5f9",padding:"1px 6px",borderRadius:3,color:"#334155"},children:w.service})}),f.jsx("td",{style:vt,children:f.jsx("span",{style:{fontSize:12,color:"#475569"},children:w.provider})}),f.jsx("td",{style:vt,children:f.jsx("span",{style:{fontSize:11,fontWeight:600,color:"#64748b",background:"#f1f5f9",padding:"2px 8px",borderRadius:4},children:FC[y]||`Tier ${y}`})}),f.jsx("td",{style:{...vt,color:"#64748b",maxWidth:240},children:w.description})]},w.id)))})]})}),e.connections.length>0&&f.jsxs("div",{style:{border:"1px solid #e2e8f0",borderRadius:10,overflow:"hidden"},children:[f.jsxs("div",{style:{padding:"10px 16px",background:"#f8fafc",borderBottom:"1px solid #e2e8f0",fontSize:13,fontWeight:600,color:"#0f172a"},children:["Connections (",e.connections.length,")"]}),f.jsxs("table",{style:{width:"100%",borderCollapse:"collapse",fontSize:13},children:[f.jsx("thead",{children:f.jsxs("tr",{style:{background:"#fafafa"},children:[f.jsx("th",{style:xt,children:"Source"}),f.jsx("th",{style:xt}),f.jsx("th",{style:xt,children:"Target"}),f.jsx("th",{style:xt,children:"Protocol"}),f.jsx("th",{style:xt,children:"Label"})]})}),f.jsx("tbody",{children:e.connections.map((y,w)=>{const k=e.components.find(g=>g.id===y.source),m=e.components.find(g=>g.id===y.target);return f.jsxs("tr",{style:{borderBottom:"1px solid #f1f5f9"},children:[f.jsx("td",{style:vt,children:f.jsx("span",{style:{fontWeight:500,color:"#0f172a"},children:(k==null?void 0:k.label)||y.source})}),f.jsx("td",{style:{...vt,textAlign:"center",color:"#94a3b8",fontSize:14},children:"→"}),f.jsx("td",{style:vt,children:f.jsx("span",{style:{fontWeight:500,color:"#0f172a"},children:(m==null?void 0:m.label)||y.target})}),f.jsx("td",{style:vt,children:y.protocol&&f.jsxs("code",{style:{fontSize:11,background:"#f1f5f9",padding:"1px 6px",borderRadius:3,color:"#334155"},children:[y.protocol,y.port?`:${y.port}`:""]})}),f.jsx("td",{style:{...vt,color:"#64748b"},children:y.label})]},w)})})]})]}),e.boundaries&&e.boundaries.length>0&&f.jsxs("div",{style:{border:"1px solid #e2e8f0",borderRadius:10,overflow:"hidden"},children:[f.jsxs("div",{style:{padding:"10px 16px",background:"#f8fafc",borderBottom:"1px solid #e2e8f0",fontSize:13,fontWeight:600,color:"#0f172a"},children:["Boundaries (",e.boundaries.length,")"]}),f.jsx("div",{style:{padding:16,display:"flex",flexWrap:"wrap",gap:10},children:e.boundaries.map(y=>f.jsxs("div",{style:{padding:"8px 14px",border:"1px dashed #cbd5e1",borderRadius:8,background:"#fafafa",fontSize:13},children:[f.jsx("div",{style:{fontWeight:600,color:"#0f172a"},children:y.label||y.id}),f.jsxs("div",{style:{fontSize:11,color:"#94a3b8"},children:[y.kind," · ",y.component_ids.length," components"]})]},y.id))})]})]}),n==="yaml"&&f.jsxs("div",{style:{border:"1px solid #e2e8f0",borderRadius:10,overflow:"hidden"},children:[f.jsxs("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",padding:"8px 14px",background:"#f8fafc",borderBottom:"1px solid #e2e8f0"},children:[f.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8},children:[f.jsx("span",{style:{fontSize:10,fontWeight:700,color:"#7c3aed",background:"#7c3aed14",padding:"2px 8px",borderRadius:4},children:"YAML"}),f.jsxs("span",{style:{fontSize:12,color:"#64748b"},children:[((x=e.name)==null?void 0:x.replace(/\s+/g,"-").toLowerCase())||"architecture",".yaml"]}),f.jsxs("span",{style:{fontSize:11,color:"#cbd5e1"},children:[l.split(` -`).length," lines"]})]}),f.jsxs("div",{style:{display:"flex",gap:6},children:[f.jsx("button",{onClick:c,style:{padding:"4px 12px",borderRadius:4,border:"1px solid #e2e8f0",background:o?"#dcfce7":"#ffffff",color:o?"#166534":"#475569",cursor:"pointer",fontSize:12,fontWeight:500,transition:"all 0.15s ease"},children:o?"Copied":"Copy"}),f.jsx("button",{onClick:d,style:{padding:"4px 12px",borderRadius:4,border:"1px solid #e2e8f0",background:"#ffffff",color:"#475569",cursor:"pointer",fontSize:12,fontWeight:500},children:"Download"})]})]}),f.jsx("div",{style:{maxHeight:600,overflow:"auto"},children:f.jsx("pre",{ref:s,style:{margin:0,padding:16,fontSize:13,lineHeight:1.7,color:"#334155",background:"#ffffff",fontFamily:"'SF Mono', 'Cascadia Code', 'Fira Code', Menlo, monospace",whiteSpace:"pre-wrap",wordBreak:"break-word"},children:l||"No YAML available"})})]})]})}const xt={padding:"10px 14px",textAlign:"left",fontSize:11,fontWeight:600,color:"#64748b",textTransform:"uppercase",letterSpacing:"0.05em"},vt={padding:"10px 14px",color:"#0f172a"},Ze="/api",VC=["Add caching layer","Reduce cost","Increase redundancy","Add monitoring","Add security"];function ep(e){var s;if((s=e.metadata)!=null&&s.suggestions&&e.metadata.suggestions.length>0)return e.metadata.suggestions.slice(0,3);const t=e.components.map(l=>l.label.toLowerCase()),n=e.components.map(l=>l.service.toLowerCase()),r=t.some(l=>l.includes("cache")||l.includes("redis")||l.includes("elasticache"))||n.some(l=>l.includes("cache")||l.includes("redis")),o=t.some(l=>l.includes("monitor")||l.includes("cloudwatch")||l.includes("grafana"))||n.some(l=>l.includes("cloudwatch")||l.includes("monitor")),i=t.some(l=>l.includes("waf")||l.includes("firewall")||l.includes("security"))||n.some(l=>l.includes("waf")||l.includes("shield"));return VC.filter(l=>!(l==="Add caching layer"&&r||l==="Add monitoring"&&o||l==="Add security"&&i)).slice(0,3)}function WC(e){return e.split(/(\*\*.*?\*\*)/g).map((t,n)=>t.startsWith("**")&&t.endsWith("**")?f.jsx("strong",{children:t.slice(2,-2)},n):f.jsx("span",{children:t},n))}async function Kl(e,t){var i;let n=e;const[r,o]=await Promise.all([fetch(`${Ze}/cost`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({spec:n})}).then(s=>s.ok?s.json():null).catch(()=>null),fetch(`${Ze}/validate`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({spec:n,compliance:[],well_architected:!0})}).then(s=>s.ok?s.json():null).catch(()=>null)]);if(r!=null&&r.estimate&&(n={...n,cost_estimate:r.estimate}),((i=o==null?void 0:o.results)==null?void 0:i.length)>0){const s=o.results[0].checks||[],l=s.filter(a=>a.passed).length;t({passed:l,total:s.length})}return n}async function tp(e,t,n){var a;const r=e?`${Ze}/modify/stream`:`${Ze}/design/stream`,o=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)});if(!o.ok){n.onError(await Go(o));return}const i=(a=o.body)==null?void 0:a.getReader();if(!i)return;const s=new TextDecoder;let l="";for(;;){const{done:u,value:p}=await i.read();if(u)break;l+=s.decode(p,{stream:!0});const c=l.split(` -`);l=c.pop()||"";for(const d of c)if(d.startsWith("data: "))try{const x=JSON.parse(d.slice(6));switch(x.stage){case"generating":case"costing":case"validating":n.onStage(x.stage,x.message);break;case"generated":n.onSpec(x.spec,x.yaml),x.usage&&n.onUsage&&n.onUsage(x.usage);break;case"costed":n.onCost(x.cost_estimate);break;case"validated":n.onValidation(x.passed,x.total);break;case"done":n.onDone(x.spec,x.yaml),x.usage&&n.onUsage&&n.onUsage(x.usage);break;case"error":n.onError(x.message);break}}catch{}}}function UC(){var _;const[e,t]=z.useState([]),[n,r]=z.useState(""),[o,i]=z.useState("idle"),[s,l]=z.useState(null),[a,u]=z.useState("diagram"),[p,c]=z.useState(""),[d,x]=z.useState(null),[y,w]=z.useState(null),k=z.useRef(null),m=z.useRef(null);z.useEffect(()=>{var S;(S=m.current)==null||S.scrollIntoView({behavior:"smooth"})},[e]);const g=async()=>{var T;if(!n.trim()||o!=="idle")return;const S={role:"user",content:n};t(I=>[...I,S]),r("");const E=s!==null;i(E?"modifying":"generating");let b=null,A="",D=!1;try{const I=E?{spec:s,instruction:n}:{description:n};try{await tp(E,I,{onStage:M=>{M==="generating"?i("generating"):(M==="costing"||M==="validating")&&i("costing")},onSpec:M=>{l(M),b=M,i("costing")},onCost:M=>{M&&b&&(b={...b,cost_estimate:M},l(b))},onValidation:(M,R)=>{M!==null&&x({passed:M,total:R})},onDone:(M,R)=>{b=M,A=R,l(M),i("done")},onUsage:M=>w(M),onError:M=>{throw new Error(M)}}),D=b!==null}catch{i(E?"modifying":"generating")}if(!D){const M=E?await fetch(`${Ze}/modify`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({spec:s,instruction:n})}):await fetch(`${Ze}/design`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({description:n})}),R=await M.json();if(!M.ok)throw new Error(su(R));b=R.spec,A=R.yaml,R.usage&&w(R.usage),i("costing"),b=await Kl(b,x),l(b),i("done")}const P=b,L={role:"assistant",content:`${E?"Modified":"Designed"} **${P.name}** with ${P.components.length} components on ${P.provider.toUpperCase()}.${P.cost_estimate?` Estimated cost: $${P.cost_estimate.monthly_total.toFixed(2)}/mo.`:""}`,spec:P,yaml:A,suggestions:ep(P)};t(M=>[...M,L]),u("diagram")}catch(I){const P=I instanceof Error?I.message:"Unknown error";t(C=>[...C,{role:"assistant",content:`Error: ${P}`}])}finally{i("idle"),(T=k.current)==null||T.focus()}},h=async S=>{if(s)try{const E=await fetch(`${Ze}/download`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({spec:s,format:S})});if(!E.ok)return;const b=await E.blob(),D=(E.headers.get("Content-Disposition")||"").match(/filename=([^\s;]+)/),T=D?D[1]:`architecture.${S==="terraform"?"tf":"yaml"}`,I=URL.createObjectURL(b),P=document.createElement("a");P.href=I,P.download=T,P.click(),URL.revokeObjectURL(I)}catch{}},v=async S=>{l(S),x(null);try{const E=await Kl(S,x);l(E)}catch{}};return f.jsxs("div",{style:{display:"flex",height:"100vh",background:"#ffffff"},children:[f.jsxs("div",{style:{width:420,borderRight:"1px solid #e2e8f0",display:"flex",flexDirection:"column",background:"#f8fafc"},children:[f.jsxs("div",{style:{padding:"16px 20px",borderBottom:"1px solid #e2e8f0",display:"flex",alignItems:"center",justifyContent:"space-between"},children:[f.jsxs("div",{children:[f.jsx("h1",{style:{fontSize:20,fontWeight:700,color:"#0f172a"},children:"Cloudwright"}),f.jsx("p",{style:{fontSize:12,color:"#64748b",marginTop:4},children:"Architecture Intelligence"})]}),s&&f.jsx("button",{onClick:()=>{if(window.confirm("Discard current session and start fresh?")){try{localStorage.setItem("cloudwright_last_session",JSON.stringify(e))}catch{}l(null),t([]),x(null)}},style:{padding:"5px 12px",borderRadius:6,border:"1px solid #e2e8f0",background:"#ffffff",color:"#64748b",cursor:"pointer",fontSize:12,fontWeight:500},children:"New"})]}),f.jsxs("div",{style:{flex:1,overflowY:"auto",padding:16},children:[e.length===0&&f.jsxs("div",{style:{color:"#64748b",padding:20,textAlign:"center"},children:[f.jsx("p",{style:{fontSize:14},children:"Describe your cloud architecture"}),f.jsx("p",{style:{fontSize:12,marginTop:8,color:"#94a3b8"},children:'"3-tier web app on AWS with CloudFront, ALB, EC2, and RDS"'})]}),e.map((S,E)=>f.jsxs("div",{style:{marginBottom:12},children:[f.jsx("div",{style:{padding:"10px 14px",borderRadius:8,background:S.role==="user"?"#2563eb":"#f1f5f9",color:S.role==="user"?"#ffffff":"#1e293b",fontSize:14,lineHeight:1.5},children:WC(S.content)}),S.role==="assistant"&&S.spec&&S.suggestions&&S.suggestions.length>0&&f.jsx("div",{style:{display:"flex",gap:6,marginTop:6,flexWrap:"wrap"},children:S.suggestions.map(b=>f.jsx("button",{onClick:()=>{var A;r(b),(A=k.current)==null||A.focus()},disabled:o!=="idle",style:{padding:"4px 10px",borderRadius:12,border:"1px solid #cbd5e1",background:"#ffffff",color:"#2563eb",cursor:o!=="idle"?"not-allowed":"pointer",fontSize:12,fontWeight:500},children:b},b))})]},E)),o!=="idle"&&f.jsxs("div",{style:{padding:"10px 14px",color:"#64748b",fontSize:14},children:[o==="generating"&&"Generating architecture...",o==="modifying"&&"Modifying architecture...",o==="costing"&&"Estimating cost & validating...",o==="done"&&"Finalizing..."]}),f.jsx("div",{ref:m})]}),f.jsx("div",{style:{padding:16,borderTop:"1px solid #e2e8f0"},children:f.jsxs("div",{style:{display:"flex",gap:8},children:[f.jsx("input",{ref:k,value:n,onChange:S=>r(S.target.value),onKeyDown:S=>S.key==="Enter"&&g(),placeholder:"Describe your architecture...",style:{flex:1,padding:"10px 14px",borderRadius:8,border:"1px solid #e2e8f0",background:"#ffffff",color:"#0f172a",fontSize:14,outline:"none"}}),f.jsx("button",{onClick:g,disabled:o!=="idle"||!n.trim(),style:{padding:"10px 20px",borderRadius:8,border:"none",background:o!=="idle"?"#e2e8f0":"#2563eb",color:o!=="idle"?"#94a3b8":"#fff",cursor:o!=="idle"?"not-allowed":"pointer",fontSize:14,fontWeight:600},children:"Send"})]})})]}),f.jsxs("div",{style:{flex:1,display:"flex",flexDirection:"column",background:"#ffffff"},children:[f.jsx("div",{style:{display:"flex",borderBottom:"1px solid #e2e8f0",background:"#ffffff"},children:["diagram","cost","validate","compliance","plan","export","spec","modify"].map(S=>f.jsx("button",{onClick:()=>u(S),style:{padding:"12px 24px",border:"none",borderBottom:a===S?"2px solid #2563eb":"2px solid transparent",background:"transparent",color:a===S?"#2563eb":"#64748b",cursor:"pointer",fontSize:14,fontWeight:500,textTransform:"capitalize"},children:S},S))}),f.jsxs("div",{style:{flex:1,overflow:"auto",display:"flex",flexDirection:"column"},children:[f.jsx("div",{style:{padding:"0.5rem 1rem"},children:f.jsx(zC,{spec:s,onDownloadTerraform:s?()=>h("terraform"):void 0,onDownloadYaml:s?()=>h("yaml"):void 0,validationSummary:d,usage:y})}),f.jsxs("div",{style:{flex:1,overflow:"auto"},children:[a==="diagram"&&(s||o!=="idle")&&f.jsxs("div",{style:{position:"relative",width:"100%",height:"100%"},children:[s&&f.jsx(jC,{spec:s,onSpecChange:v}),o!=="idle"&&f.jsxs("div",{style:{position:"absolute",top:16,right:16,background:"rgba(37, 99, 235, 0.9)",color:"white",padding:"8px 16px",borderRadius:8,fontSize:13,fontWeight:500,display:"flex",alignItems:"center",gap:8},children:[f.jsx("span",{style:{width:8,height:8,borderRadius:"50%",background:"white",animation:"pulse 1s infinite"}}),o==="generating"?"Generating...":o==="modifying"?"Modifying...":o==="costing"?"Costing & validating...":"Finalizing..."]})]}),a==="diagram"&&!s&&o==="idle"&&f.jsx("div",{style:{padding:32,color:"#64748b"},children:"Design an architecture to see the diagram."}),a==="cost"&&(s==null?void 0:s.cost_estimate)&&f.jsx(MC,{estimate:s.cost_estimate}),a==="cost"&&(!s||!s.cost_estimate)&&f.jsx("div",{style:{padding:32,color:"#64748b"},children:"No cost estimate available."}),a==="spec"&&s&&f.jsx(HC,{spec:s,yaml:((_=e.findLast(S=>S.yaml))==null?void 0:_.yaml)||"No YAML available"}),a==="spec"&&!s&&f.jsx("div",{style:{padding:32,color:"#64748b"},children:"Design an architecture first."}),a==="validate"&&s&&f.jsx(LC,{spec:s,apiBase:Ze}),a==="validate"&&!s&&f.jsx("div",{style:{padding:32,color:"#64748b"},children:"Design an architecture first."}),a==="compliance"&&s&&f.jsx($C,{spec:s,apiBase:Ze}),a==="compliance"&&!s&&f.jsx("div",{style:{padding:32,color:"#64748b"},children:"Design an architecture first."}),a==="plan"&&s&&f.jsx(OC,{spec:s,apiBase:Ze}),a==="plan"&&!s&&f.jsx("div",{style:{padding:32,color:"#64748b"},children:"Design an architecture first."}),a==="export"&&s&&f.jsx(BC,{spec:s,apiBase:Ze}),a==="export"&&!s&&f.jsx("div",{style:{padding:32,color:"#64748b"},children:"Design an architecture first."}),a==="modify"&&s&&f.jsxs("div",{style:{padding:32,maxWidth:800},children:[f.jsx("h2",{style:{fontSize:18,marginBottom:16,color:"#0f172a"},children:"Modify Architecture"}),o!=="idle"&&f.jsxs("div",{style:{marginBottom:12,fontSize:13,color:"#64748b"},children:[o==="modifying"&&"Modifying architecture...",o==="costing"&&"Estimating cost & validating...",o==="done"&&"Finalizing..."]}),f.jsx("div",{style:{display:"flex",gap:8},children:f.jsx("input",{value:p,onChange:S=>c(S.target.value),onKeyDown:async S=>{if(S.key==="Enter"&&p.trim()&&o==="idle"){const E=p;c(""),i("modifying");let b=null,A="",D=!1;try{try{await tp(!0,{spec:s,instruction:E},{onStage:I=>{I==="generating"?i("modifying"):(I==="costing"||I==="validating")&&i("costing")},onSpec:I=>{l(I),b=I,i("costing")},onCost:I=>{I&&b&&(b={...b,cost_estimate:I},l(b))},onValidation:(I,P)=>{I!==null&&x({passed:I,total:P})},onDone:(I,P)=>{b=I,A=P,l(I),i("done")},onUsage:I=>w(I),onError:I=>{throw new Error(I)}}),D=b!==null}catch{i("modifying")}if(!D){const I=await fetch(`${Ze}/modify`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({spec:s,instruction:E})}),P=await I.json();if(!I.ok)throw new Error(su(P,"Modification failed"));P.usage&&w(P.usage);const C=P.spec;A=P.yaml,i("costing"),b=await Kl(C,x),l(b),i("done")}const T=b;t(I=>[...I,{role:"user",content:E},{role:"assistant",content:`Modified **${T.name}** with ${T.components.length} components on ${T.provider.toUpperCase()}.${T.cost_estimate?` Estimated cost: $${T.cost_estimate.monthly_total.toFixed(2)}/mo.`:""}`,spec:T,yaml:A,suggestions:ep(T)}])}catch(T){t(I=>[...I,{role:"user",content:E},{role:"assistant",content:`Error: ${T instanceof Error?T.message:"Modification failed"}`}])}finally{i("idle")}}},placeholder:"e.g. Add a Redis cache between web and database",style:{flex:1,padding:"10px 14px",borderRadius:8,border:"1px solid #e2e8f0",background:"#ffffff",color:"#0f172a",fontSize:14,outline:"none"}})}),f.jsx("p",{style:{fontSize:12,color:"#64748b",marginTop:8},children:"Press Enter to apply modification"})]}),a==="modify"&&!s&&f.jsx("div",{style:{padding:32,color:"#64748b"},children:"Design an architecture first."})]})]})]})]})}Zl.createRoot(document.getElementById("root")).render(f.jsx(pp.StrictMode,{children:f.jsx(UC,{})})); diff --git a/packages/web/cloudwright_web/static/index.html b/packages/web/cloudwright_web/static/index.html index ac78efa..1bc55bb 100644 --- a/packages/web/cloudwright_web/static/index.html +++ b/packages/web/cloudwright_web/static/index.html @@ -8,7 +8,7 @@ * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #ffffff; color: #0f172a; } - + diff --git a/packages/web/frontend/src/App.tsx b/packages/web/frontend/src/App.tsx index b760fa1..6175ca1 100644 --- a/packages/web/frontend/src/App.tsx +++ b/packages/web/frontend/src/App.tsx @@ -5,6 +5,7 @@ import SummaryBar from "./components/SummaryBar"; import ValidationPanel from "./components/ValidationPanel"; import CompliancePanel from "./components/CompliancePanel"; import PlanPanel from "./components/PlanPanel"; +import ReviewPanel from "./components/ReviewPanel"; import ExportPanel from "./components/ExportPanel"; import SpecPanel from "./components/SpecPanel"; import { parseApiError, formatApiError } from "./lib/apiError"; @@ -224,7 +225,7 @@ function App() { const [loadingStage, setLoadingStage] = useState("idle"); const [currentSpec, setCurrentSpec] = useState(null); const [activeTab, setActiveTab] = useState< - "diagram" | "cost" | "validate" | "compliance" | "plan" | "export" | "spec" | "modify" + "diagram" | "cost" | "validate" | "compliance" | "plan" | "review" | "export" | "spec" | "modify" >("diagram"); const [modifyInput, setModifyInput] = useState(""); @@ -514,7 +515,7 @@ function App() {
{/* Tabs */}
- {(["diagram", "cost", "validate", "compliance", "plan", "export", "spec", "modify"] as const).map((tab) => ( + {(["diagram", "cost", "validate", "compliance", "plan", "review", "export", "spec", "modify"] as const).map((tab) => ( + setIncludeOscal(e.target.checked)} + /> + Include OSCAL 1.1.2 component-definition export + + +
+ + + {report?.oscal && ( + + )} +
{error && (
; + apiBase: string; +} + +const SEV_COLORS: Record = { + critical: { bg: "#fef2f2", text: "#991b1b", border: "#fca5a5" }, + high: { bg: "#fff7ed", text: "#9a3412", border: "#fdba74" }, + medium: { bg: "#fffbeb", text: "#92400e", border: "#fcd34d" }, + low: { bg: "#f0fdf4", text: "#166534", border: "#86efac" }, +}; + +export default function ReviewPanel({ spec, apiBase }: ReviewPanelProps) { + const [wellArchitected, setWellArchitected] = useState(false); + const [report, setReport] = useState(null); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + + const run = useCallback(async () => { + setLoading(true); + setError(null); + try { + const res = await fetch(`${apiBase}/review`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ spec, well_architected: wellArchitected }), + }); + if (!res.ok) throw new Error(await parseApiError(res)); + setReport((await res.json()) as CritiqueReport); + } catch (e) { + setError(e instanceof Error ? e.message : "Review failed"); + } finally { + setLoading(false); + } + }, [spec, apiBase, wellArchitected]); + + return ( +
+

Architecture Review

+

+ Deterministic critique — scorer, linter, and validator merged into one severity-ranked + report. Runs offline, no LLM call. +

+ + + + + + {error && ( +
+ {error} +
+ )} + + {report && ( +
+
+ {report.score.toFixed(0)}/100 (grade {report.grade}) + + {report.blocking_count === 0 + ? "no blocking findings" + : `${report.blocking_count} blocking finding(s)`} + +
+ +

+ Findings ({report.findings.length}) +

+ + {report.findings.length === 0 ? ( +
+ No findings. This architecture passes every critic. +
+ ) : ( + report.findings.map((f, i) => { + const c = SEV_COLORS[f.severity] || SEV_COLORS.low; + return ( +
+
+ + [{f.severity}] + + {f.message} + ({f.source}) +
+ {f.recommendation && ( +
+ {f.recommendation} +
+ )} +
+ ); + }) + )} +
+ )} +
+ ); +} diff --git a/packages/web/tests/test_review_and_oscal.py b/packages/web/tests/test_review_and_oscal.py new file mode 100644 index 0000000..890cce8 --- /dev/null +++ b/packages/web/tests/test_review_and_oscal.py @@ -0,0 +1,146 @@ +"""Web surface for the v1.6.0 differentiating features: offline review and OSCAL. + +Prior to this, ``cloudwright review`` (deterministic critique) and +``cloudwright compliance --oscal`` (OSCAL 1.1.2 component-definition export) +were CLI-only. These tests cover the new ``POST /api/review`` route and the +``oscal`` flag on ``POST /api/compliance``. +""" + +from __future__ import annotations + +import pytest +from fastapi.testclient import TestClient + + +@pytest.fixture +def client(): + from cloudwright_web.app import app + + return TestClient(app) + + +def _sample_spec() -> dict: + return { + "name": "Sample", + "provider": "aws", + "region": "us-east-1", + "components": [ + { + "id": "web", + "service": "ec2", + "provider": "aws", + "label": "Web Server", + "tier": 2, + "description": "", + "config": {}, + }, + { + "id": "db", + "service": "rds", + "provider": "aws", + "label": "Database", + "tier": 3, + "description": "", + "config": {}, + }, + ], + } + + +class TestReviewEndpoint: + def test_review_returns_expected_keys_for_valid_spec(self, client): + resp = client.post("/api/review", json={"spec": _sample_spec()}) + + assert resp.status_code == 200 + data = resp.json() + assert "score" in data + assert "grade" in data + assert "findings" in data + assert "blocking_count" in data + assert "summary" in data + assert isinstance(data["findings"], list) + + def test_review_accepts_compliance_and_well_architected(self, client): + resp = client.post( + "/api/review", + json={"spec": _sample_spec(), "compliance": ["hipaa"], "well_architected": True}, + ) + + assert resp.status_code == 200 + data = resp.json() + assert "findings" in data + + def test_review_bad_body_returns_structured_4xx(self, client): + resp = client.post("/api/review", json={"spec": {"provider": "aws"}}) + + assert 400 <= resp.status_code < 500 + assert resp.json() + + def test_review_missing_spec_field_returns_422(self, client): + resp = client.post("/api/review", json={}) + + assert resp.status_code == 422 + + def test_review_rejects_over_component_limit(self, client): + spec = _sample_spec() + spec["components"] = [ + { + "id": f"c{i}", + "service": "lambda", + "provider": "aws", + "label": f"L{i}", + "tier": 2, + "description": "", + "config": {}, + } + for i in range(201) + ] + resp = client.post("/api/review", json={"spec": spec}) + + assert resp.status_code == 422 + + def test_review_works_with_no_api_key(self, client): + """CLOUDWRIGHT_API_KEY is unset in the test env; auth must no-op.""" + resp = client.post("/api/review", json={"spec": _sample_spec()}) + + assert resp.status_code != 401 + + +class TestComplianceOscalExport: + def test_compliance_without_oscal_flag_has_no_oscal_key(self, client): + resp = client.post("/api/compliance", json={"spec": _sample_spec()}) + + assert resp.status_code == 200 + assert "oscal" not in resp.json() + + def test_compliance_oscal_flag_returns_component_definition_shape(self, client): + resp = client.post( + "/api/compliance", + json={"spec": _sample_spec(), "frameworks": ["hipaa"], "oscal": True}, + ) + + assert resp.status_code == 200 + data = resp.json() + assert "oscal" in data + oscal_doc = data["oscal"] + assert "component-definition" in oscal_doc + component_def = oscal_doc["component-definition"] + assert "uuid" in component_def + assert "metadata" in component_def + assert "components" in component_def + + def test_compliance_oscal_bad_body_returns_structured_4xx(self, client): + resp = client.post( + "/api/compliance", + json={"spec": {"provider": "aws"}, "oscal": True}, + ) + + assert 400 <= resp.status_code < 500 + + def test_compliance_oscal_works_with_no_api_key(self, client): + resp = client.post( + "/api/compliance", + json={"spec": _sample_spec(), "oscal": True}, + ) + + assert resp.status_code != 401 From 132de39d1dee53055848e18d402d017cd23c8aaf Mon Sep 17 00:00:00 2001 From: Xavier Puspus <36430014+xmpuspus@users.noreply.github.com> Date: Wed, 8 Jul 2026 07:16:00 -0700 Subject: [PATCH 07/10] Add 'cloudwright integrate': per-harness MCP config + rules generator for 11 coding agents --- docs/integrations.md | 123 ++++ .../cloudwright_cli/commands/integrate_cmd.py | 618 ++++++++++++++++++ packages/cli/cloudwright_cli/main.py | 2 + packages/cli/tests/test_integrate.py | 273 ++++++++ 4 files changed, 1016 insertions(+) create mode 100644 docs/integrations.md create mode 100644 packages/cli/cloudwright_cli/commands/integrate_cmd.py create mode 100644 packages/cli/tests/test_integrate.py diff --git a/docs/integrations.md b/docs/integrations.md new file mode 100644 index 0000000..88d1590 --- /dev/null +++ b/docs/integrations.md @@ -0,0 +1,123 @@ +# Harness Integrations + +Cloudwright ships an MCP server (`cloudwright mcp`), a CLI, and a GitHub Action. Most AI coding +harnesses in 2026 are MCP clients, so one server reaches almost all of them, but each harness +wants the server entry in a different file, under a different JSON (or TOML) key, and each has +its own convention for the plain-text rules file that steers agent behavior. This page is the +per-harness wiring reference. Run `cloudwright integrate --list` for the same table from the +terminal, and `cloudwright integrate --harness ` for the exact snippet plus `--write` to +drop it straight into the right file. + +Related: [MCP Reference](mcp-reference.md) | [CLI Reference](cli-reference.md) | [GitHub Action](github-action.md) | [README](../README.md) + +--- + +## How the MCP server launches + +There is no separate console script for the MCP server. Every harness below launches it the same +way: command `cloudwright`, args `["mcp"]` (the server defaults to stdio transport; pass +`["mcp", "--transport", "stdio"]` if a harness wants that spelled out explicitly). The differences +between harnesses are entirely in where that command/args pair goes and what key it sits under. + +--- + +## Harness table + +| Harness | MCP client? | Config file and key | Rules file | How to wire | +|---|---|---|---|---| +| Claude Code | Yes | `.mcp.json` (project) or `~/.claude.json` (user), key `mcpServers` | `CLAUDE.md` (does not read AGENTS.md) | `cloudwright integrate --harness claude-code --write` | +| Cursor | Yes | `.cursor/mcp.json` (project) or `~/.cursor/mcp.json`, key `mcpServers` | `AGENTS.md` (native) plus `.cursor/rules/*.mdc` | `cloudwright integrate --harness cursor --write` | +| Cline | Yes | `cline_mcp_settings.json` under the VS Code extension's global storage, key `mcpServers` | `.clinerules` (AGENTS.md support is global-only and contested) | `cloudwright integrate --harness cline --write --output ` | +| Windsurf | Yes | `~/.codeium/windsurf/mcp_config.json`, key `mcpServers` | `.windsurfrules` (also reads AGENTS.md) | `cloudwright integrate --harness windsurf --write` | +| GitHub Copilot | Yes | `.vscode/mcp.json`, key `servers` (not `mcpServers`), entries need `"type": "stdio"` | `.github/copilot-instructions.md` plus native AGENTS.md | `cloudwright integrate --harness copilot --write` | +| Zed | Yes | `.zed/settings.json` (project) or `~/.config/zed/settings.json`, key `context_servers` | `.rules` (falls back to AGENTS.md) | `cloudwright integrate --harness zed --write` | +| OpenAI Codex CLI | Yes | `~/.codex/config.toml`, TOML table `[mcp_servers.cloudwright]` | `AGENTS.md` (canonical origin of the convention) | `cloudwright integrate --harness codex --write` | +| JetBrains Junie | Yes | `.junie/mcp/mcp.json`, key `mcpServers` | `AGENTS.md` (primary), `.junie/guidelines.md` (legacy fallback) | `cloudwright integrate --harness junie --write` | +| Kiro | Yes | `.kiro/settings/mcp.json` (project) or `~/.kiro/settings/mcp.json`, key `mcpServers` | `.kiro/steering/*.md` (own convention); list AGENTS.md too | `cloudwright integrate --harness kiro --write` | +| Antigravity | Yes | `~/.gemini/config/mcp_config.json`, key `mcpServers` | `AGENTS.md`; confirm whether `GEMINI.md` still applies | `cloudwright integrate --harness antigravity --write` | +| Aider | No | n/a | `AGENTS.md` | See "Not an MCP client" below | + +--- + +## Not an MCP client: Aider + +Aider has no shipped MCP integration. Use the CLI pipe path instead: from an Aider session, run + +``` +/run cloudwright design "" --json +``` + +and parse the structured output directly. `cloudwright integrate --harness aider` prints this +guidance along with the rules-file note (Aider reads `AGENTS.md` natively, same as most of the +harnesses above). Unofficial third-party MCP bridges for Aider exist (`mcpm-aider`, +`aider-mcp-server`) but are not something cloudwright depends on for a supported path. + +--- + +## Discontinued or superseded (not generated by `integrate`) + +`cloudwright integrate` does not generate configs for these; asking for one by name returns a +message pointing at the live successor instead. + +- **Roo Code** was sunset in April 2026 and its repo was archived in May 2026. No successor is + tracked here. +- **Continue.dev** was acquired by Cursor in June 2026; its repo is now read-only. Wire Cursor + instead. +- **Amazon Q Developer** is being sunset by AWS in favor of **Kiro**, which carries over MCP + support. Use `cloudwright integrate --harness kiro`. +- **Google Gemini CLI** stopped serving individual/free-tier users in June 2026 in favor of + **Antigravity**. Use `cloudwright integrate --harness antigravity`. + +--- + +## The rules-file block + +`cloudwright integrate --rules` emits a short, harness-agnostic block that tells an agent to gate +infrastructure work through cloudwright: + +``` +## Cloudwright gate + +Before proposing, generating, or applying cloud infrastructure or Terraform, Pulumi, or +CloudFormation changes, run cloudwright first: + +- `cloudwright design "" --json` for a typed architecture spec +- `cloudwright review ` for an offline architecture critique (no LLM, free) +- `cloudwright cost ` for a per-component cost estimate +- `cloudwright compliance --frameworks ` for control-mapped findings + +Treat any high or critical review or compliance finding as a blocker. Fix it before writing +Terraform, Pulumi, or CloudFormation. +``` + +Use `--agent-file` to pick which file it targets: + +| `--agent-file` value | File | Why it exists as a separate target | +|---|---|---| +| `agents` (default) | `AGENTS.md` | Read natively by Cursor, Windsurf, Copilot, Codex, Junie, Aider, and Kiro; Zed falls back to it | +| `claude` | `CLAUDE.md` | Claude Code does not read AGENTS.md at all, so it needs its own copy | +| `gemini` | `GEMINI.md` | Gemini CLI's default context file; AGENTS.md is not read unless manually reconfigured | + +`--write` appends the block to the target file (creating it if missing) behind an HTML comment +marker so a second run does not duplicate it; pass `--force` to replace an already-installed +block in place. + +--- + +## Quick start + +```bash +# See every supported harness and what it needs +cloudwright integrate --list + +# Wire Claude Code and Cursor in one repo +cloudwright integrate --harness claude-code --write +cloudwright integrate --harness cursor --write + +# Add the gate instructions everywhere AGENTS.md is read, plus a CLAUDE.md copy for Claude Code +cloudwright integrate --rules --write +cloudwright integrate --rules --agent-file claude --write + +# Machine-readable output for scripting +cloudwright --json integrate --harness codex +``` diff --git a/packages/cli/cloudwright_cli/commands/integrate_cmd.py b/packages/cli/cloudwright_cli/commands/integrate_cmd.py new file mode 100644 index 0000000..3812143 --- /dev/null +++ b/packages/cli/cloudwright_cli/commands/integrate_cmd.py @@ -0,0 +1,618 @@ +"""Wire cloudwright into popular AI coding harnesses. + +Cloudwright ships an MCP server (`cloudwright mcp`), a CLI, and a GitHub Action. +Most harnesses are MCP clients but each wants its server entry in a different +file and under a different JSON/TOML key. This command prints (and optionally +writes) the exact wiring per harness, plus a harness-agnostic rules-file block +that tells an agent to gate infrastructure changes through cloudwright before +it writes Terraform, Pulumi, or CloudFormation. +""" + +from __future__ import annotations + +import json +from dataclasses import dataclass +from pathlib import Path +from typing import Annotated + +import typer +from rich.console import Console +from rich.panel import Panel +from rich.syntax import Syntax +from rich.table import Table + +from cloudwright_cli.output import emit_success, is_json_mode +from cloudwright_cli.utils import handle_error + +console = Console() + +_RULES_START = "" +_RULES_END = "" + +_RULES_BODY = ( + "## Cloudwright gate\n\n" + "Before proposing, generating, or applying cloud infrastructure or Terraform, Pulumi, " + "or CloudFormation changes, run cloudwright first:\n\n" + '- `cloudwright design "" --json` for a typed architecture spec\n' + "- `cloudwright review ` for an offline architecture critique (no LLM, free)\n" + "- `cloudwright cost ` for a per-component cost estimate\n" + "- `cloudwright compliance --frameworks ` for control-mapped findings\n\n" + "Treat any high or critical review or compliance finding as a blocker. Fix it before " + "writing Terraform, Pulumi, or CloudFormation.\n" +) + + +@dataclass(frozen=True) +class Harness: + key: str + name: str + mcp: bool + config_format: str | None = None # "json" | "toml" | None (non-MCP) + config_key: str | None = None + default_write_path: str | None = None + path_note: str = "" + entry_shape: str = "flat" # "flat" | "zed" + entry_extra: dict | None = None + rules_file: str = "AGENTS.md" + rules_note: str = "" + notes: tuple[str, ...] = () + + +_HARNESSES: dict[str, Harness] = { + "claude-code": Harness( + key="claude-code", + name="Claude Code", + mcp=True, + config_format="json", + config_key="mcpServers", + default_write_path=".mcp.json", + path_note="Project scope. User scope alternative: ~/.claude.json.", + rules_file="CLAUDE.md", + rules_note=( + "Claude Code does not read AGENTS.md natively (open GitHub issue, no roadmap " + "commitment as of mid-2026). Use CLAUDE.md, not AGENTS.md, for this harness." + ), + ), + "cursor": Harness( + key="cursor", + name="Cursor", + mcp=True, + config_format="json", + config_key="mcpServers", + default_write_path=".cursor/mcp.json", + path_note="Project scope, wins on name conflicts. User scope alternative: ~/.cursor/mcp.json.", + rules_file="AGENTS.md", + rules_note=( + "Cursor reads AGENTS.md natively. .cursor/rules/*.mdc is its own native rules " + "directory (replaces the old single .cursorrules file since v2.2+); keep both." + ), + ), + "cline": Harness( + key="cline", + name="Cline", + mcp=True, + config_format="json", + config_key="mcpServers", + default_write_path=None, + path_note=( + "cline_mcp_settings.json lives under the VS Code extension's global storage " + "directory (path varies by OS and extension version). Pass --output to point at " + "the exact file, or add the server through Cline's in-panel MCP Servers UI instead." + ), + rules_file=".clinerules", + rules_note=( + "Cline's AGENTS.md support is global-only (~/.agents/AGENTS.md) and contested by " + "maintainers; project-root AGENTS.md is not read." + ), + ), + "windsurf": Harness( + key="windsurf", + name="Windsurf", + mcp=True, + config_format="json", + config_key="mcpServers", + default_write_path="~/.codeium/windsurf/mcp_config.json", + path_note="Global only. Edit via Cmd/Ctrl+Shift+P -> Configure MCP Servers, or the in-app MCP Marketplace.", + rules_file=".windsurfrules", + rules_note="Windsurf also recognizes AGENTS.md alongside its native .windsurfrules / .windsurf/rules/*.md.", + ), + "copilot": Harness( + key="copilot", + name="GitHub Copilot", + mcp=True, + config_format="json", + config_key="servers", + entry_extra={"type": "stdio"}, + default_write_path=".vscode/mcp.json", + path_note=( + 'VS Code uses the key "servers", not "mcpServers", and a local-command entry needs ' + '"type": "stdio". The Copilot coding agent (repo/org level) and the standalone ' + "Copilot CLI use their own separate config surfaces." + ), + rules_file=".github/copilot-instructions.md", + rules_note=( + "Copilot coding agent also reads AGENTS.md natively (since August 2025); if both " + "files exist, AGENTS.md is treated as primary." + ), + ), + "zed": Harness( + key="zed", + name="Zed", + mcp=True, + config_format="json", + config_key="context_servers", + entry_shape="zed", + default_write_path=".zed/settings.json", + path_note=( + "Project scope. Global alternative: ~/.config/zed/settings.json. Zed's " + 'context_servers schema nests the launch command as {"command": {"path": ..., ' + '"args": [...]}}; if Zed documents a different shape by the time you read this, ' + "trust the docs over this snippet." + ), + rules_file=".rules", + rules_note=( + "Zed's priority order is .rules -> .cursorrules -> .windsurfrules -> AGENTS.md " + "(first match wins); a global ~/.config/zed/AGENTS.md is always appended too." + ), + ), + "codex": Harness( + key="codex", + name="OpenAI Codex CLI", + mcp=True, + config_format="toml", + config_key="mcp_servers", + default_write_path="~/.codex/config.toml", + path_note="Global. `codex mcp add cloudwright -- cloudwright mcp` does the same thing from the command line.", + rules_file="AGENTS.md", + rules_note="Codex is the tool that popularized AGENTS.md; it is native and canonical here.", + ), + "junie": Harness( + key="junie", + name="JetBrains Junie", + mcp=True, + config_format="json", + config_key="mcpServers", + default_write_path=".junie/mcp/mcp.json", + path_note="Project scope. Junie also ships an in-product MCP Installation Assistant that walks through a server registry.", + rules_file="AGENTS.md", + rules_note="Junie CLI reads AGENTS.md as its primary source, falling back to the legacy .junie/guidelines.md.", + ), + "aider": Harness( + key="aider", + name="Aider", + mcp=False, + rules_file="AGENTS.md", + rules_note="Aider reads AGENTS.md / AGENTS.override.md and has no native MCP client.", + notes=( + "Unofficial third-party MCP bridges (mcpm-aider, aider-mcp-server) exist but are " + "not a supported integration path here.", + ), + ), + "kiro": Harness( + key="kiro", + name="Kiro", + mcp=True, + config_format="json", + config_key="mcpServers", + default_write_path=".kiro/settings/mcp.json", + path_note="Project scope. User scope alternative: ~/.kiro/settings/mcp.json.", + rules_file="AGENTS.md", + rules_note=( + "Kiro's primary convention is its own steering system (.kiro/steering/*.md: " + "product.md, tech.md, structure.md), distinct from AGENTS.md; list both." + ), + notes=("Kiro is AWS's successor to Amazon Q Developer, which AWS is sunsetting.",), + ), + "antigravity": Harness( + key="antigravity", + name="Antigravity", + mcp=True, + config_format="json", + config_key="mcpServers", + default_write_path="~/.gemini/config/mcp_config.json", + path_note="Global, shared across the Antigravity CLI and IDE.", + rules_file="AGENTS.md", + rules_note=( + "Gemini CLI's default rules file was GEMINI.md; confirm whether Antigravity keeps " + "that convention before relying on it." + ), + notes=("Antigravity is Google's successor to Gemini CLI for individual developers.",), + ), +} + +_SUCCESSORS: dict[str, tuple[str, str]] = { + "roo-code": ( + "Roo Code", + "discontinued (sunset announced 2026-04-20, repo archived 2026-05-15); no supported successor", + ), + "continue-dev": ( + "Continue.dev", + "acquired by Cursor in June 2026, repo now read-only; wire cursor instead " + "(cloudwright integrate --harness cursor)", + ), + "amazon-q": ( + "Amazon Q Developer", + "being sunset by AWS; use its successor, kiro (cloudwright integrate --harness kiro)", + ), + "gemini-cli": ( + "Google Gemini CLI", + "individual/free access ended 2026-06-18; use its successor, antigravity " + "(cloudwright integrate --harness antigravity)", + ), +} + +_AGENT_FILES = { + "agents": "AGENTS.md", + "claude": "CLAUDE.md", + "gemini": "GEMINI.md", +} + +_AGENT_FILE_NOTES = { + "agents": ( + "Read natively by Cursor, Windsurf, Copilot, Codex, Junie, Aider, and Kiro; Zed falls " + "back to it. Claude Code does NOT read this file: use --agent-file claude for that harness." + ), + "claude": "Claude Code's native rules file. Claude Code does not read AGENTS.md.", + "gemini": ( + "Gemini CLI's default context file, loaded hierarchically from ~/.gemini/GEMINI.md down " + "through the project tree. AGENTS.md support exists but is not the default." + ), +} + + +def integrate( + ctx: typer.Context, + list_harnesses: Annotated[ + bool, typer.Option("--list", "-l", help="List supported harnesses and what each needs") + ] = False, + harness: Annotated[ + str | None, typer.Option("--harness", "-H", help="Print the exact MCP wiring for this harness") + ] = None, + rules: Annotated[ + bool, typer.Option("--rules", help="Emit a harness-agnostic rules block that gates infra through cloudwright") + ] = False, + agent_file: Annotated[ + str, typer.Option("--agent-file", help="Rules file target for --rules: agents, claude, or gemini") + ] = "agents", + write: Annotated[ + bool, typer.Option("--write", help="Write the config or rules block to its file (creates parent dirs)") + ] = False, + output: Annotated[str | None, typer.Option("--output", "-o", help="Override the default write path")] = None, + force: Annotated[ + bool, typer.Option("--force", help="Overwrite an existing cloudwright entry without confirmation") + ] = False, +) -> None: + """Print (and optionally write) the wiring that connects an AI coding harness to cloudwright. + + Three modes, pick one: + + \b + --list list every supported harness and what it needs + --harness exact MCP config snippet + rules-file note for one harness + --rules harness-agnostic instructions telling an agent to gate infra + changes through `cloudwright design/review/cost/compliance` + + `--write` writes the result to disk instead of only printing it (parent directories are + created; an existing conflicting entry is left untouched unless --force is passed). + """ + try: + if list_harnesses: + _cmd_list(ctx) + return + if harness: + _cmd_harness(ctx, harness, write=write, output=output, force=force) + return + if rules: + _cmd_rules(ctx, agent_file, write=write, output=output, force=force) + return + + raise ValueError("Specify one of --list, --harness , or --rules. Run --list to see supported harnesses.") + + except typer.Exit: + raise + except Exception as e: + handle_error(ctx, e) + + +def _harness_summary(h: Harness) -> dict: + return { + "key": h.key, + "name": h.name, + "mcp_client": h.mcp, + "config_file": h.default_write_path, + "config_key": h.config_key, + "rules_file": h.rules_file, + } + + +def _cmd_list(ctx: typer.Context) -> None: + rows = [_harness_summary(h) for h in _HARNESSES.values()] + + if is_json_mode(ctx): + emit_success( + ctx, + { + "harnesses": rows, + "not_mcp_clients": ["aider"], + "discontinued": {k: {"name": n, "note": note} for k, (n, note) in _SUCCESSORS.items()}, + }, + ) + return + + table = Table(title="Supported harnesses") + table.add_column("Harness") + table.add_column("Integration") + table.add_column("Config file / key") + table.add_column("Rules file") + for h in _HARNESSES.values(): + integration = "MCP config" if h.mcp else "CLI pipe" + config_col = ( + f"{h.default_write_path or '(see notes)'} [{h.config_key}]" if h.mcp else "cloudwright --json" + ) + table.add_row(h.name, integration, config_col, h.rules_file) + console.print(table) + console.print("\nNot an MCP client: Aider (uses the CLI pipe path).", style="dim") + console.print( + "Discontinued or superseded, not generated here: Roo Code, Continue.dev, " + "Amazon Q Developer (-> kiro), Google Gemini CLI (-> antigravity).", + style="dim", + ) + console.print( + "\nRun `cloudwright integrate --harness ` for exact wiring, or " + "`cloudwright integrate --rules` for the harness-agnostic gate instructions." + ) + + +def _resolve_harness(name: str) -> Harness: + key = name.strip().lower().replace("_", "-").replace(" ", "-") + if key in _HARNESSES: + return _HARNESSES[key] + if key in _SUCCESSORS: + display, note = _SUCCESSORS[key] + raise ValueError(f"{display} is {note}.") + valid = ", ".join(_HARNESSES) + raise ValueError(f"Unknown harness '{name}'. Supported: {valid}.") + + +def _entry(h: Harness) -> dict: + if h.entry_shape == "zed": + return {"command": {"path": "cloudwright", "args": ["mcp"]}} + entry: dict[str, object] = {} + if h.entry_extra: + entry.update(h.entry_extra) + entry["command"] = "cloudwright" + entry["args"] = ["mcp"] + return entry + + +def _document(h: Harness) -> dict: + return {h.config_key: {"cloudwright": _entry(h)}} + + +def _toml_table(table: str, values: dict) -> str: + lines = [f"[{table}]"] + for k, v in values.items(): + if isinstance(v, list): + items = ", ".join(json.dumps(i) for i in v) + lines.append(f"{k} = [{items}]") + else: + lines.append(f"{k} = {json.dumps(v)}") + return "\n".join(lines) + + +def _toml_block(h: Harness) -> str: + return _toml_table(f"{h.config_key}.cloudwright", _entry(h)) + + +def _cmd_harness(ctx: typer.Context, name: str, *, write: bool, output: str | None, force: bool) -> None: + h = _resolve_harness(name) + + if not h.mcp: + if write: + raise ValueError( + f"{h.name} has no MCP config to write (it is not an MCP client). " + "Use `cloudwright integrate --rules --write` to install the gate instructions " + f"into {h.rules_file} instead." + ) + payload = _aider_payload(h) + if is_json_mode(ctx): + emit_success(ctx, payload) + return + _print_aider(h, payload) + return + + snippet_text = _toml_block(h) if h.config_format == "toml" else json.dumps(_document(h), indent=2) + + payload: dict = { + "harness": h.key, + "name": h.name, + "mcp_client": True, + "config_format": h.config_format, + "config_file": h.default_write_path, + "path_note": h.path_note, + "config_key": h.config_key, + "config_snippet": _document(h) if h.config_format == "json" else snippet_text, + "rules_file": h.rules_file, + "rules_note": h.rules_note, + "notes": list(h.notes), + } + + write_result = None + if write: + write_result = _write_harness_config(h, output=output, force=force) + payload["write"] = write_result + + if is_json_mode(ctx): + emit_success(ctx, payload) + return + + _print_harness(h, snippet_text, write_result) + + +def _aider_payload(h: Harness) -> dict: + return { + "harness": h.key, + "name": h.name, + "mcp_client": False, + "cli_pipe": { + "instruction": "Aider has no native MCP client. Use the CLI pipe path instead.", + "example": '/run cloudwright design "" --json', + }, + "rules_file": h.rules_file, + "rules_note": h.rules_note, + "notes": list(h.notes), + } + + +def _print_aider(h: Harness, payload: dict) -> None: + console.print(f"\n[bold]{h.name}[/bold] (not an MCP client)\n") + console.print(payload["cli_pipe"]["instruction"]) + console.print(f" Example: [cyan]{payload['cli_pipe']['example']}[/cyan]") + console.print(f"\nRules file: [cyan]{h.rules_file}[/cyan]") + console.print(f" {h.rules_note}", style="dim") + if h.notes: + console.print("\nNotes:") + for n in h.notes: + console.print(f" - {n}") + + +def _print_harness(h: Harness, snippet_text: str, write_result: dict | None) -> None: + console.print(f"\n[bold]{h.name}[/bold] (MCP client)\n") + console.print(f"Config file: {h.default_write_path or '(see notes)'}") + if h.path_note: + console.print(f" {h.path_note}", style="dim") + console.print(f"Key: [cyan]{h.config_key}[/cyan]\n") + console.print(Syntax(snippet_text, "toml" if h.config_format == "toml" else "json", word_wrap=True)) + console.print(f"\nRules file: [cyan]{h.rules_file}[/cyan]") + if h.rules_note: + console.print(f" {h.rules_note}", style="dim") + if h.notes: + console.print("\nNotes:") + for n in h.notes: + console.print(f" - {n}") + if write_result: + console.print(f"\n[green]{write_result['action']}[/green] {write_result['path']}") + + +def _target_path(h: Harness, output: str | None) -> Path: + raw = output or h.default_write_path + if not raw: + raise ValueError( + f"{h.name} has no fixed config path; pass --output to write it explicitly. {h.path_note}" + ) + return Path(raw).expanduser() + + +def _write_harness_config(h: Harness, *, output: str | None, force: bool) -> dict: + path = _target_path(h, output) + path.parent.mkdir(parents=True, exist_ok=True) + if h.config_format == "toml": + return _write_toml(path, h, force=force) + return _write_json(path, h, force=force) + + +def _write_json(path: Path, h: Harness, *, force: bool) -> dict: + entry = _entry(h) + if path.exists(): + raw = path.read_text().strip() or "{}" + try: + existing = json.loads(raw) + except json.JSONDecodeError as e: + raise ValueError(f"{path} exists but is not valid JSON: {e}") from e + bucket = existing.setdefault(h.config_key, {}) + if "cloudwright" in bucket and bucket["cloudwright"] != entry and not force: + raise ValueError( + f"{path} already has a 'cloudwright' entry under {h.config_key!r} that differs. Pass --force to overwrite." + ) + action = "updated" if "cloudwright" in bucket else "added" + bucket["cloudwright"] = entry + path.write_text(json.dumps(existing, indent=2) + "\n") + return {"path": str(path), "action": action} + + path.write_text(json.dumps(_document(h), indent=2) + "\n") + return {"path": str(path), "action": "created"} + + +def _write_toml(path: Path, h: Harness, *, force: bool) -> dict: + block = _toml_block(h) + header = f"[{h.config_key}.cloudwright]" + if path.exists(): + text = path.read_text() + if header in text: + if not force: + raise ValueError(f"{path} already has {header}. Pass --force to overwrite.") + text = _replace_toml_table(text, header, block) + path.write_text(text) + return {"path": str(path), "action": "updated"} + sep = "" if text.endswith("\n\n") else ("\n\n" if text.endswith("\n") else "\n\n") + path.write_text(text + sep + block + "\n") + return {"path": str(path), "action": "appended"} + + path.write_text(block + "\n") + return {"path": str(path), "action": "created"} + + +def _replace_toml_table(text: str, header: str, new_block: str) -> str: + lines = text.splitlines(keepends=True) + start = None + end = len(lines) + for i, line in enumerate(lines): + if line.strip() == header: + start = i + continue + if start is not None and i > start and line.startswith("["): + end = i + break + if start is None: + return text + "\n\n" + new_block + "\n" + return "".join(lines[:start]) + new_block + "\n" + "".join(lines[end:]) + + +def _cmd_rules(ctx: typer.Context, agent_file: str, *, write: bool, output: str | None, force: bool) -> None: + key = agent_file.strip().lower() + if key not in _AGENT_FILES: + raise ValueError(f"Unknown --agent-file '{agent_file}'. Choose one of: {', '.join(_AGENT_FILES)}.") + filename = _AGENT_FILES[key] + block = f"{_RULES_START}\n{_RULES_BODY}{_RULES_END}\n" + + payload: dict = { + "agent_file": filename, + "block": block, + "note": _AGENT_FILE_NOTES[key], + } + + write_result = None + if write: + path = Path(output) if output else Path(filename) + write_result = _write_rules(path, block, force=force) + payload["write"] = write_result + + if is_json_mode(ctx): + emit_success(ctx, payload) + return + + console.print(Panel(block, title=f"Cloudwright gate for {filename}")) + console.print(_AGENT_FILE_NOTES[key], style="dim") + if write_result: + console.print(f"\n[green]{write_result['action']}[/green] {write_result['path']}") + + +def _write_rules(path: Path, block: str, *, force: bool) -> dict: + path.parent.mkdir(parents=True, exist_ok=True) + if path.exists(): + text = path.read_text() + if _RULES_START in text: + if not force: + raise ValueError(f"{path} already has a cloudwright gate block. Pass --force to replace it.") + start = text.index(_RULES_START) + end = text.index(_RULES_END) + len(_RULES_END) + text = text[:start] + block.rstrip("\n") + text[end:] + path.write_text(text) + return {"path": str(path), "action": "updated"} + sep = "\n" if text.endswith("\n") else "\n\n" + path.write_text(text + sep + block) + return {"path": str(path), "action": "appended"} + + header = f"# {path.name}\n\n" + path.write_text(header + block) + return {"path": str(path), "action": "created"} diff --git a/packages/cli/cloudwright_cli/main.py b/packages/cli/cloudwright_cli/main.py index ab04692..78aeea7 100644 --- a/packages/cli/cloudwright_cli/main.py +++ b/packages/cli/cloudwright_cli/main.py @@ -16,6 +16,7 @@ from cloudwright_cli.commands.import_cmd import import_infra from cloudwright_cli.commands.import_live_cmd import import_live from cloudwright_cli.commands.init_cmd import init +from cloudwright_cli.commands.integrate_cmd import integrate from cloudwright_cli.commands.lint_cmd import lint from cloudwright_cli.commands.mcp_cmd import mcp_serve from cloudwright_cli.commands.modify_cmd import modify @@ -89,4 +90,5 @@ def main( app.command(name="adr")(cloudwright_command()(adr)) app.command()(cloudwright_command()(schema)) app.command(name="mcp")(cloudwright_command()(mcp_serve)) +app.command(name="integrate")(cloudwright_command()(integrate)) app.add_typer(catalog_app, name="catalog") diff --git a/packages/cli/tests/test_integrate.py b/packages/cli/tests/test_integrate.py new file mode 100644 index 0000000..38dee5a --- /dev/null +++ b/packages/cli/tests/test_integrate.py @@ -0,0 +1,273 @@ +"""Tests for `cloudwright integrate` (harness wiring generator).""" + +from __future__ import annotations + +import json +from pathlib import Path + +from cloudwright_cli.main import app +from typer.testing import CliRunner + +runner = CliRunner() + + +class TestList: + def test_list_runs_and_names_harnesses(self): + result = runner.invoke(app, ["integrate", "--list"]) + assert result.exit_code == 0 + for name in ["Claude Code", "Cursor", "Cline", "Windsurf", "GitHub Copilot", "Zed", "Codex", "Junie", "Aider"]: + assert name in result.output + + def test_list_mentions_discontinued_harnesses_honestly(self): + result = runner.invoke(app, ["integrate", "--list"]) + assert result.exit_code == 0 + assert "Roo Code" in result.output + assert "Continue.dev" in result.output + assert "kiro" in result.output.lower() + assert "antigravity" in result.output.lower() + + def test_list_json(self): + result = runner.invoke(app, ["--json", "integrate", "--list"]) + assert result.exit_code == 0 + envelope = json.loads(result.output) + data = envelope["data"] + keys = {h["key"] for h in data["harnesses"]} + assert "claude-code" in keys + assert "aider" in keys + assert "roo-code" in data["discontinued"] + + +class TestHarnessDetail: + def test_harness_claude_code_config(self): + result = runner.invoke(app, ["integrate", "--harness", "claude-code"]) + assert result.exit_code == 0 + assert "cloudwright" in result.output + assert '"mcp"' in result.output + assert "mcpServers" in result.output + assert "CLAUDE.md" in result.output + + def test_harness_accepts_normalized_names(self): + result = runner.invoke(app, ["integrate", "--harness", "Claude Code"]) + assert result.exit_code == 0 + assert "mcpServers" in result.output + + def test_harness_zed_uses_context_servers(self): + result = runner.invoke(app, ["integrate", "--harness", "zed"]) + assert result.exit_code == 0 + assert "context_servers" in result.output + assert '"mcpServers"' not in result.output + + def test_harness_codex_emits_toml_table(self): + result = runner.invoke(app, ["integrate", "--harness", "codex"]) + assert result.exit_code == 0 + assert "[mcp_servers.cloudwright]" in result.output + assert 'command = "cloudwright"' in result.output + + def test_harness_copilot_uses_servers_key(self): + result = runner.invoke(app, ["integrate", "--harness", "copilot"]) + assert result.exit_code == 0 + assert '"servers"' in result.output + assert "stdio" in result.output + + envelope = json.loads(runner.invoke(app, ["--json", "integrate", "--harness", "copilot"]).output) + assert envelope["data"]["config_key"] == "servers" + assert "mcpServers" not in envelope["data"]["config_snippet"] + + def test_harness_aider_explains_cli_pipe_no_mcp_json(self): + result = runner.invoke(app, ["integrate", "--harness", "aider"]) + assert result.exit_code == 0 + assert "not an MCP client" in result.output + assert "cloudwright design" in result.output + assert '"mcpServers"' not in result.output + + def test_harness_kiro_and_antigravity_resolve(self): + for name in ("kiro", "antigravity"): + result = runner.invoke(app, ["integrate", "--harness", name]) + assert result.exit_code == 0 + assert "mcpServers" in result.output + + def test_harness_aider_write_errors_with_rules_hint(self): + result = runner.invoke(app, ["integrate", "--harness", "aider", "--write"]) + assert result.exit_code != 0 + assert "--rules --write" in (result.output + result.stderr) + + def test_harness_unknown_errors(self): + result = runner.invoke(app, ["integrate", "--harness", "not-a-real-tool"]) + assert result.exit_code != 0 + + def test_harness_discontinued_points_to_successor(self): + result = runner.invoke(app, ["integrate", "--harness", "gemini-cli"]) + assert result.exit_code != 0 + assert "antigravity" in (result.output + result.stderr).lower() + + result = runner.invoke(app, ["integrate", "--harness", "amazon-q"]) + assert result.exit_code != 0 + assert "kiro" in (result.output + result.stderr).lower() + + +class TestRules: + def test_rules_default_is_agents_md(self): + result = runner.invoke(app, ["integrate", "--rules"]) + assert result.exit_code == 0 + assert "AGENTS.md" in result.output + assert "cloudwright design" in result.output + assert "cloudwright review" in result.output + assert "cloudwright cost" in result.output + assert "cloudwright compliance" in result.output + + def test_rules_claude_agent_file(self): + result = runner.invoke(app, ["integrate", "--rules", "--agent-file", "claude"]) + assert result.exit_code == 0 + assert "CLAUDE.md" in result.output + assert "cloudwright design" in result.output + + def test_rules_gemini_agent_file(self): + result = runner.invoke(app, ["integrate", "--rules", "--agent-file", "gemini"]) + assert result.exit_code == 0 + assert "GEMINI.md" in result.output + + def test_rules_invalid_agent_file_errors(self): + result = runner.invoke(app, ["integrate", "--rules", "--agent-file", "nope"]) + assert result.exit_code != 0 + + def test_rules_no_em_dash_no_emoji(self): + result = runner.invoke(app, ["integrate", "--rules"]) + assert "—" not in result.output + + +class TestGlobalJson: + def test_json_flag_returns_parseable_envelope_for_harness(self): + result = runner.invoke(app, ["--json", "integrate", "--harness", "cursor"]) + assert result.exit_code == 0 + envelope = json.loads(result.output) + assert "data" in envelope + assert envelope["data"]["config_key"] == "mcpServers" + assert envelope["data"]["config_snippet"]["mcpServers"]["cloudwright"]["command"] == "cloudwright" + assert envelope["data"]["config_snippet"]["mcpServers"]["cloudwright"]["args"] == ["mcp"] + + def test_json_flag_aider_has_no_mcp_config_snippet(self): + result = runner.invoke(app, ["--json", "integrate", "--harness", "aider"]) + assert result.exit_code == 0 + envelope = json.loads(result.output) + assert envelope["data"]["mcp_client"] is False + assert "config_snippet" not in envelope["data"] + + def test_json_flag_codex_config_snippet_is_toml_text(self): + result = runner.invoke(app, ["--json", "integrate", "--harness", "codex"]) + assert result.exit_code == 0 + envelope = json.loads(result.output) + assert "[mcp_servers.cloudwright]" in envelope["data"]["config_snippet"] + + +class TestNoModeSelected: + def test_no_flags_errors_with_guidance(self): + result = runner.invoke(app, ["integrate"]) + assert result.exit_code != 0 + assert "--list" in (result.output + result.stderr) + + +class TestRegistration: + def test_integrate_registered_in_top_level_help(self): + result = runner.invoke(app, ["--help"]) + assert result.exit_code == 0 + assert "integrate" in result.output + + +class TestWrite: + def test_write_creates_new_json_config(self, tmp_path: Path, monkeypatch): + monkeypatch.chdir(tmp_path) + result = runner.invoke(app, ["integrate", "--harness", "cursor", "--write"]) + assert result.exit_code == 0 + cfg = tmp_path / ".cursor" / "mcp.json" + assert cfg.exists() + data = json.loads(cfg.read_text()) + assert data["mcpServers"]["cloudwright"]["command"] == "cloudwright" + assert data["mcpServers"]["cloudwright"]["args"] == ["mcp"] + + def test_write_merges_into_existing_json_preserving_other_servers(self, tmp_path: Path, monkeypatch): + monkeypatch.chdir(tmp_path) + cfg_dir = tmp_path / ".cursor" + cfg_dir.mkdir() + cfg = cfg_dir / "mcp.json" + cfg.write_text(json.dumps({"mcpServers": {"other-tool": {"command": "other", "args": []}}})) + + result = runner.invoke(app, ["integrate", "--harness", "cursor", "--write"]) + assert result.exit_code == 0 + data = json.loads(cfg.read_text()) + assert data["mcpServers"]["other-tool"]["command"] == "other" + assert data["mcpServers"]["cloudwright"]["command"] == "cloudwright" + + def test_write_refuses_to_overwrite_conflicting_entry_without_force(self, tmp_path: Path, monkeypatch): + monkeypatch.chdir(tmp_path) + cfg_dir = tmp_path / ".cursor" + cfg_dir.mkdir() + cfg = cfg_dir / "mcp.json" + cfg.write_text(json.dumps({"mcpServers": {"cloudwright": {"command": "something-else", "args": []}}})) + + result = runner.invoke(app, ["integrate", "--harness", "cursor", "--write"]) + assert result.exit_code != 0 + + result = runner.invoke(app, ["integrate", "--harness", "cursor", "--write", "--force"]) + assert result.exit_code == 0 + data = json.loads(cfg.read_text()) + assert data["mcpServers"]["cloudwright"]["command"] == "cloudwright" + + def test_write_output_override(self, tmp_path: Path): + out = tmp_path / "custom" / "mcp.json" + result = runner.invoke(app, ["integrate", "--harness", "cline", "--write", "--output", str(out)]) + assert result.exit_code == 0 + assert out.exists() + data = json.loads(out.read_text()) + assert data["mcpServers"]["cloudwright"]["command"] == "cloudwright" + + def test_write_cline_without_output_errors(self, tmp_path: Path, monkeypatch): + monkeypatch.chdir(tmp_path) + result = runner.invoke(app, ["integrate", "--harness", "cline", "--write"]) + assert result.exit_code != 0 + + def test_write_codex_toml_creates_table(self, tmp_path: Path): + out = tmp_path / "config.toml" + result = runner.invoke(app, ["integrate", "--harness", "codex", "--write", "--output", str(out)]) + assert result.exit_code == 0 + text = out.read_text() + assert "[mcp_servers.cloudwright]" in text + assert 'command = "cloudwright"' in text + + def test_write_codex_toml_appends_without_clobbering_other_tables(self, tmp_path: Path): + out = tmp_path / "config.toml" + out.write_text('[mcp_servers.other]\ncommand = "other"\nargs = []\n') + result = runner.invoke(app, ["integrate", "--harness", "codex", "--write", "--output", str(out)]) + assert result.exit_code == 0 + text = out.read_text() + assert "[mcp_servers.other]" in text + assert "[mcp_servers.cloudwright]" in text + + def test_write_rules_creates_agents_md(self, tmp_path: Path): + out = tmp_path / "AGENTS.md" + result = runner.invoke(app, ["integrate", "--rules", "--write", "--output", str(out)]) + assert result.exit_code == 0 + assert out.exists() + text = out.read_text() + assert "cloudwright design" in text + + def test_write_rules_is_idempotent_guard(self, tmp_path: Path): + out = tmp_path / "AGENTS.md" + result = runner.invoke(app, ["integrate", "--rules", "--write", "--output", str(out)]) + assert result.exit_code == 0 + + result = runner.invoke(app, ["integrate", "--rules", "--write", "--output", str(out)]) + assert result.exit_code != 0 + + result = runner.invoke(app, ["integrate", "--rules", "--write", "--output", str(out), "--force"]) + assert result.exit_code == 0 + text = out.read_text() + assert text.count("cloudwright:gate:start") == 1 + + def test_write_rules_appends_to_existing_file(self, tmp_path: Path): + out = tmp_path / "AGENTS.md" + out.write_text("# My project\n\nSome existing instructions.\n") + result = runner.invoke(app, ["integrate", "--rules", "--write", "--output", str(out)]) + assert result.exit_code == 0 + text = out.read_text() + assert "Some existing instructions." in text + assert "cloudwright design" in text From 22f02fc15dbf1506374aa159d7e08979bf6bfaeb Mon Sep 17 00:00:00 2001 From: Xavier Puspus <36430014+xmpuspus@users.noreply.github.com> Date: Wed, 8 Jul 2026 07:17:20 -0700 Subject: [PATCH 08/10] Cost credibility: as_of from catalog vintage, region-real pricing, per-alternative + ratio confidence, coverage doc --- docs/provider-coverage.md | 106 ++++++++ .../cli/cloudwright_cli/commands/compare.py | 14 + packages/cli/cloudwright_cli/commands/cost.py | 14 +- packages/core/cloudwright/catalog/store.py | 118 ++++++-- packages/core/cloudwright/cost.py | 48 +++- packages/core/cloudwright/spec.py | 20 +- packages/core/tests/test_cost_honesty.py | 257 ++++++++++++++++++ 7 files changed, 542 insertions(+), 35 deletions(-) create mode 100644 docs/provider-coverage.md create mode 100644 packages/core/tests/test_cost_honesty.py diff --git a/docs/provider-coverage.md b/docs/provider-coverage.md new file mode 100644 index 0000000..378cb43 --- /dev/null +++ b/docs/provider-coverage.md @@ -0,0 +1,106 @@ +# Provider coverage: what is real, what is a guess + +Cloudwright supports four providers (AWS, GCP, Azure, Databricks) with one shared +code path for cost, compliance, and export. That code path does not have equal +data behind it for every provider. This page states plainly what is backed by +real catalog pricing versus formula or fallback pricing, so a reader can judge +how much to trust a cost number before they act on it. + +All counts below were queried directly from the bundled catalog +(`packages/core/cloudwright/data/catalog.db`) and from the exporter/importer +source files in this repository. They are not estimates. + +## Catalog pricing data + +| Provider | Instance rows (compute) | Managed-service rows | Real per-region pricing | +|---|---|---|---| +| AWS | 1174 | 281 | Yes, 4 regions (us-east, us-west, eu-west, ap-southeast) | +| GCP | 117 | 17 | Yes, same 4 regions | +| Azure | 17 | 8 | Yes, same 4 regions | +| Databricks | 0 | 0 | No catalog rows at all | + +Notes: + +- The catalog seeds only AWS, GCP, and Azure from JSON price files. Databricks has + no `providers` row and no instance or managed-service rows. Every Databricks cost + number comes from a hardcoded formula, not a price list. +- "4 regions" means the catalog carries real, provider-specific pricing rows for + one baseline region plus three others (a US west equivalent, an EU west + equivalent, an Asia-Pacific southeast equivalent) per provider. That is 174 real + non-baseline pricing rows total across AWS, GCP, and Azure combined. Any region + outside those four falls back to a static multiplier against the baseline price, + which is an estimate, not a verified price. +- Managed services (RDS/Cloud SQL/Azure SQL, load balancers, CDNs, caches, and so + on) have no region column in the catalog schema at all. Their pricing is always + the baseline-region row, rescaled by the static regional multiplier for any + non-baseline region. Only compute instance pricing (EC2/Compute Engine/Virtual + Machines) can use a real per-region row. +- AWS's compute and managed-service row counts dwarf GCP's and Azure's. GCP and + Azure catalog coverage is real but thin: most non-compute Azure services and a + meaningful share of GCP services still fall through to formula pricing + (`packages/core/cloudwright/catalog/formula.py`) because no matching catalog row + exists for them. + +## Terraform exporter service coverage + +Counted as `if svc ==` / `elif svc ==` / `elif svc in (...)` dispatch branches in +each provider's exporter file: + +| Provider | File | Dispatch branches | +|---|---|---| +| AWS | `exporter/terraform/aws.py` | 24 | +| GCP | `exporter/terraform/gcp.py` | 10 | +| Azure | `exporter/terraform/azure.py` | 9 | +| Databricks | `exporter/terraform/databricks.py` | 12 | + +AWS has more than double the dispatch branches of GCP or Azure, meaning more +service types can be rendered as real Terraform resources rather than being +silently dropped or emitted as a generic placeholder. + +## Live import coverage + +Counted from `SUPPORTED_SERVICES` in each provider's live importer: + +| Provider | File | Services | +|---|---|---| +| AWS | `importer/live_aws.py` | 13 (ec2, vpc, rds, s3, lambda, ecs, eks, dynamodb, alb, cloudfront, sqs, api_gateway, cloudtrail) | +| GCP | `importer/live_gcp.py` | 3 (compute_engine, cloud_storage, cloud_sql) | +| Azure | `importer/live_azure.py` | 4 (virtual_machines, blob_storage, azure_sql, aks) | +| Databricks | none | 0, no live importer exists | + +`cloudwright import-live` can pull a real running AWS account into an ArchSpec +across 13 service types. For GCP and Azure it can only see a handful of core +services. For Databricks it cannot import anything at all. + +## Cost basis, plainly stated + +| Provider | Cost basis | +|---|---| +| AWS | Catalog-real for compute and the managed services with rows in `managed_services`. Falls to formula/fallback only for services outside catalog coverage. | +| GCP | Partially catalog-real (compute, cloud_storage, cloud_sql, and a handful of networking services). Most other managed services are formula/fallback. | +| Azure | Mostly formula/fallback. The catalog has only 17 instance rows and 8 managed-service rows, so most Azure services price through formulas, not real price data. | +| Databricks | 100% formula/fallback. No catalog rows exist for any Databricks service. | + +Multi-cloud cost comparisons (`cloudwright compare`, `cloudwright cost --compare`) +now show a Confidence column per provider so a GCP or Azure total is not presented +with the same authority as an AWS total backed by real catalog pricing. A "high" +aggregate confidence means every priced line item came from a catalog row (either +an exact regional row or the baseline row); it does not mean every line item is +region-accurate. Per-line-item confidence in `cloudwright cost` distinguishes +"high" (real per-region catalog data), "medium" (real catalog data at a different +region, rescaled by a static multiplier), and "low" (formula or hardcoded +fallback, not catalog data at all). + +## What this means for a cost estimate + +- If your spec is AWS-only, in one of the four catalog regions, using services + with catalog rows: the estimate is close to real published pricing. +- If your spec is AWS-only but in a region outside the four catalog regions, or + uses a managed service (which is never region-specific in this catalog): the + estimate uses a static regional multiplier and should be treated as directional, + not exact. +- If your spec is GCP or Azure: expect a meaningful share of line items to be + formula-priced, not catalog-priced. Check the per-line Confidence column before + trusting a total. +- If your spec is Databricks: every number is a formula estimate. Treat the total + as a rough order of magnitude only. diff --git a/packages/cli/cloudwright_cli/commands/compare.py b/packages/cli/cloudwright_cli/commands/compare.py index 4657ee4..0f14fb3 100644 --- a/packages/cli/cloudwright_cli/commands/compare.py +++ b/packages/cli/cloudwright_cli/commands/compare.py @@ -37,11 +37,15 @@ def compare( if is_json_mode(ctx): origin_total = spec.cost_estimate.monthly_total if spec.cost_estimate else 0.0 + origin_confidence = spec.cost_estimate.pricing_confidence if spec.cost_estimate else "-" + origin_confidence_detail = spec.cost_estimate.pricing_confidence_detail if spec.cost_estimate else "" data = { "baseline": spec.provider, "providers": { spec.provider: { "monthly_total": origin_total, + "pricing_confidence": origin_confidence, + "pricing_confidence_detail": origin_confidence_detail, "components": [c.model_dump() for c in spec.components], } }, @@ -49,6 +53,8 @@ def compare( for alt in alts: data["providers"][alt.provider] = { "monthly_total": alt.monthly_total, + "pricing_confidence": alt.pricing_confidence, + "pricing_confidence_detail": alt.pricing_confidence_detail, "key_differences": alt.key_differences, "components": [c.model_dump() for c in alt.spec.components] if alt.spec else [], } @@ -79,12 +85,15 @@ def compare( totals_table = Table(title="Monthly Cost Totals", show_header=True) totals_table.add_column("Provider") totals_table.add_column("Monthly Total", justify="right") + totals_table.add_column("Confidence", justify="center") totals_table.add_column("Key Differences", style="dim") origin_total = spec.cost_estimate.monthly_total if spec.cost_estimate else 0.0 + origin_confidence = spec.cost_estimate.pricing_confidence if spec.cost_estimate else "-" totals_table.add_row( spec.provider.upper(), f"${origin_total:,.2f}" if origin_total else "-", + origin_confidence, "(baseline)", ) for alt in alts: @@ -92,7 +101,12 @@ def compare( totals_table.add_row( alt.provider.upper(), f"${alt.monthly_total:,.2f}" if alt.monthly_total else "-", + alt.pricing_confidence, diffs, ) console.print(totals_table) + console.print( + "[dim]Non-AWS estimates typically rely on formula/fallback pricing rather than " + "real catalog data. Check the Confidence column before treating totals as comparable.[/dim]" + ) diff --git a/packages/cli/cloudwright_cli/commands/cost.py b/packages/cli/cloudwright_cli/commands/cost.py index e4432ef..f23041f 100644 --- a/packages/cli/cloudwright_cli/commands/cost.py +++ b/packages/cli/cloudwright_cli/commands/cost.py @@ -115,10 +115,11 @@ def _print_single_cost_table(spec: ArchSpec) -> None: table.add_column("Notes", style="dim") comp_map = {c.id: c for c in spec.components} + conf_styles = {"high": "green", "medium": "yellow"} for item in est.breakdown: comp = comp_map.get(item.component_id) svc_label = comp.service if comp else item.service - conf_style = "green" if item.confidence == "high" else "yellow" + conf_style = conf_styles.get(item.confidence, "red") table.add_row( item.component_id, svc_label, @@ -129,6 +130,9 @@ def _print_single_cost_table(spec: ArchSpec) -> None: console.print(table) + prices_as_of = est.prices_as_of or est.as_of + console.print(f"[dim]Prices as of {prices_as_of}. {est.pricing_confidence_detail}.[/dim]") + if est.pricing_confidence != "high": console.print( "[yellow]Pricing confidence: low[/yellow] — one or more services used formula/fallback " @@ -170,16 +174,24 @@ def _print_multi_cloud_table(spec: ArchSpec, providers: list[str]) -> None: # Totals row totals = [] + confidences = [] for p in all_providers: s = alternatives_map.get(p) if s and s.cost_estimate: totals.append(f"${s.cost_estimate.monthly_total:,.2f}") + confidences.append(s.cost_estimate.pricing_confidence) else: totals.append("-") + confidences.append("-") table.add_section() table.add_row("[bold]TOTAL[/bold]", *totals) + table.add_row("[dim]Confidence[/dim]", *[f"[dim]{c}[/dim]" for c in confidences]) console.print(table) + console.print( + "[dim]Non-AWS totals lean heavily on formula/fallback pricing, not catalog data. " + "See the Confidence row above.[/dim]" + ) def _print_carbon_table(spec: ArchSpec, carbon: dict) -> None: diff --git a/packages/core/cloudwright/catalog/store.py b/packages/core/cloudwright/catalog/store.py index e340c82..fed90e0 100644 --- a/packages/core/cloudwright/catalog/store.py +++ b/packages/core/cloudwright/catalog/store.py @@ -459,28 +459,102 @@ def find_instance(self, name: str) -> dict | None: return self._row_to_dict(row) if row else None def get_service_pricing( - self, service: str, provider: str, config: dict | None = None, pricing_tier: str = "on_demand" + self, + service: str, + provider: str, + config: dict | None = None, + pricing_tier: str = "on_demand", + region: str | None = None, ) -> float | None: """Get monthly pricing for a service. Returns monthly cost or None.""" - base = self._get_base_price(service, provider, config) + price, _matched = self.get_service_pricing_with_match( + service, provider, config, pricing_tier=pricing_tier, region=region + ) + return price + + def get_service_pricing_with_match( + self, + service: str, + provider: str, + config: dict | None = None, + pricing_tier: str = "on_demand", + region: str | None = None, + ) -> tuple[float | None, bool]: + """Like get_service_pricing, but also reports whether the price came from a + real per-region catalog row (region_matched=True) versus the us-east-1 + baseline that the caller must rescale with a static regional multiplier + (region_matched=False) if it wants a non-baseline-region number. + """ + base, matched = self._get_base_price(service, provider, config, region=region) if base is None: - return None + return None, False multiplier = _PRICING_MULTIPLIERS.get(pricing_tier, 1.0) - return round(base * multiplier, 2) + return round(base * multiplier, 2), matched + + def get_instance_price_for_region(self, instance_name: str, provider: str, region: str) -> float | None: + """Return the real hourly price for instance_name in the given provider region + code, or None if the catalog has no pricing row for that exact region. + + Callers should treat a None result as "no real regional data" and fall back + to the us-east-1 baseline rescaled by a static multiplier — and should mark + that fallback as a lower-confidence estimate, not catalog-verified pricing. + """ + with self._connect() as conn: + row = conn.execute( + """SELECT p.price_per_hour + FROM instance_types i + JOIN pricing p ON p.instance_type_id = i.id AND p.os = 'linux' AND p.price_type = 'on_demand' + JOIN regions r ON r.id = p.region_id + WHERE (i.name = ? OR i.id = ?) AND i.provider_id = ? AND r.code = ? + LIMIT 1""", + (instance_name, instance_name, provider, region), + ).fetchone() + return row["price_per_hour"] if row and row["price_per_hour"] else None - def _get_base_price(self, service: str, provider: str, config: dict | None = None) -> float | None: - """Compute on-demand monthly price for a service. Returns None if unknown.""" + def get_catalog_refresh_date(self) -> str | None: + """Return the most recent catalog_metadata refresh timestamp (YYYY-MM-DD), + or None when the catalog carries no refresh history at all. + + Used to stamp cost estimates with the pricing data's real vintage instead + of the date the estimate happened to run — the bundled catalog is refreshed + on a schedule, not continuously, so "today" routinely overstates freshness. + """ + with self._connect() as conn: + row = conn.execute("SELECT MAX(updated_at) as latest FROM catalog_metadata").fetchone() + if not row or not row["latest"]: + return None + latest = row["latest"] + # updated_at is an ISO 8601 timestamp; surface just the date portion to + # match the plain YYYY-MM-DD format `as_of` has always used. + return latest[:10] if len(latest) >= 10 else latest + + def _get_base_price( + self, service: str, provider: str, config: dict | None = None, region: str | None = None + ) -> tuple[float | None, bool]: + """Compute on-demand monthly price for a service. + + Returns (price, region_matched). region_matched is True only when the + price came from a real per-region catalog row — currently possible only + for instance-priced compute services (ec2/compute_engine/virtual_machines). + Managed services have no region column in the catalog schema at all, so + region_matched is always False for those; the caller applies a static + regional multiplier and downgrades confidence accordingly. + """ config = config or {} # For compute instances, look up by instance_type if service in ("ec2", "compute_engine", "virtual_machines"): instance_type = config.get("instance_type", config.get("machine_type", config.get("vm_size"))) if instance_type: + count = config.get("count", 1) + if region: + regional_hourly = self.get_instance_price_for_region(instance_type, provider, region) + if regional_hourly: + return round(regional_hourly * 730 * count, 2), True inst = self.find_instance(instance_type) if inst and inst.get("price_per_hour"): - count = config.get("count", 1) - return round(inst["price_per_hour"] * 730 * count, 2) - return None + return round(inst["price_per_hour"] * 730 * count, 2), False + return None, False # For managed services, look up in managed_services table with self._connect() as conn: @@ -505,9 +579,9 @@ def _get_base_price(self, service: str, provider: str, config: dict | None = Non # Multi-AZ doubles compute cost if config.get("multi_az", False): monthly = round(monthly + hourly * 730, 2) - return monthly + return monthly, False # Fallback default pricing - return _default_managed_price(service, config) + return _default_managed_price(service, config), False # Storage if service in ("s3", "cloud_storage", "blob_storage"): @@ -524,7 +598,7 @@ def _get_base_price(self, service: str, provider: str, config: dict | None = Non per_gb = 0.023 else: per_gb = 0.023 - return round(storage_gb * per_gb, 2) + return round(storage_gb * per_gb, 2), False # Load balancers if service in ("alb", "nlb", "app_gateway", "azure_lb", "cloud_load_balancing"): @@ -537,8 +611,8 @@ def _get_base_price(self, service: str, provider: str, config: dict | None = Non round(row["price_per_month"], 2) if row["price_per_month"] > 0 else _default_managed_price(service, config) - ) - return _default_managed_price(service, config) + ), False + return _default_managed_price(service, config), False # CDN if service in ("cloudfront", "cloud_cdn", "azure_cdn"): @@ -562,7 +636,7 @@ def _get_base_price(self, service: str, provider: str, config: dict | None = Non rate = 0.085 else: rate = 0.085 - return round(estimated_gb * rate, 2) + return round(estimated_gb * rate, 2), False # Cache if service in ("elasticache", "memorystore", "azure_cache"): @@ -573,8 +647,8 @@ def _get_base_price(self, service: str, provider: str, config: dict | None = Non (provider, node_type), ).fetchone() if row: - return round(row["price_per_hour"] * 730, 2) - return _default_managed_price(service, config) + return round(row["price_per_hour"] * 730, 2), False + return _default_managed_price(service, config), False # Serverless (Lambda, Cloud Functions, Azure Functions) if service in ("lambda", "cloud_functions", "azure_functions"): @@ -586,24 +660,24 @@ def _get_base_price(self, service: str, provider: str, config: dict | None = Non # Compute cost: GB-seconds gb_seconds = (monthly_requests * avg_duration_ms / 1000) * (memory_mb / 1024) compute_cost = gb_seconds * 0.0000166667 - return round(request_cost + compute_cost, 2) + return round(request_cost + compute_cost, 2), False # Queues if service in ("sqs", "pub_sub", "service_bus"): monthly_requests = config.get("monthly_requests", 10_000_000) per_million = 0.40 if service == "sqs" else 0.60 - return round((monthly_requests / 1_000_000) * per_million, 2) + return round((monthly_requests / 1_000_000) * per_million, 2), False # DynamoDB if service in ("dynamodb", "firestore", "cosmos_db"): if config.get("billing_mode") == "provisioned": rcu = config.get("read_capacity", 5) wcu = config.get("write_capacity", 5) - return round(wcu * 0.00065 * 730 + rcu * 0.00013 * 730, 2) - return 25.0 # on-demand base + return round(wcu * 0.00065 * 730 + rcu * 0.00013 * 730, 2), False + return 25.0, False # on-demand base # Return None so cost.py Tier 2 (registry formulas) can fire - return None + return None, False def sync_from_registry( self, registry: ServiceRegistry | None = None, *, _conn: sqlite3.Connection | None = None diff --git a/packages/core/cloudwright/cost.py b/packages/core/cloudwright/cost.py index 1b9bb6d..0853252 100644 --- a/packages/core/cloudwright/cost.py +++ b/packages/core/cloudwright/cost.py @@ -357,17 +357,33 @@ def estimate( data_transfer = self._estimate_data_transfer(spec, workload_profile=workload_profile) total = round(component_total + data_transfer, 2) - # Aggregate confidence: "high" only when every billed line item used catalog data + # Aggregate confidence: "high" only when every billed line item is catalog-backed + # (not formula/fallback). A "medium" per-line confidence — a real catalog price + # rescaled by a static regional multiplier — is still catalog data, not a formula + # guess, so it does not flip the aggregate to "low". billed = [c for c in breakdown if c.monthly > 0] - pricing_confidence = "high" if billed and all(c.confidence == "high" for c in billed) else "low" + pricing_confidence = "high" if billed and all(not c.estimated for c in billed) else "low" + + catalog_backed = sum(1 for c in breakdown if not c.estimated) + pricing_confidence_detail = f"{catalog_backed}/{len(breakdown)} line items catalog-backed" + + # The bundled catalog is refreshed on a schedule, not continuously — stamp + # as_of with the catalog's real refresh date so the estimate doesn't claim + # same-day freshness the price data doesn't have. estimated_on still records + # when this particular estimate ran. + today = date.today().isoformat() + refresh_date = self.catalog.get_catalog_refresh_date() return CostEstimate( monthly_total=total, breakdown=breakdown, data_transfer_monthly=data_transfer, currency="USD", - as_of=date.today().isoformat(), + as_of=refresh_date or today, + prices_as_of=refresh_date, + estimated_on=today, pricing_confidence=pricing_confidence, + pricing_confidence_detail=pricing_confidence_detail, region=region, region_multiplier=rmult, ) @@ -430,6 +446,8 @@ def compare_providers( provider=target_provider, monthly_total=alt_estimate.monthly_total, spec=alt_spec, + pricing_confidence=alt_estimate.pricing_confidence, + pricing_confidence_detail=alt_estimate.pricing_confidence_detail, key_differences=differences[:5], ) ) @@ -506,15 +524,25 @@ def _price_component_with_meta( confidence = "low" is_estimated = False - # Tier 1: catalog DB (has instance-level pricing and pricing_tier support) - base = self.catalog.get_service_pricing(comp.service, provider, config, pricing_tier=pricing_tier) + # Tier 1: catalog DB (has instance-level pricing and pricing_tier support). + # region_matched is True only when the catalog has a real pricing row for + # this exact region (currently only possible for instance-priced compute + # services) — otherwise we fall back to the us-east-1 baseline rescaled by + # a static multiplier, which is an estimate, not verified catalog data. + base, region_matched = self.catalog.get_service_pricing_with_match( + comp.service, provider, config, pricing_tier=pricing_tier, region=region + ) if base is not None: from_catalog = True - confidence = "high" - # The catalog stores us-east-1 baseline prices and does not vary by - # region, so the regional multiplier is applied here too (not only on - # the formula/fallback tiers below). - base *= region_mult + if region_matched: + confidence = "high" + elif region_mult != 1.0: + confidence = "medium" + base *= region_mult + else: + # Baseline region (or an unlisted region defaulting to 1.0x) — the + # catalog price applies as-is, no multiplier guess involved. + confidence = "high" if base is None: # Tier 2: registry formula dispatch diff --git a/packages/core/cloudwright/spec.py b/packages/core/cloudwright/spec.py index d724352..be14421 100644 --- a/packages/core/cloudwright/spec.py +++ b/packages/core/cloudwright/spec.py @@ -93,7 +93,11 @@ class ComponentCost(BaseModel): monthly: float hourly: float | None = None notes: str = "" - confidence: str = "high" # "high" = real catalog row; "low" = formula/fallback + # "high" = real catalog row (or a per-region row) backs this price; + # "medium" = catalog data exists but was rescaled by a static regional + # multiplier because the catalog has no real pricing row for this exact + # region; "low" = formula/fallback, not catalog data at all. + confidence: str = "high" estimated: bool = False # True when price comes from a fallback, not catalog data @@ -102,8 +106,15 @@ class CostEstimate(BaseModel): breakdown: list[ComponentCost] = Field(default_factory=list) data_transfer_monthly: float = 0.0 currency: str = "USD" + # Historically stamped with date.today(), which claimed same-day freshness + # for pricing data that may be months stale. Now set from the catalog's own + # refresh timestamp when available (see CostEngine.estimate), falling back + # to today only when the catalog carries no refresh history at all. as_of: str = Field(default_factory=lambda: date.today().isoformat()) - pricing_confidence: str = "high" # "high" only when every line item is high + prices_as_of: str | None = None # catalog pricing-data vintage; None if unknown + estimated_on: str = Field(default_factory=lambda: date.today().isoformat()) # when this estimate ran + pricing_confidence: str = "high" # "high" only when every billed line item is catalog-backed + pricing_confidence_detail: str = "" # e.g. "17/20 line items catalog-backed" region: str = "us-east-1" region_multiplier: float = 1.0 # multiplier applied relative to us-east-1 baseline @@ -113,6 +124,11 @@ class Alternative(BaseModel): monthly_total: float spec: ArchSpec | None = None key_differences: list[str] = Field(default_factory=list) + # Propagated from the alternative's own CostEstimate so cross-provider + # comparisons don't present formula-priced non-AWS estimates as if they + # carried the same authority as catalog-backed AWS numbers. + pricing_confidence: str = "high" + pricing_confidence_detail: str = "" class ComponentChange(BaseModel): diff --git a/packages/core/tests/test_cost_honesty.py b/packages/core/tests/test_cost_honesty.py new file mode 100644 index 0000000..646ebd9 --- /dev/null +++ b/packages/core/tests/test_cost_honesty.py @@ -0,0 +1,257 @@ +"""Cost-credibility tests (July 2026 audit). + +Covers four defects verified in the audit: +1. CostEstimate.as_of stamped today's date on stale (Feb 2026) catalog pricing. +2. Cross-provider Alternative dropped the confidence signal entirely. +3. Region-aware pricing ignored real per-region catalog rows in favor of a + static multiplier, even where the catalog has genuine regional data. +4. Aggregate pricing_confidence was binary (high/low) with no ratio detail. +""" + +from __future__ import annotations + +from datetime import date + +import pytest +from cloudwright.catalog import Catalog +from cloudwright.cost import CostEngine +from cloudwright.spec import ArchSpec, Component + + +def _ec2_spec(region: str = "us-east-1", instance_type: str = "t3.medium") -> ArchSpec: + return ArchSpec( + name="EC2 Only", + provider="aws", + region=region, + components=[ + Component( + id="web", + service="ec2", + provider="aws", + label="Web", + tier=2, + config={"instance_type": instance_type}, + ), + ], + connections=[], + ) + + +def _rds_spec(region: str = "us-east-1") -> ArchSpec: + return ArchSpec( + name="RDS Only", + provider="aws", + region=region, + components=[ + Component( + id="db", + service="rds", + provider="aws", + label="DB", + tier=3, + config={"instance_class": "db.t3.medium", "storage_gb": 50}, + ), + ], + connections=[], + ) + + +def _mixed_spec() -> ArchSpec: + """One catalog-backed component, one formula/fallback component.""" + return ArchSpec( + name="Mixed", + provider="aws", + region="us-east-1", + components=[ + Component( + id="web", + service="ec2", + provider="aws", + label="Web", + tier=2, + config={"instance_type": "t3.medium"}, + ), + Component( + id="mystery", + service="definitely_unknown_service_xyz", + provider="aws", + label="?", + tier=2, + config={}, + ), + ], + connections=[], + ) + + +class TestPricesAsOfReflectsCatalogRefresh: + def test_as_of_matches_catalog_refresh_not_today(self): + engine = CostEngine() + refresh_date = engine.catalog.get_catalog_refresh_date() + assert refresh_date, "bundled catalog.db must carry catalog_metadata rows" + + est = engine.estimate(_ec2_spec()) + assert est.as_of == refresh_date + # The bundled catalog was refreshed in Feb 2026; today (test run date) is later. + assert est.as_of != date.today().isoformat() + + def test_prices_as_of_field_present_and_matches_as_of(self): + engine = CostEngine() + est = engine.estimate(_ec2_spec()) + assert est.prices_as_of == est.as_of + + def test_estimated_on_is_todays_date(self): + engine = CostEngine() + est = engine.estimate(_ec2_spec()) + assert est.estimated_on == date.today().isoformat() + + def test_catalog_refresh_date_none_when_metadata_empty(self, tmp_path): + """A fresh catalog with no refresh history reports no fabricated freshness.""" + empty_db = tmp_path / "empty_catalog.db" + catalog = Catalog(db_path=empty_db) + assert catalog.get_catalog_refresh_date() is None + + def test_as_of_falls_back_to_today_when_catalog_has_no_metadata(self, tmp_path): + """Without any catalog_metadata, as_of should still be populated (fallback to today) + rather than left blank — it just can't claim a real refresh date it doesn't have. + """ + empty_db = tmp_path / "empty_catalog2.db" + catalog = Catalog(db_path=empty_db) + engine = CostEngine(catalog=catalog) + est = engine.estimate(_ec2_spec()) + assert est.as_of == date.today().isoformat() + assert est.prices_as_of is None + + +class TestAlternativeCarriesConfidence: + def test_compare_providers_alternative_has_confidence(self): + engine = CostEngine() + spec = _ec2_spec() + alts = engine.compare_providers(spec, ["gcp"]) + assert len(alts) == 1 + alt = alts[0] + assert alt.pricing_confidence in ("high", "medium", "low") + assert "/" in alt.pricing_confidence_detail + + def test_alternative_model_has_confidence_fields_with_defaults(self): + from cloudwright.spec import Alternative + + alt = Alternative(provider="gcp", monthly_total=100.0) + assert hasattr(alt, "pricing_confidence") + assert hasattr(alt, "pricing_confidence_detail") + + def test_alternative_confidence_matches_its_own_estimate(self): + """The Alternative's confidence should reflect the alt spec's own cost + estimate, not just copy the origin spec's confidence. + """ + engine = CostEngine() + spec = _mixed_spec() + alts = engine.compare_providers(spec, ["gcp"]) + alt = alts[0] + alt_estimate = engine.estimate(alt.spec) + assert alt.pricing_confidence == alt_estimate.pricing_confidence + assert alt.pricing_confidence_detail == alt_estimate.pricing_confidence_detail + + +class TestRegionAwarePricing: + def test_real_regional_row_used_when_available(self): + """t3.medium has a genuine aws:eu-west-1 pricing row in the catalog — + the estimate should use it directly rather than the static multiplier. + """ + catalog = Catalog() + real_hourly = catalog.get_instance_price_for_region("t3.medium", "aws", "eu-west-1") + assert real_hourly is not None, "expected a real eu-west-1 catalog row for t3.medium" + + engine = CostEngine(catalog=catalog) + est = engine.estimate(_ec2_spec(region="eu-west-1")) + item = est.breakdown[0] + + expected_monthly = round(real_hourly * 730, 2) + assert item.monthly == pytest.approx(expected_monthly) + assert item.confidence == "high" + + # Sanity: the real regional price must differ from a naive baseline*multiplier + # guess, proving the test actually exercises the regional-row path. + baseline_hourly = catalog.get_instance_price_for_region("t3.medium", "aws", "us-east-1") + naive_guess = round(baseline_hourly * 730 * 1.08, 2) + assert expected_monthly != naive_guess + + def test_multiplier_downgrades_confidence_when_no_regional_row(self): + """RDS pricing has no per-region rows in the catalog schema at all, so any + non-baseline region must fall back to the static multiplier — and that + fallback must not be reported as high confidence. + """ + engine = CostEngine() + est = engine.estimate(_rds_spec(region="eu-west-1")) + item = est.breakdown[0] + assert item.confidence == "medium" + assert item.estimated is False # still catalog-derived, just region-rescaled + # A medium-confidence, region-rescaled line item is not a formula/fallback + # guess, so it must not flip the legacy binary aggregate to "low". + assert est.pricing_confidence == "high" + + def test_baseline_region_stays_high_confidence(self): + engine = CostEngine() + est = engine.estimate(_rds_spec(region="us-east-1")) + item = est.breakdown[0] + assert item.confidence == "high" + + def test_compute_instance_without_regional_row_falls_back_to_multiplier(self): + """A region with no seeded pricing rows at all (e.g. sa-east-1) must fall + back to the baseline * multiplier estimate and be marked medium confidence. + """ + catalog = Catalog() + assert catalog.get_instance_price_for_region("t3.medium", "aws", "sa-east-1") is None + + engine = CostEngine(catalog=catalog) + est = engine.estimate(_ec2_spec(region="sa-east-1")) + item = est.breakdown[0] + assert item.confidence == "medium" + + +class TestPricingConfidenceDetailRatio: + def test_ratio_detail_present_for_mixed_spec(self): + engine = CostEngine() + est = engine.estimate(_mixed_spec()) + assert est.pricing_confidence_detail == "1/2 line items catalog-backed" + + def test_ratio_detail_all_catalog_backed(self): + engine = CostEngine() + est = engine.estimate(_ec2_spec()) + assert est.pricing_confidence_detail == "1/1 line items catalog-backed" + + def test_ratio_detail_none_catalog_backed(self): + engine = CostEngine() + spec = ArchSpec( + name="All Unknown", + provider="aws", + region="us-east-1", + components=[ + Component( + id="mystery", + service="definitely_unknown_service_xyz", + provider="aws", + label="?", + tier=2, + config={}, + ), + ], + connections=[], + ) + est = engine.estimate(spec) + assert est.pricing_confidence_detail == "0/1 line items catalog-backed" + + def test_legacy_pricing_confidence_field_still_binary(self): + """Back-compat: the old aggregate field stays high/low even though + per-line confidence now has a medium tier. + """ + engine = CostEngine() + est = engine.estimate(_mixed_spec()) + assert est.pricing_confidence in ("high", "low") + assert est.pricing_confidence == "low" + + est_clean = engine.estimate(_ec2_spec(region="eu-west-1")) + # eu-west-1 with a real catalog row is still fully catalog-backed — + # a medium-confidence *region* estimate is not a formula/fallback estimate, + # so the legacy aggregate should remain "high". + assert est_clean.pricing_confidence == "high" From c091392b083b7f6787e861d6d3f0fe93451fde14 Mon Sep 17 00:00:00 2001 From: Xavier Puspus <36430014+xmpuspus@users.noreply.github.com> Date: Wed, 8 Jul 2026 07:24:00 -0700 Subject: [PATCH 09/10] v1.7.0: bump versions, CHANGELOG, README (harness reach + audit fixes) --- CHANGELOG.md | 26 +++++++++++++++++++++++ README.md | 27 +++++++++++++++++++----- packages/cli/cloudwright_cli/__init__.py | 2 +- packages/core/cloudwright/__init__.py | 2 +- packages/core/pyproject.toml | 8 +++---- packages/mcp/cloudwright_mcp/__init__.py | 2 +- packages/web/cloudwright_web/__init__.py | 2 +- server.json | 4 ++-- 8 files changed, 58 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 250795a..2973fdd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,32 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.7.0] - 2026-07-08 + +Closes the July 2026 product audit findings. The differentiating features (offline review, +compliance with OSCAL) now reach every MCP-capable coding agent, not just the CLI; the web tier +is hardened against event-loop stalls and oversized payloads; cost output stops claiming +freshness it does not have; and a new `integrate` command wires cloudwright into 11 coding +harnesses. + +### Added + +- **`cloudwright integrate`.** Generates the exact MCP server config for each popular coding agent (Claude Code, Cursor, Cline, Windsurf, GitHub Copilot, Zed, OpenAI Codex CLI, JetBrains Junie, Kiro, Antigravity) in that client's own format (`mcpServers`, VS Code `servers`, Zed `context_servers`, or Codex TOML), plus a CLI-pipe path for Aider (not an MCP client). `--rules` emits a harness-agnostic gate block for AGENTS.md, CLAUDE.md, or GEMINI.md that tells any agent to run `cloudwright review`/`cost`/`compliance` before it writes infrastructure. `--write` merges into the right file without clobbering existing servers. See `docs/integrations.md`. +- **Review, compliance, and plan as MCP tools.** The MCP server now exposes `review_architecture` (offline critique, no API key), `scan_compliance_controls` (control-mapped findings, with an `oscal` flag returning the OSCAL 1.1.2 component-definition), and `plan_infrastructure` (read-only, validate-only by default, never applies). Any MCP client gets cloudwright's design-time checks in its agent loop. +- **Review and OSCAL on the web canvas.** New `POST /api/review` runs the offline critique; `POST /api/compliance` takes an `oscal` flag. The canvas gains a Review tab (score, grade, findings) and an OSCAL JSON download on the Compliance panel. +- **Honest cost signals.** Cost estimates now report `prices_as_of` (the catalog vintage) and `estimated_on` (today) separately instead of stamping today's date on older price data, and expose a `pricing_confidence_detail` ratio ("17/20 line items catalog-backed"). Cross-provider `compare` carries a per-alternative confidence column. Region pricing uses a real regional catalog row when one exists (high confidence) and only falls back to the static multiplier (medium) when none does. New `docs/provider-coverage.md` states per-provider coverage plainly. +- **MCP session TTL.** MCP sessions older than `CLOUDWRIGHT_MCP_SESSION_TTL_DAYS` (default 7) are swept on server start and session-list. +- **Release and security docs.** `RELEASING.md` (the release runbook) and `SECURITY.md` (disclosure policy) are now committed, plus `schema_version` on the persisted spec for future migrations. + +### Fixed + +- **Web tier no longer stalls the event loop.** Diagram rendering (a d2 subprocess up to 300s) now runs via `asyncio.to_thread`, so one PNG request no longer freezes every other request on the worker. `/api/diagram` gained a request model, so bad input returns 4xx instead of a raw 500. +- **Request-size and component-count caps.** A 1 MB body-size limit and a component-count cap protect the spec-accepting endpoints from resource-exhaustion payloads. The per-IP rate-limiter buckets are now evicted instead of growing without bound. +- **Container no longer serves unauthenticated by accident.** With `CLOUDWRIGHT_REQUIRE_AUTH=1` (set in the Dockerfile) and no `CLOUDWRIGHT_API_KEY`, the app refuses to start; docker-compose fails fast on an empty key. Local `uvicorn` stays open-by-default for development. +- **Structured logging activates on real launch paths.** `configure_logging()` now runs in `create_app()`, so `cloudwright chat --web` and bare `uvicorn` get structured logs and request-id correlation, not just `serve()`. +- **Clean CLI errors.** A malformed spec file now prints `Error: Invalid spec file: field 'name' is required` instead of a Pydantic traceback, and `--json` mode emits `{"error": {"code": ..., "message": ...}}` on failure. Full tracebacks remain available with `--verbose`. +- **CI gains a dependency-CVE gate and a version-sync check.** A `pip-audit` job and a `check_version_sync.py` job (asserting all 13 version markers agree) now run in CI. + ## [1.6.1] - 2026-07-08 Hotfix for a crash in the flagship command, found by the July 2026 product audit. diff --git a/README.md b/README.md index 555896e..919c159 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ cloudwright design "HIPAA healthcare API on AWS with Postgres and Redis" Cloudwright takes a one-line description of a cloud system and produces a structured architecture spec, a per-component cost breakdown, a compliance report, and ready-to-apply Terraform, Pulumi (TypeScript or Python), or CloudFormation. It works across AWS, GCP, Azure, and Databricks. The latest work adds compliance scanning that maps every finding to the framework control it violates (HIPAA / SOC 2 / FedRAMP / PCI-DSS / ISO 27001 / NIST), a `cloudwright plan` step that proves the exported infrastructure actually deploys, and live import for GCP and Azure alongside AWS. -[Try it](#quickstart) - [What's new](#whats-new) - [Docs](docs/) - [MCP server](#mcp-server-claude--cursor--cline) +[Try it](#quickstart) - [What's new](#whats-new) - [Docs](docs/) - [MCP server](#mcp-server-works-with-every-mcp-client) ## What you get @@ -68,18 +68,18 @@ cloudwright chat --web # Open http://localhost:8765, use the Catalog drawer, then Export -> Terraform ``` -## MCP server (Claude / Cursor / Cline) +## MCP server (works with every MCP client) -Expose Cloudwright as [Model Context Protocol](https://modelcontextprotocol.io/) tools so AI agents can design, cost, validate, and export architectures directly. 18 tools across 6 groups (design, cost, validate, analyze, export, session). +Expose Cloudwright as [Model Context Protocol](https://modelcontextprotocol.io/) tools so AI agents can design, cost, validate, review, check compliance, plan, and export architectures directly. Almost every popular coding agent is an MCP client (Claude Code, Cursor, Cline, Windsurf, GitHub Copilot, Zed, OpenAI Codex CLI, JetBrains Junie, Kiro, Antigravity), so one server puts cloudwright inside all of their agent loops. Tool groups: design, cost, validate, analyze, export, session, review, compliance, plan. ```bash pip install cloudwright-ai-mcp cloudwright mcp # all tools, stdio -cloudwright mcp --tools design,cost # subset +cloudwright mcp --tools design,cost,review # subset cloudwright mcp --transport sse # SSE for HTTP clients ``` -`claude_desktop_config.json` (same shape works for Cursor and Cline): +Do not hand-write the config. `cloudwright integrate --harness ` prints the exact wiring for your agent in its own format, and `--write` merges it into the right file. For a manual setup, the base shape (Claude Code, Cursor, Cline, Windsurf, Copilot, Junie) is: ```json { @@ -92,6 +92,8 @@ cloudwright mcp --transport sse # SSE for HTTP clients } ``` +Zed uses `context_servers`, VS Code Copilot uses `servers`, and Codex CLI uses a `[mcp_servers.cloudwright]` TOML table. `cloudwright integrate` emits the right one for each, and Aider (not an MCP client) gets a CLI-pipe recipe. Full matrix in [docs/integrations.md](docs/integrations.md). + ## Analysis `cloudwright lint` (10 anti-pattern checks), `cloudwright score` (5-dimension quality grade), `cloudwright analyze` (blast radius and SPOF), `cloudwright drift ` (design vs deployed), `cloudwright policy --rules policy.yaml` (policy-as-code with 9 built-in checks), `cloudwright security` (security anti-patterns; also scans exported Terraform HCL), `cloudwright compliance --frameworks hipaa,soc2,fedramp` (every finding mapped to its HIPAA / SOC 2 / FedRAMP / PCI-DSS / ISO 27001 / NIST control ID, with optional Checkov deep scan), and `cloudwright plan --target terraform` (proves the exported artifact validates / plans). Every command supports `--json`. See [docs/](docs/) and the `examples/` directory for end-to-end samples. @@ -112,6 +114,21 @@ hcl = export_spec(spec, "terraform", output_dir="./infra") +## What's new in v1.7.0 + +Cloudwright's design-time checks now reach every coding agent, not just its own CLI. Almost every popular AI coding harness speaks MCP, so one server puts `review`, `compliance`, and `plan` inside their agent loops. + +- **`cloudwright integrate` wires cloudwright into 11 harnesses.** It writes the MCP server config in each client's own format (Claude Code, Cursor, Cline, Windsurf, GitHub Copilot, Zed, OpenAI Codex CLI, JetBrains Junie, Kiro, Antigravity), and gives Aider the CLI-pipe path. `cloudwright integrate --rules` emits a gate block for AGENTS.md, CLAUDE.md, or GEMINI.md that tells any agent to run `cloudwright review`/`cost`/`compliance` before it writes infrastructure. See [docs/integrations.md](docs/integrations.md). +- **The MCP server exposes the differentiators.** New `review_architecture` (offline critique, no key), `scan_compliance_controls` (control-mapped, with an `oscal` flag), and read-only `plan_infrastructure` tools. Every MCP client gets them. +- **Review and OSCAL on the web canvas.** A Review tab (score, grade, findings) and an OSCAL JSON download on the Compliance panel. +- **Cost stops overclaiming.** Estimates report `prices_as_of` (catalog vintage) separately from `estimated_on` (today), show a "17/20 catalog-backed" ratio, carry per-alternative confidence in `compare`, and use a real regional price row when the catalog has one. [docs/provider-coverage.md](docs/provider-coverage.md) states per-provider coverage plainly. +- **Web hardening.** Diagram rendering no longer blocks the event loop, spec payloads are size- and component-capped, the container refuses to serve unauthenticated by accident, and malformed input returns a clean error instead of a traceback. + +```bash +cloudwright integrate --harness claude-code # MCP config for your agent +cloudwright integrate --rules --agent-file claude # gate block for CLAUDE.md +``` + ## What's new in v1.6.0

diff --git a/packages/cli/cloudwright_cli/__init__.py b/packages/cli/cloudwright_cli/__init__.py index f49459c..14d9d2f 100644 --- a/packages/cli/cloudwright_cli/__init__.py +++ b/packages/cli/cloudwright_cli/__init__.py @@ -1 +1 @@ -__version__ = "1.6.1" +__version__ = "1.7.0" diff --git a/packages/core/cloudwright/__init__.py b/packages/core/cloudwright/__init__.py index c4535e6..66c1376 100644 --- a/packages/core/cloudwright/__init__.py +++ b/packages/core/cloudwright/__init__.py @@ -17,7 +17,7 @@ ValidationResult, ) -__version__ = "1.6.1" +__version__ = "1.7.0" __all__ = [ "Alternative", diff --git a/packages/core/pyproject.toml b/packages/core/pyproject.toml index 708851f..5d58573 100644 --- a/packages/core/pyproject.toml +++ b/packages/core/pyproject.toml @@ -29,10 +29,10 @@ dependencies = [ ] [project.optional-dependencies] -cli = ["cloudwright-ai-cli==1.6.1"] -web = ["cloudwright-ai-cli==1.6.1", "cloudwright-ai-web==1.6.1"] -mcp = ["cloudwright-ai-mcp==1.6.1"] -all = ["cloudwright-ai-cli==1.6.1", "cloudwright-ai-web==1.6.1", "cloudwright-ai-mcp==1.6.1", "databricks-sdk>=0.38.0"] +cli = ["cloudwright-ai-cli==1.7.0"] +web = ["cloudwright-ai-cli==1.7.0", "cloudwright-ai-web==1.7.0"] +mcp = ["cloudwright-ai-mcp==1.7.0"] +all = ["cloudwright-ai-cli==1.7.0", "cloudwright-ai-web==1.7.0", "cloudwright-ai-mcp==1.7.0", "databricks-sdk>=0.38.0"] pdf = ["weasyprint", "markdown2"] databricks = ["databricks-sdk>=0.38.0"] live-import = [ diff --git a/packages/mcp/cloudwright_mcp/__init__.py b/packages/mcp/cloudwright_mcp/__init__.py index f49459c..14d9d2f 100644 --- a/packages/mcp/cloudwright_mcp/__init__.py +++ b/packages/mcp/cloudwright_mcp/__init__.py @@ -1 +1 @@ -__version__ = "1.6.1" +__version__ = "1.7.0" diff --git a/packages/web/cloudwright_web/__init__.py b/packages/web/cloudwright_web/__init__.py index b72f32c..fc068cd 100644 --- a/packages/web/cloudwright_web/__init__.py +++ b/packages/web/cloudwright_web/__init__.py @@ -1,6 +1,6 @@ """Cloudwright Web — FastAPI backend for architecture intelligence.""" -__version__ = "1.6.1" +__version__ = "1.7.0" def __getattr__(name: str): diff --git a/server.json b/server.json index 92a50d0..275eea3 100644 --- a/server.json +++ b/server.json @@ -2,7 +2,7 @@ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json", "name": "io.github.xmpuspus/cloudwright", "description": "Natural-language cloud architecture: deployable Terraform/Pulumi, cost, compliance control mapping.", - "version": "1.6.1", + "version": "1.7.0", "repository": { "url": "https://github.com/xmpuspus/cloudwright", "source": "github" @@ -12,7 +12,7 @@ "registryType": "pypi", "registryBaseUrl": "https://pypi.org", "identifier": "cloudwright-ai-mcp", - "version": "1.6.1", + "version": "1.7.0", "transport": { "type": "stdio" } From 4c29d6695843ddd5e160542e46683b0eaab41286 Mon Sep 17 00:00:00 2001 From: Xavier Puspus <36430014+xmpuspus@users.noreply.github.com> Date: Wed, 8 Jul 2026 07:56:53 -0700 Subject: [PATCH 10/10] Docs: mcp-reference to 22 tools/9 groups (review/compliance/plan), cost confidence-tier docstring --- docs/mcp-reference.md | 38 +++++++++++++++++++++++++++---- packages/core/cloudwright/cost.py | 4 +++- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/docs/mcp-reference.md b/docs/mcp-reference.md index a0a7105..742c539 100644 --- a/docs/mcp-reference.md +++ b/docs/mcp-reference.md @@ -1,6 +1,6 @@ # MCP Reference -Cloudwright exposes 18 tools across 6 groups as a Model Context Protocol (MCP) server. Any MCP-compatible client (Claude Desktop, Cursor, Cline, and others) can call these tools directly. +Cloudwright exposes 22 tools across 9 groups as a Model Context Protocol (MCP) server. Almost every popular coding agent is an MCP client (Claude Code, Cursor, Cline, Windsurf, GitHub Copilot, Zed, OpenAI Codex CLI, JetBrains Junie, Kiro, Antigravity), so one server puts these tools in all of their agent loops. Run `cloudwright integrate --harness ` to generate the wiring for your client. See [integrations.md](integrations.md). Related: [Getting Started](getting-started.md) | [CLI Reference](cli-reference.md) | [Troubleshooting](troubleshooting.md) | [README](../README.md) @@ -47,7 +47,7 @@ Restart Claude Desktop after editing the file. ## Start the server manually ```bash -# All 18 tools, stdio transport (default) +# All 22 tools, stdio transport (default) cloudwright mcp # Subset of tool groups @@ -57,7 +57,7 @@ cloudwright mcp --tools design,cost cloudwright mcp --transport sse ``` -Valid tool group names for `--tools`: `design`, `cost`, `validate`, `analyze`, `export`, `session`. +Valid tool group names for `--tools`: `design`, `cost`, `validate`, `analyze`, `export`, `session`, `review`, `compliance`, `plan`. --- @@ -132,7 +132,37 @@ Stateful multi-turn conversation sessions. `chat_send` calls an LLM (requires an | `chat_create_session` | Create a stateful design session. Returns a `session_id` handle. Accepts optional provider, monthly budget, and compliance constraints frozen for the session. | | `chat_send` | Send a message to an existing session. Returns the LLM response text, updated ArchSpec (if produced), and token usage for this turn and cumulative. | | `chat_list_sessions` | List all saved sessions with metadata: session_id, timestamps, token usage, and whether a spec is present. | -| `chat_delete_session` | Delete a session and its history. Destructive — no undo. Returns `{deleted: true}` on success. | +| `chat_delete_session` | Delete a session and its history. Destructive, no undo. Returns `{deleted: true}` on success. | + +--- + +### review (1 tool) + +Offline architecture critique. No LLM, no network, no API key. + +| Tool | Description | +|---|---| +| `review_architecture` | Run the deterministic critics (scorer, linter, validator) against an ArchSpec and return a severity-ranked report: `{score, grade, findings, blocking_count, summary}`. Accepts optional `compliance` frameworks and a `well_architected` flag. This is the same engine as the `cloudwright review` CLI command. | + +--- + +### compliance (1 tool) + +Control-mapped compliance scanning with optional OSCAL output. Offline, no API key. + +| Tool | Description | +|---|---| +| `scan_compliance_controls` | Scan an ArchSpec against compliance frameworks and map every finding to its control ID. With `oscal=true`, returns an OSCAL 1.1.2 `component-definition` document instead of the plain report. Optional `checkov` deep scan and `traceability` chain. | + +--- + +### plan (1 tool) + +Read-only deployability check. Never applies changes. + +| Tool | Description | +|---|---| +| `plan_infrastructure` | Export an ArchSpec and run `terraform`/`tofu` `init -backend=false` + `validate` (default), or a full `plan`/`preview` with `run_plan=true`. Returns a structured result. Degrades to `{available: false}` when the IaC toolchain is absent; there is no apply path. | --- diff --git a/packages/core/cloudwright/cost.py b/packages/core/cloudwright/cost.py index 0853252..f745f4b 100644 --- a/packages/core/cloudwright/cost.py +++ b/packages/core/cloudwright/cost.py @@ -513,7 +513,9 @@ def _price_component_with_meta( ) -> tuple[float, str, bool]: """Return (monthly_cost, confidence, is_estimated) for a single component. - confidence: "high" when the price came from a real catalog row, "low" otherwise. + confidence: "high" for a real catalog row, "medium" for a catalog row + rescaled by the static regional multiplier (no real row for that region), + "low" for a formula/fallback price. is_estimated: True when the price is a formula/fallback, not catalog data. region_mult: pre-computed regional multiplier to apply to formula/fallback tiers. """