diff --git a/CHANGELOG.md b/CHANGELOG.md index d96aac0..7c16b28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,37 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.6.0] - 2026-06-16 + +This release closes the defensibility + relevance gaps from the June 2026 product audit: +the design engine now self-corrects, compliance binds at design time with OSCAL output, cost +estimates stop fabricating numbers, and the credibility holes a security review would flag +first are fixed. + +### Added + +- **Generate -> critique -> repair loop + `cloudwright review`.** `Architect.design()` now runs the deterministic critics that already lived in the tree (scorer, linter, validator) against every generated spec and, when blocking (high/critical) findings remain, asks the model once to fix them — bounded, fails safe to the original spec, and records a `critique` block in `spec.metadata` (score, grade, findings/blocking before and after, repair iterations). The same engine is exposed standalone as `cloudwright review spec.yaml [--compliance hipaa,soc2] [--well-architected]` — a free, offline, severity-ranked architecture review with no API key. Disable repair with `Architect(repair=False)`. +- **OSCAL 1.1.2 export.** `cloudwright compliance spec.yaml --frameworks fedramp --oscal [-o report.md]` also emits an OSCAL `component-definition` document (deterministic UUIDs, NIST-style lowercased control IDs, per-component `control-implementations` with satisfied / not-satisfied status). Targets the FedRAMP 20x / OSCAL direction — control mapping a CSPM or evidence tool cannot produce at design time. +- **Control traceability.** `cloudwright compliance spec.yaml --traceability` shows the full chain design intent -> component -> Terraform resource type -> framework control ID -> status, as an audit artifact (`build_traceability()` in `compliance.py`). +- **Compliance-gated component patterns.** New `cloudwright/patterns.py` tags the bundled templates and modules with the frameworks they satisfy; `suggest_compliant_patterns("hipaa")` returns pre-blessed architectures so the tool proposes compliant designs instead of only flagging violations after the fact. +- **Agentic drift -> remediation.** New `cloudwright/remediation.py` `remediate(current, desired)` closes the loop read-only: drift diff -> monthly cost delta -> critique quality delta -> terraform/tofu plan preview, with an honest summary. Exposed via `cloudwright drift ... --remediate`. Never applies; `skip_plan=True` skips the IaC toolchain entirely. +- **Credible cost estimates.** Region-aware pricing (every region was previously priced as us-east-1), per-connection data-transfer/egress estimation, a per-line-item pricing `confidence` (`high` = catalog row, `low` = formula/fallback) with a top-level `pricing_confidence`, design-time carbon estimation (`cloudwright cost --carbon`), and FOCUS-spec CSV export (`cloudwright cost --focus`) for downstream FinOps tools. +- **OpenTofu support.** `cloudwright export spec.yaml --format opentofu` (alias for the Terraform HCL) and a tofu-aware planner that prefers `tofu` when present (override with `CLOUDWRIGHT_TF_BINARY`), falling back to `terraform`. +- **Self-serve docs.** New `docs/getting-started.md`, `docs/cli-reference.md`, `docs/troubleshooting.md`, `docs/mcp-reference.md`. +- **Surfaced telemetry.** The web canvas now renders the model / tokens / cost / latency the backend already computed, and a shared `parseApiError()` makes the canvas show the backend's structured `{code, message, suggestion}` errors and `Retry-After` instead of a generic "Request failed". + +### Fixed + +- **Compliance now overrides the workload profile.** A `sandbox`/`dev` spec carrying a compliance framework (e.g. HIPAA) no longer skips forced encryption / HA — the framework check moved ahead of the non-production early-return in `parsing.py`, with a real regression test (the prior test passed only because it set `production`). +- **WAF Terraform export is deployable.** `aws_wafv2_web_acl` now emits a multi-line `default_action { allow {} }`; the previous single-line nested block was rejected by `terraform validate`. +- **Cost region + fabricated prices.** The `region` parameter is now applied to catalog, formula, and fallback prices; the silent `$10` fallback for unknown services is marked low-confidence/estimated and logged at WARNING. +- **LLM parse failures keep the full response.** `_extract_json` logs the complete model output at debug before raising, instead of discarding everything past 300 characters — the one artifact needed to reproduce the most common LLM bug. + +### Security + +- **Terraform exporter injection hardening.** The 13 numeric resource fields (e.g. `allocated_storage`) are now coerced to real numbers via `_hcl_num`, and the export validator rejects newlines and braces in string values — closing a path where a string-typed numeric field could inject a `provisioner "local-exec"` into the generated HCL. Pulumi and CloudFormation paths were already safe. Regression test included. +- **`cloudwright plan` secret scoping.** The subprocess environment no longer carries the LLM/app API keys (terraform never needs them), only credential-shaped keys are merged from a project `.env`, and any secret-shaped value is redacted from returned `output_tail`. + ## [1.5.0] - 2026-05-19 ### Added diff --git a/README.md b/README.md index 5154598..555896e 100644 --- a/README.md +++ b/README.md @@ -27,9 +27,9 @@ Cloudwright takes a one-line description of a cloud system and produces a struct ## What you get - Architecture spec (typed YAML, version-controlled, the single source of truth) -- Cost breakdown across AWS, GCP, Azure, Databricks (multi-region, per-component, four pricing tiers) -- Compliance report covering HIPAA, SOC 2, PCI-DSS, FedRAMP Moderate, GDPR, and Well-Architected -- Terraform and CloudFormation export with safe defaults (encryption, IMDSv2, locked-down S3, sensible RDS settings) +- Cost breakdown across AWS, GCP, Azure, Databricks (region-aware, per-component, four pricing tiers, optional carbon + FOCUS CSV export). Each line carries a confidence flag — `high` from the bundled price catalog (deepest on AWS), `low` from formula/fallback — so an estimate never silently passes off a guess as a quote. +- Compliance report covering HIPAA, SOC 2, PCI-DSS, FedRAMP Moderate, GDPR, NIST 800-53, and Well-Architected, with OSCAL 1.1.2 export and control traceability +- Terraform, OpenTofu, Pulumi (TypeScript or Python), and CloudFormation export with safe defaults (encryption, IMDSv2, locked-down S3, sensible RDS settings) - Diagrams in ASCII, Mermaid, D2, and a fully editable web canvas - MCP server for AI agents (Claude Desktop, Cursor, Cline, and any MCP-compatible client) @@ -112,7 +112,32 @@ hcl = export_spec(spec, "terraform", output_dir="./infra") -## What's new +## What's new in v1.6.0 + +

+ cloudwright review gives an offline, severity-ranked architecture critique; cloudwright compliance --oscal emits an OSCAL component-definition +

+ +

`cloudwright review` — offline scorer + linter + validator in one report — then the same findings exported as OSCAL.

+ +The design engine now reviews and repairs its own output, compliance binds at design time with OSCAL output, and the cost estimate stops guessing silently. + +- **The architect self-corrects.** Every `cloudwright design` runs the built-in critics (scorer, linter, validator) against the generated spec and, when blocking findings remain, repairs it in one bounded pass before you ever see it — recorded in `spec.metadata.critique`. The same engine is a free, offline command: `cloudwright review spec.yaml` gives a severity-ranked architecture review with no API key. +- **OSCAL + control traceability.** `cloudwright compliance spec.yaml --frameworks fedramp --oscal` emits an OSCAL 1.1.2 component-definition — control mapping a CSPM or evidence tool cannot produce before deploy. `--traceability` prints the chain design intent -> component -> Terraform resource -> control ID -> status. +- **Cost you can defend.** Region-aware pricing (every region used to be priced as us-east-1), data-transfer/egress estimation, a per-line pricing confidence (`high` = catalog, `low` = fallback), design-time carbon (`cloudwright cost --carbon`), and FOCUS-spec CSV export (`--focus`). +- **Drift -> remediation and OpenTofu.** `cloudwright drift ... --remediate` turns drift into a cost + compliance + plan preview (read-only). `cloudwright export --format opentofu` and a tofu-aware `plan`. +- **Hardening.** Terraform exporter injection hardening, `cloudwright plan` no longer carries the LLM key into the IaC subprocess, the WAF export is deployable, and the "compliance overrides workload profile" guarantee is now actually enforced for sandbox specs. + +```bash +cloudwright review spec.yaml # offline, no API key +cloudwright compliance spec.yaml --frameworks fedramp --oscal # OSCAL component-definition +cloudwright cost spec.yaml --carbon --focus # region-aware + carbon + FOCUS CSV +cloudwright export spec.yaml --format opentofu -o ./infra +``` + +See [docs/](docs/) for getting-started, CLI, MCP, and troubleshooting guides. + +## What's new in v1.5.0 Terminal — `cloudwright compliance` maps every finding to its framework control ID, then `cloudwright plan` proves the Terraform validates: diff --git a/docs/cli-reference.md b/docs/cli-reference.md new file mode 100644 index 0000000..4f42d26 --- /dev/null +++ b/docs/cli-reference.md @@ -0,0 +1,664 @@ +# CLI Reference + +Full reference for the `cloudwright` command. See [Getting Started](getting-started.md) for the quick path. + +Related: [Troubleshooting](troubleshooting.md) | [MCP Reference](mcp-reference.md) | [README](../README.md) + +--- + +## Global flags + +These go **before** the subcommand: + +```bash +cloudwright [--json] [--stream] [--verbose] [--dry-run] ... +``` + +| Flag | Description | +|---|---| +| `--json` | Output as JSON instead of rich terminal output | +| `--stream` | NDJSON streaming — one JSON object per line (combine with `--json`) | +| `--dry-run` | Preview LLM calls without making them (shows model, tokens, prompt preview) | +| `--verbose` / `-v` | Verbose logging | +| `--version` / `-V` | Print version and exit | + +--- + +## Design and modify + +### `design` + +Generate a cloud architecture from a natural-language description. + +**Requires:** `ANTHROPIC_API_KEY` or `OPENAI_API_KEY` + +```bash +cloudwright design [options] +``` + +| Option | Default | Description | +|---|---|---| +| `--provider` | `aws` | Cloud provider: `aws`, `gcp`, `azure`, `databricks` | +| `--region` | `us-east-1` | Primary region | +| `--budget` | none | Monthly budget cap in USD | +| `--compliance` | none | Compliance framework(s): `hipaa`, `pci-dss`, `soc2`, `fedramp`, `gdpr`. Repeatable. | +| `--output` / `-o` | auto-save | Write YAML to this file | +| `--yaml` | off | Show YAML panel instead of ASCII diagram | + +Examples: + +```bash +cloudwright design "HIPAA-compliant healthcare API on AWS with Postgres and Redis" +cloudwright design "serverless event pipeline" --provider gcp --region us-central1 +cloudwright design "e-commerce platform" --compliance pci-dss --budget 3000 -o shop.yaml +``` + +v1.6 note: `design` now runs a generate->critique->repair loop. Blocking findings (missing encryption, SPOFs, missing load balancer) are fed back to the model so it self-corrects before the spec is returned. + +--- + +### `modify` + +Apply a natural-language modification to an existing spec. Shows a structured diff and cost delta before writing. + +**Requires:** `ANTHROPIC_API_KEY` or `OPENAI_API_KEY` + +```bash +cloudwright modify [options] +``` + +| Option | Default | Description | +|---|---|---| +| `--output` / `-o` | overwrite input | Write modified spec here | +| `--dry-run` | off | Show changes without writing | + +Examples: + +```bash +cloudwright modify spec.yaml "add a Redis cache between the API and the database" +cloudwright modify spec.yaml "move compute from ECS to Lambda" -o serverless.yaml +cloudwright modify spec.yaml "upgrade the database to Aurora Serverless v2" --dry-run +``` + +--- + +### `compare` + +Translate a spec to one or more other cloud providers and show a side-by-side service and cost comparison. + +**Requires:** `ANTHROPIC_API_KEY` or `OPENAI_API_KEY` + +```bash +cloudwright compare --providers +``` + +Example: + +```bash +cloudwright compare spec.yaml --providers gcp,azure +``` + +--- + +### `chat` + +Multi-turn interactive architecture design. In terminal mode, type a description to get started; use `/help` to see in-session commands (`/yaml`, `/diagram`, `/cost`, `/validate`, `/terraform`, `/export `, `/save`, `/new`). + +**Requires:** `ANTHROPIC_API_KEY` or `OPENAI_API_KEY` + +```bash +cloudwright chat [options] +``` + +| Option | Default | Description | +|---|---|---| +| `--web` | off | Launch web canvas at `http://localhost:8765` instead of terminal | +| `--port` | `8765` | Port for `--web` | +| `--resume` | none | Resume a saved session by ID | +| `--debug` | off | Log LLM requests and token counts to stderr | + +```bash +cloudwright chat # terminal session +cloudwright chat --web # browser canvas +cloudwright chat --resume abc123 # resume prior session +``` + +--- + +## Cost + +### `cost` + +Show monthly cost breakdown for an existing spec. Runs offline. + +```bash +cloudwright cost [options] +``` + +| Option | Default | Description | +|---|---|---| +| `--compare` | none | Comma-separated providers for multi-cloud cost comparison | +| `--pricing-tier` | `on_demand` | `on_demand`, `reserved_1yr`, `reserved_3yr`, `spot` | +| `--workload-profile` / `-w` | none | `small`, `medium`, `large`, `enterprise` — sets realistic traffic/storage defaults | + +Examples: + +```bash +cloudwright cost spec.yaml +cloudwright cost spec.yaml --workload-profile medium +cloudwright cost spec.yaml --compare gcp,azure +cloudwright cost spec.yaml --pricing-tier reserved_1yr +``` + +--- + +## Validate and compliance + +### `validate` + +Run compliance or Well-Architected checks against a spec. Exit code 1 on any failure. + +Runs offline. + +```bash +cloudwright validate --compliance [options] +cloudwright validate --well-architected [options] +``` + +| Option | Default | Description | +|---|---|---| +| `--compliance` | none | Comma-separated frameworks: `hipaa`, `pci-dss`, `soc2`, `fedramp`, `gdpr` | +| `--well-architected` | off | Run Well-Architected pillar checks | +| `--report` | none | Write a markdown compliance report to this path | +| `--pdf` | none | Write a PDF compliance report (requires `cloudwright-ai[pdf]`) | + +Examples: + +```bash +cloudwright validate spec.yaml --compliance hipaa,soc2 +cloudwright validate spec.yaml --well-architected +cloudwright validate spec.yaml --compliance pci-dss --report report.md +``` + +--- + +### `compliance` + +Deeper scan that maps every finding to its exact framework control ID. Optionally folds in a Checkov deep scan against the exported Terraform. + +Runs offline. Checkov integration requires `pip install 'cloudwright-ai[compliance]'` and `checkov` on PATH. + +```bash +cloudwright compliance [options] +``` + +| Option | Default | Description | +|---|---|---| +| `--frameworks` / `-f` | all | Comma-separated: `hipaa`, `soc2`, `pci-dss`, `fedramp`, `gdpr`, `iso27001`, `nist` | +| `--checkov` / `--no-checkov` | auto-detect | Force or skip the Checkov deep scan | +| `--fail-on` | `high` | Fail on: `critical`, `high`, `medium`, `none` | +| `--output` / `-o` | none | Write a markdown control report to this path | + +Examples: + +```bash +cloudwright compliance spec.yaml +cloudwright compliance spec.yaml --frameworks hipaa,soc2 -o controls.md +cloudwright compliance spec.yaml --checkov --fail-on critical +``` + +--- + +### `security` + +Scan for security anti-patterns: unencrypted stores, public-facing databases, missing WAF, weak auth, overly permissive protocols. + +Runs offline. + +```bash +cloudwright security [options] +``` + +| Option | Default | Description | +|---|---|---| +| `--fail-on` | `high` | Fail on: `critical`, `high`, `medium`, `none` | +| `--output` / `-o` | none | Write findings to a file | + +Example: + +```bash +cloudwright security spec.yaml --fail-on medium +``` + +--- + +### `review` (v1.6) + +Unified offline review: runs scorer, linter, and validator together and returns a single severity-ranked finding list. Free, no API key required. + +```bash +cloudwright review [options] +``` + +| Option | Default | Description | +|---|---|---| +| `--compliance` | none | Comma-separated frameworks to include in the validator pass | +| `--well-architected` | off | Include Well-Architected checks | + +Examples: + +```bash +cloudwright review spec.yaml +cloudwright review spec.yaml --compliance hipaa --well-architected +cloudwright --json review spec.yaml +``` + +--- + +## Export and plan + +### `export` + +Export an ArchSpec to IaC, diagram, or audit formats. + +Runs offline (SVG/PNG require the D2 binary: `curl -fsSL https://d2lang.com/install.sh | sh`). + +```bash +cloudwright export --format [options] +``` + +| Option | Description | +|---|---| +| `--format` / `-f` | `terraform`, `pulumi-ts`, `pulumi-python`, `cloudformation`, `mermaid`, `d2`, `svg`, `png`, `sbom`, `aibom` | +| `--output` / `-o` | Output file or directory. For `terraform`, `pulumi-ts`, `pulumi-python`: pass a directory path for a full project layout. | + +Examples: + +```bash +cloudwright export spec.yaml --format terraform -o ./infra +cloudwright export spec.yaml --format pulumi-ts -o ./infra +cloudwright export spec.yaml --format cloudformation -o template.yaml +cloudwright export spec.yaml --format mermaid +cloudwright export spec.yaml --format sbom -o sbom.json +``` + +--- + +### `plan` + +Prove the exported infrastructure is deployable. Runs `terraform validate` and optionally `terraform plan` (or `pulumi preview`). Nothing is applied. + +Requires Terraform or Pulumi on PATH. `--no-plan` skips the credential-requiring plan step. + +```bash +cloudwright plan [options] +``` + +| Option | Default | Description | +|---|---|---| +| `--target` / `-t` | `terraform` | `terraform`, `pulumi-python`, `pulumi-ts` | +| `--no-plan` | off | Validate only (no credentials needed) | +| `--timeout` | `180` | Seconds before the plan step is aborted | + +Examples: + +```bash +cloudwright plan spec.yaml +cloudwright plan spec.yaml --no-plan +cloudwright plan spec.yaml --target pulumi-ts +cloudwright --json plan spec.yaml +``` + +--- + +## Import and drift + +### `import` + +Import an existing Terraform state file or CloudFormation template into an ArchSpec YAML. + +Runs offline. + +```bash +cloudwright import [options] +``` + +| Option | Default | Description | +|---|---|---| +| `--format` / `-f` | auto-detect | `terraform` or `cloudformation` | +| `--output` / `-o` | stdout | Write ArchSpec YAML to this file | +| `--name` | from source | Override the architecture name | + +Examples: + +```bash +cloudwright import terraform.tfstate -o spec.yaml +cloudwright import stack.yaml --format cloudformation -o spec.yaml +``` + +--- + +### `import-live` + +Walk live cloud APIs to produce an ArchSpec from running infrastructure. Requires `pip install 'cloudwright-ai[live-import]'` and cloud credentials. + +```bash +cloudwright import-live [options] +``` + +| Option | Default | Description | +|---|---|---| +| `--provider` | `aws` | `aws`, `gcp`, `azure` | +| `--region` | `us-east-1` | Cloud region | +| `--profile` | none | AWS named profile (`~/.aws/credentials`) | +| `--project` | none | GCP project ID (or `GOOGLE_CLOUD_PROJECT` env) | +| `--subscription` | none | Azure subscription ID (or `AZURE_SUBSCRIPTION_ID` env) | +| `--services` | all | Comma-separated subset, e.g. `ec2,rds,s3` | +| `--output` / `-o` | stdout | Write ArchSpec YAML to this file | +| `--name` | auto | Override the architecture name | + +Examples: + +```bash +cloudwright import-live --provider aws --region us-east-1 -o spec.yaml +cloudwright import-live --provider aws --profile staging --services ec2,rds +cloudwright import-live --provider gcp --project my-project-123 -o gcp-spec.yaml +cloudwright import-live --provider azure --subscription xxxxxxxx-xxxx-... -o azure.yaml +``` + +--- + +### `drift` + +Compare a design spec against deployed infrastructure to detect configuration drift. + +Runs offline. + +```bash +cloudwright drift [options] +``` + +| Option | Default | Description | +|---|---|---| +| `--format` / `-f` | `auto` | Infrastructure format: `auto`, `terraform`, `cloudformation` | + +Example: + +```bash +cloudwright drift spec.yaml terraform.tfstate +cloudwright --json drift spec.yaml stack.yaml --format cloudformation +``` + +--- + +### `diff` + +Show the structural diff between two ArchSpec files: added, removed, and changed components, and total cost delta. + +Runs offline. + +```bash +cloudwright diff +``` + +Example: + +```bash +cloudwright diff v1.yaml v2.yaml +cloudwright --json diff v1.yaml v2.yaml +``` + +--- + +## Analysis + +### `lint` + +Detect architecture anti-patterns: unencrypted data stores, single-AZ databases, missing load balancer on public compute, missing auth, oversized instances. + +Runs offline. + +```bash +cloudwright lint [options] +``` + +| Option | Default | Description | +|---|---|---| +| `--strict` | off | Fail on warnings in addition to errors | + +Example: + +```bash +cloudwright lint spec.yaml +cloudwright lint spec.yaml --strict +cloudwright --json --stream lint spec.yaml +``` + +--- + +### `score` + +Score an architecture across 5 dimensions: reliability (30%), security (25%), cost efficiency (20%), compliance (15%), complexity (10%). Returns 0-100 with a letter grade. + +Runs offline. + +```bash +cloudwright score [options] +``` + +| Option | Default | Description | +|---|---|---| +| `--with-cost` | off | Run cost estimation before scoring (improves cost-dimension accuracy) | + +Example: + +```bash +cloudwright score spec.yaml +cloudwright score spec.yaml --with-cost +``` + +--- + +### `analyze` + +Analyze blast radius, single points of failure, and dependency structure. + +Runs offline. + +```bash +cloudwright analyze [options] +``` + +| Option | Default | Description | +|---|---|---| +| `--component` / `-c` | all | Focus analysis on a specific component ID | + +Examples: + +```bash +cloudwright analyze spec.yaml +cloudwright analyze spec.yaml --component rds_primary +``` + +--- + +### `policy` + +Evaluate a spec against custom policy rules defined in a YAML file. Built-in checks cover budget limits, provider constraints, required components, and compliance flags. + +Runs offline. + +```bash +cloudwright policy --rules +``` + +Exit code 1 when any `deny` rule fires. + +--- + +### `adr` + +Generate an Architecture Decision Record (MADR format) from a spec. + +**Requires:** `ANTHROPIC_API_KEY` or `OPENAI_API_KEY` (falls back to a deterministic template if the LLM is unavailable). + +```bash +cloudwright adr [options] +``` + +| Option | Default | Description | +|---|---|---| +| `--output` / `-o` | stdout | Write the ADR markdown to this file | +| `--title` | auto | ADR title | +| `--decision` | auto | Specific decision to document | + +Example: + +```bash +cloudwright adr spec.yaml -o docs/adr-001.md +cloudwright adr spec.yaml --decision "use Aurora Serverless over standard RDS" +``` + +--- + +## Misc + +### `init` + +Create an ArchSpec from a pre-built template. Use `--list` to see available templates. + +Runs offline. + +```bash +cloudwright init --template [options] +cloudwright init --list +``` + +| Option | Default | Description | +|---|---|---| +| `--template` / `-t` | none | Template name (see `--list`) | +| `--output` / `-o` | `spec.yaml` | Output file | +| `--list` / `-l` | off | List available templates | +| `--provider` | from template | Override provider | +| `--region` | from template | Override region | +| `--name` | from template | Override architecture name | +| `--compliance` | none | Comma-separated compliance frameworks | +| `--budget` | none | Monthly budget in USD | +| `--project` / `-p` | off | Create a `.cloudwright/` project directory with a config file | + +Examples: + +```bash +cloudwright init --list +cloudwright init --template aws-three-tier -o infra.yaml +cloudwright init --template aws-three-tier --compliance hipaa --budget 5000 +``` + +--- + +### `schema` + +Look up service config fields, pricing formula, and cross-cloud equivalents, or list the checks for a compliance framework. + +Runs offline. + +```bash +cloudwright schema +``` + +`query` is either a `provider.service` key (e.g. `aws.ec2`, `gcp.cloud_sql`) or a compliance framework name (`hipaa`, `soc2`). + +Examples: + +```bash +cloudwright schema aws.ec2 +cloudwright schema gcp.cloud_run +cloudwright schema hipaa +cloudwright --json schema aws.rds +``` + +--- + +### `catalog` + +Search and compare cloud instances from the bundled pricing catalog. + +Runs offline. + +```bash +cloudwright catalog search [options] +cloudwright catalog compare ... +``` + +| `search` option | Description | +|---|---| +| `--provider` | Filter by provider: `aws`, `gcp`, `azure` | +| `--vcpus` | Minimum vCPUs | +| `--memory` | Minimum memory in GB | + +Examples: + +```bash +cloudwright catalog search "memory-optimized aws" +cloudwright catalog search "4 vcpu 32gb" --provider aws +cloudwright catalog compare m5.xlarge m6i.xlarge +``` + +--- + +### `refresh` + +Fetch live pricing from cloud provider APIs and write into the local catalog database. + +Requires network access. Does not require an LLM key. + +```bash +cloudwright refresh [options] +``` + +| Option | Default | Description | +|---|---|---| +| `--provider` / `-p` | all | `aws`, `gcp`, or `azure` | +| `--category` / `-c` | all | Filter to a category or service name | +| `--region` / `-r` | default | Override region for pricing lookups | +| `--dry-run` | off | Fetch but don't write to catalog | + +--- + +### `databricks-validate` + +Validate Databricks components in a spec against a live workspace. Requires `pip install 'cloudwright-ai[databricks]'` and `DATABRICKS_HOST` / `DATABRICKS_TOKEN`. + +```bash +cloudwright databricks-validate [--host URL] [--token TOKEN] +``` + +--- + +### `mcp` + +Start an MCP server exposing Cloudwright tools to AI agents (Claude Desktop, Cursor, Cline). + +```bash +cloudwright mcp [options] +``` + +| Option | Default | Description | +|---|---|---| +| `--tools` / `-t` | all | Comma-separated tool groups: `design`, `cost`, `validate`, `analyze`, `export`, `session` | +| `--transport` | `stdio` | `stdio` or `sse` | + +See [MCP Reference](mcp-reference.md) for setup instructions. + +## New flags in v1.6.0 + +| Command | Flag | Purpose | +|---|---|---| +| `compliance` | `--oscal` / `-O` | Also emit an OSCAL 1.1.2 component-definition JSON (to `.oscal.json` when `--output` is set, else stdout). | +| `compliance` | `--traceability` | Print the chain component -> Terraform resource -> framework control ID -> status. | +| `cost` | `--carbon` | Include a design-time carbon (kg CO2e/month) estimate. | +| `cost` | `--focus` | Emit a FinOps FOCUS-spec CSV of the cost line items (`-o file.csv` or stdout). | +| `export` | `--format opentofu` | Alias for the Terraform HCL target (OpenTofu-compatible). `tofu`/`terraform` for `plan` is auto-detected; override with `CLOUDWRIGHT_TF_BINARY`. | +| `drift` | `--remediate` | Turn detected drift into a read-only remediation preview: diff -> cost delta -> quality delta -> terraform/tofu plan. | + +`cloudwright design` now runs a generate -> critique -> repair loop by default and records a `critique` block (score, grade, findings, repair iterations) in `spec.metadata`. The same critics are exposed offline as `cloudwright review `. diff --git a/docs/getting-started.md b/docs/getting-started.md new file mode 100644 index 0000000..f408ad7 --- /dev/null +++ b/docs/getting-started.md @@ -0,0 +1,231 @@ +# Getting Started + +This guide gets you from zero to a deployable architecture spec in about five minutes. + +Related: [CLI Reference](cli-reference.md) | [Troubleshooting](troubleshooting.md) | [MCP Reference](mcp-reference.md) | [README](../README.md) + +--- + +## Install + +Cloudwright is published as four packages. The `[cli]` extra is the starting point for most users. + +```bash +pip install 'cloudwright-ai[cli]' +``` + +Other extras: + +| Extra | What it adds | +|---|---| +| `[cli]` | The `cloudwright` command | +| `[web]` | FastAPI backend + React canvas (`cloudwright chat --web`) | +| `[mcp]` | MCP server for Claude Desktop / Cursor / Cline | +| `[all]` | All of the above | +| `[pdf]` | PDF compliance report export | +| `[live-import]` | `import-live` for AWS, GCP, and Azure | +| `[live-import-aws]` | AWS-only live import (boto3) | +| `[live-import-gcp]` | GCP-only live import | +| `[live-import-azure]` | Azure-only live import | +| `[compliance]` | Checkov deep scan in `cloudwright compliance` | +| `[databricks]` | `databricks-validate` adapter | + +All extras together: + +```bash +pip install 'cloudwright-ai[all]' +``` + +Requires Python 3.12 or later. + +--- + +## Set your API key + +`cloudwright design`, `cloudwright modify`, `cloudwright compare`, `cloudwright chat`, and `cloudwright adr` call an LLM. All other commands run offline. + +```bash +export ANTHROPIC_API_KEY=sk-ant-... +``` + +OpenAI also works: + +```bash +export OPENAI_API_KEY=sk-... +``` + +Cloudwright picks up whichever key is present. Anthropic (Claude Sonnet for design, Haiku for projection) is preferred when both are set. + +--- + +## Design your first architecture + +```bash +cloudwright design "3-tier web app on AWS with PostgreSQL and Redis" +``` + +This runs the LLM, prints an ASCII diagram and cost table, and auto-saves a `spec.yaml` in the current directory. v1.6 adds a generate->critique->repair loop: blocking findings (missing encryption, single points of failure) are fed back to the model before the spec is returned. + +Common options: + +```bash +# Target a different provider or region +cloudwright design "serverless API" --provider gcp --region us-central1 + +# Add compliance constraints +cloudwright design "healthcare API with Postgres" --compliance hipaa --compliance soc2 + +# Set a monthly budget cap +cloudwright design "data pipeline" --budget 2000 + +# Save spec to a specific file +cloudwright design "..." -o my-arch.yaml + +# Print YAML panel instead of ASCII diagram +cloudwright design "..." --yaml +``` + +The global `--dry-run` flag shows what the LLM call would look like without making it: + +```bash +cloudwright --dry-run design "3-tier web app on AWS" +``` + +--- + +## Estimate cost + +`cost` runs offline against a bundled SQLite pricing catalog. No API key needed. + +```bash +cloudwright cost spec.yaml +cloudwright cost spec.yaml --workload-profile medium +``` + +Workload profiles (`small`, `medium`, `large`, `enterprise`) set realistic defaults for request volumes, storage, node counts, and data transfer. + +--- + +## Validate against a compliance framework + +```bash +cloudwright validate spec.yaml --compliance hipaa +cloudwright validate spec.yaml --compliance hipaa,soc2 +cloudwright validate spec.yaml --well-architected +cloudwright validate spec.yaml --compliance pci-dss --report report.md +``` + +Available frameworks: `hipaa`, `pci-dss`, `soc2`, `fedramp`, `gdpr`, plus `well-architected`. Exit code is non-zero when any check fails. + +For a deeper scan that maps each finding to its specific control ID (HIPAA `164.312`, SOC 2 `CC6.1`, FedRAMP `SC-28`, PCI-DSS, GDPR, ISO 27001, NIST 800-53) and optionally folds in Checkov against the generated Terraform: + +```bash +cloudwright compliance spec.yaml --frameworks hipaa,soc2 +``` + +--- + +## Export to Terraform (or Pulumi / CloudFormation) + +```bash +# Print HCL to stdout +cloudwright export spec.yaml --format terraform + +# Write a Terraform project directory +cloudwright export spec.yaml --format terraform -o ./infra + +# Pulumi TypeScript or Python project +cloudwright export spec.yaml --format pulumi-ts -o ./infra +cloudwright export spec.yaml --format pulumi-python -o ./infra + +# CloudFormation YAML +cloudwright export spec.yaml --format cloudformation -o template.yaml +``` + +All IaC exporters apply safe defaults: S3 public-access blocks, RDS encryption and deletion protection, EC2 IMDSv2, CloudFront TLSv1.2_2021. + +--- + +## Prove the export deploys (requires Terraform or Pulumi on PATH) + +```bash +# Offline proof: runs terraform validate, no cloud credentials needed +cloudwright plan spec.yaml --no-plan + +# Full proof: runs terraform plan with a real resource diff +cloudwright plan spec.yaml +``` + +Nothing is applied. The verdict is `DEPLOYABLE` or `NOT DEPLOYABLE`. + +--- + +## Commands that work fully offline + +No LLM call, no cloud API call, no environment variables needed: + +| Command | What it does | +|---|---| +| `cost` | Estimate monthly bill from bundled catalog | +| `validate` | Compliance and Well-Architected checks | +| `review` | Unified scorer + linter + validator (v1.6) | +| `export` | Generate Terraform / Pulumi / CloudFormation / diagrams | +| `diff` | Compare two ArchSpec files | +| `drift` | Compare spec against .tfstate or CloudFormation template | +| `lint` | Architecture anti-pattern detection | +| `score` | 5-dimension quality score (0-100) | +| `analyze` | Blast radius and SPOF analysis | +| `security` | Security anti-pattern scan | +| `compliance` | Control-mapped compliance scan (Checkov is optional) | +| `import` | Import .tfstate or CloudFormation into an ArchSpec | +| `schema` | Browse service configs and compliance checks | +| `catalog search` | Search cloud instance catalog | +| `catalog compare` | Compare instance types side by side | +| `init` | Create a spec from a pre-built template | + +Commands that call an LLM (require `ANTHROPIC_API_KEY` or `OPENAI_API_KEY`): + +- `design` — generate a new architecture +- `modify` — update an existing spec with a natural-language instruction +- `compare` — translate a spec to other providers +- `chat` — multi-turn terminal or web session +- `adr` — generate an Architecture Decision Record + +--- + +## Web canvas + +```bash +pip install 'cloudwright-ai[web]' +cloudwright chat --web +``` + +Opens `http://localhost:8765`. The canvas lets you chat to design, drag and drop components, edit fields, add resources from the catalog drawer, and run Compliance and Plan checks in the UI. + +Use a different port: + +```bash +cloudwright chat --web --port 9000 +``` + +--- + +## Machine-readable output + +Every command accepts `--json` before the subcommand: + +```bash +cloudwright --json cost spec.yaml +cloudwright --json validate spec.yaml --compliance hipaa + +# NDJSON streaming: one JSON line per finding +cloudwright --json --stream security spec.yaml +``` + +--- + +## Next steps + +- [CLI Reference](cli-reference.md) — every command with all options +- [Troubleshooting](troubleshooting.md) — common errors and fixes +- [MCP Reference](mcp-reference.md) — use Cloudwright from Claude Desktop or Cursor diff --git a/docs/mcp-reference.md b/docs/mcp-reference.md new file mode 100644 index 0000000..a0a7105 --- /dev/null +++ b/docs/mcp-reference.md @@ -0,0 +1,216 @@ +# 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. + +Related: [Getting Started](getting-started.md) | [CLI Reference](cli-reference.md) | [Troubleshooting](troubleshooting.md) | [README](../README.md) + +--- + +## Install + +The MCP server is a separate package: + +```bash +pip install cloudwright-ai-mcp +``` + +Or install it alongside the CLI and web extras: + +```bash +pip install 'cloudwright-ai[all]' +``` + +--- + +## Configure Claude Desktop + +Add this to `claude_desktop_config.json` (same shape works for Cursor and Cline): + +```json +{ + "mcpServers": { + "cloudwright": { + "command": "cloudwright", + "args": ["mcp"] + } + } +} +``` + +On macOS, the config file is at: +`~/Library/Application Support/Claude/claude_desktop_config.json` + +Restart Claude Desktop after editing the file. + +--- + +## Start the server manually + +```bash +# All 18 tools, stdio transport (default) +cloudwright mcp + +# Subset of tool groups +cloudwright mcp --tools design,cost + +# SSE transport for HTTP clients +cloudwright mcp --transport sse +``` + +Valid tool group names for `--tools`: `design`, `cost`, `validate`, `analyze`, `export`, `session`. + +--- + +## Tool groups and tools + +### design (3 tools) + +LLM-powered tools for creating and evolving architectures. These call an LLM and require `ANTHROPIC_API_KEY` or `OPENAI_API_KEY`. + +| Tool | Description | +|---|---| +| `design_architecture` | Generate a cloud architecture from a natural-language description. Returns a complete ArchSpec with components, connections, and cost estimate. | +| `modify_architecture` | Apply a natural-language modification instruction to an existing ArchSpec. Returns an updated spec. | +| `compare_providers` | Translate an ArchSpec to one or more target providers, returning one alternative ArchSpec per provider. | + +--- + +### cost (2 tools) + +Pricing computation. Both tools are pure offline calculation — no LLM, no network, no API cost. + +| Tool | Description | +|---|---| +| `estimate_cost` | Estimate the monthly bill for an ArchSpec. Returns a per-component breakdown and total. Supports pricing tiers: `on_demand`, `reserved_1yr`, `reserved_3yr`, `spot`. | +| `compare_provider_costs` | Compare the monthly cost totals of an ArchSpec across cloud providers. Returns one numeric cost summary per provider. | + +--- + +### validate (4 tools) + +Static analysis and compliance checks. All tools are offline — no LLM, no network, read-only. + +| Tool | Description | +|---|---| +| `validate_compliance` | Validate an ArchSpec against compliance frameworks (`hipaa`, `pci-dss`, `soc2`, `fedramp`, `gdpr`). Returns pass/fail per check with remediation hints. | +| `security_scan` | Scan an ArchSpec for security anti-patterns (unencrypted stores, public databases, missing WAF, weak auth). Returns severity-graded findings per component. | +| `scan_terraform` | Scan Terraform HCL source directly for security misconfigurations. No Terraform binary invoked. | +| `lint_architecture` | Lint an ArchSpec for architectural anti-patterns. Returns warnings with rule name, severity, component IDs, and recommendation. | + +--- + +### analyze (3 tools) + +Structural analysis and quality scoring. All tools are offline, read-only. + +| Tool | Description | +|---|---| +| `analyze_blast_radius` | Analyze blast radius, SPOFs, and dependency structure. Returns direct and transitive dependents per component. Optionally scoped to one component ID. | +| `score_architecture` | Score an ArchSpec across 5 dimensions (reliability, security, cost efficiency, compliance, complexity). Returns per-dimension scores, weighted total (0-100), and letter grade. | +| `diff_architectures` | Diff two ArchSpec files. Returns added/removed/changed components, connections, cost delta, compliance impact, and a human-readable summary. | + +--- + +### export (3 tools) + +IaC generation and catalog lookup. All tools are offline. + +| Tool | Description | +|---|---| +| `export_architecture` | Export an ArchSpec to Terraform HCL, CloudFormation YAML, Mermaid, D2, SBOM, AIBOM, or compliance markdown. Returns `{format, content}`. | +| `list_services` | List all cloud services in the registry for a given provider (aws, gcp, azure, databricks). Returns slug, name, category, and supported tiers per service. | +| `catalog_search` | Search the cloud instance catalog by provider, text query, vCPU count, memory size, or maximum hourly price. Returns matching instances with specs and pricing. | + +--- + +### session (4 tools) + +Stateful multi-turn conversation sessions. `chat_send` calls an LLM (requires an API key); the others are offline. + +| Tool | Description | +|---|---| +| `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. | + +--- + +## Example: design and export from Claude + +Once configured, you can ask Claude: + +> "Design a HIPAA-compliant 3-tier API on AWS with PostgreSQL, then export it as Terraform." + +Claude will call `design_architecture` with `compliance=["hipaa"]`, receive the ArchSpec, then call `export_architecture` with `format="terraform"` and return the HCL. + +--- + +## Example: multi-turn session + +``` +User: Create a conversation session for an AWS architecture with a $5000/month budget. + [calls chat_create_session -> {session_id: "abc123def456"}] + +User: Design a web app with a CDN and a managed database. + [calls chat_send(session_id="abc123def456", message="Design...")] + +User: Add a Redis cache. + [calls chat_send(session_id="abc123def456", message="Add a Redis cache")] +``` + +Sessions persist across Claude Desktop restarts (stored on disk in `~/.cloudwright/sessions/`). + +--- + +## Which tools need an API key + +Tools that call an LLM (`ANTHROPIC_API_KEY` or `OPENAI_API_KEY` required): + +- `design_architecture` +- `modify_architecture` +- `compare_providers` +- `chat_send` + +All other tools are pure computation: no LLM, no network, no cost beyond the MCP call itself. + +--- + +## Partial tool registration + +To limit which tools the AI agent can call (useful for cost control or read-only contexts): + +```bash +# Only offline analysis tools +cloudwright mcp --tools validate,analyze,export + +# Only design tools (LLM-backed) +cloudwright mcp --tools design,session + +# Cost tools only +cloudwright mcp --tools cost +``` + +--- + +## SSE transport + +For clients that prefer HTTP/SSE over stdio: + +```bash +cloudwright mcp --transport sse +``` + +The server listens on a local port. Configure the client with the SSE endpoint URL instead of a command/args pair. + +--- + +## Troubleshooting MCP + +**Tools not appearing in Claude Desktop:** Restart Claude Desktop after editing `claude_desktop_config.json`. Confirm `cloudwright` is on PATH by running `cloudwright --version` in a terminal. + +**`cloudwright-ai-mcp` not installed:** Run `pip install cloudwright-ai-mcp` and confirm the `cloudwright` binary is the one from that environment. + +**LLM tools return errors:** Set `ANTHROPIC_API_KEY` or `OPENAI_API_KEY` in the shell environment where Claude Desktop runs (on macOS, this may require setting it in `~/.zshenv` rather than `~/.zshrc`). + +See [Troubleshooting](troubleshooting.md) for more. diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md new file mode 100644 index 0000000..728a70a --- /dev/null +++ b/docs/troubleshooting.md @@ -0,0 +1,362 @@ +# Troubleshooting + +Common errors and how to fix them. + +Related: [Getting Started](getting-started.md) | [CLI Reference](cli-reference.md) | [README](../README.md) + +--- + +## Missing API key + +**Symptom:** + +``` +Error: No LLM provider configured. Set ANTHROPIC_API_KEY or OPENAI_API_KEY. +``` + +or + +``` +RuntimeError: No LLM provider configured. +``` + +**Fix:** + +```bash +export ANTHROPIC_API_KEY=sk-ant-... +# or +export OPENAI_API_KEY=sk-... +``` + +This is only required for commands that call an LLM: `design`, `modify`, `compare`, `chat`, and `adr`. Everything else runs offline. + +To verify which commands are offline, see the [command list in Getting Started](getting-started.md#commands-that-work-fully-offline). + +--- + +## Wrong extras version (lockstep requirement) + +**Symptom:** + +``` +ImportError: cannot import name 'X' from 'cloudwright' +``` + +or features from a recent release are missing after upgrading. + +**Cause:** + +The four Cloudwright packages (`cloudwright-ai`, `cloudwright-ai-cli`, `cloudwright-ai-web`, `cloudwright-ai-mcp`) must be on the same version. The extras pins in `cloudwright-ai[cli]` etc. enforce this, but a partial install or a manual pip upgrade of just one package can break the lockstep. + +**Fix:** + +```bash +pip install 'cloudwright-ai[all]=={version}' --force-reinstall +``` + +Replace `{version}` with the target version (e.g. `1.6.0`). Check the current installed version with: + +```bash +cloudwright --version +``` + +--- + +## `cloudwright plan` fails because terraform is not on PATH + +**Symptom:** + +``` +[SKIP] terraform not found on PATH +``` + +or + +``` +FileNotFoundError: terraform +``` + +**Fix:** + +Install Terraform: https://developer.hashicorp.com/terraform/install + +Then verify: + +```bash +terraform version +``` + +If you only want offline proof without cloud credentials, pass `--no-plan`: + +```bash +cloudwright plan spec.yaml --no-plan +``` + +This runs `terraform validate` only and does not need credentials. + +For Pulumi targets, install Pulumi: https://www.pulumi.com/docs/install/ + +--- + +## `cloudwright plan` times out + +**Symptom:** + +``` +[SKIP] plan timed out after 180s +``` + +or the command hangs for several minutes before failing. + +**Fix:** + +Extend the timeout (in seconds): + +```bash +cloudwright plan spec.yaml --timeout 600 +``` + +Common causes: slow network when Terraform downloads provider plugins on first init, or an unusually large plan against a cloud account with many existing resources. + +--- + +## Provider credential errors during `plan` or `import-live` + +**Symptom:** + +``` +Error: No valid credential sources found for AWS Provider. +``` + +or permission-denied messages from GCP / Azure. + +**Fix for plan:** Use `--no-plan` to skip the credential-requiring step: + +```bash +cloudwright plan spec.yaml --no-plan +``` + +**Fix for import-live:** Configure credentials before running: + +- AWS: `aws configure` or set `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY`, or use `--profile ` for a named profile. +- GCP: `gcloud auth application-default login`, then pass `--project `. +- Azure: `az login`, then pass `--subscription `. + +Per-service permission errors during `import-live` are non-fatal. Components Cloudwright cannot read are skipped and reported on stderr. + +--- + +## Rate limiting + +**Symptom:** + +``` +Rate limited, try again in a moment. +``` + +or HTTP 429 responses from the LLM provider. + +**Fix:** + +Wait 10-30 seconds and retry. If this happens frequently, you are hitting the API tier's rate limit. Options: + +- Reduce concurrency if you are running multiple `design` calls in parallel. +- Use `--dry-run` to check prompt size without making the call. +- Upgrade your API tier on the provider's dashboard. + +--- + +## Provider download / network timeout during `plan` + +**Symptom:** + +Terraform stalls downloading a provider plugin, or the plan times out waiting for network. + +**Fix:** + +If you are behind a proxy, set `HTTPS_PROXY` in your environment before running `cloudwright plan`. Alternatively, pre-download the provider: + +```bash +cd /tmp && terraform init -from-module github.com/hashicorp/example +``` + +Or run with `--no-plan` to skip the network-dependent provider download: + +```bash +cloudwright plan spec.yaml --no-plan +``` + +--- + +## SVG or PNG export fails ("D2 binary not found") + +**Symptom:** + +``` +Warning: D2 binary not found — returning D2 source text. +``` + +or for PNG: + +``` +Error: D2 binary not found +``` + +**Fix:** + +```bash +curl -fsSL https://d2lang.com/install.sh | sh +``` + +Then verify: + +```bash +d2 --version +``` + +The `mermaid`, `terraform`, `cloudformation`, `sbom`, and `aibom` formats do not need D2. + +--- + +## PDF compliance report fails + +**Symptom:** + +``` +ImportError: No module named 'weasyprint' +``` + +**Fix:** + +```bash +pip install 'cloudwright-ai[pdf]' +``` + +--- + +## `import-live` fails with ImportError + +**Symptom:** + +``` +Live import core is unavailable. Install with: pip install 'cloudwright-ai[live-import]' +``` + +**Fix:** + +```bash +pip install 'cloudwright-ai[live-import]' +``` + +For provider-specific installs: + +```bash +pip install 'cloudwright-ai[live-import-aws]' # AWS only +pip install 'cloudwright-ai[live-import-gcp]' # GCP only +pip install 'cloudwright-ai[live-import-azure]' # Azure only +``` + +--- + +## `databricks-validate` fails with ImportError + +**Symptom:** + +``` +Error: databricks-sdk not installed. Run: pip install cloudwright-ai[databricks] +``` + +**Fix:** + +```bash +pip install 'cloudwright-ai[databricks]' +``` + +Then set `DATABRICKS_HOST` and `DATABRICKS_TOKEN` (or pass them as options). + +--- + +## Behavioral tests fail with API key set + +**Symptom (for contributors running the test suite):** + +Tests in `test_e2e.py`, `test_architect.py`, and the web `test_api.py` make live LLM calls when `ANTHROPIC_API_KEY` or `OPENAI_API_KEY` is set, causing them to be slow or incur costs. + +**Fix:** + +Unset the keys before running tests to match CI behavior: + +```bash +env -u ANTHROPIC_API_KEY -u OPENAI_API_KEY python -m pytest packages/core/tests -q --timeout=60 +``` + +Live-LLM tests (`test_e2e.py::TestLLM::*`) are expected to fail with keys unset. This is not a regression. + +--- + +## Web canvas shows a blank page or errors on startup + +**Symptom:** + +Browser shows nothing or a JavaScript error after `cloudwright chat --web`. + +**Cause:** + +The static bundle in `packages/web/cloudwright_web/static/` may be stale (built from a previous version) or missing. + +**Fix:** + +Rebuild the frontend: + +```bash +cd packages/web/frontend && npm run build +rm -rf ../cloudwright_web/static +cp -r dist ../cloudwright_web/static +``` + +Then restart: + +```bash +cloudwright chat --web +``` + +--- + +## Port already in use + +**Symptom:** + +``` +Error: port 8765 is already in use. +``` + +**Fix:** + +```bash +cloudwright chat --web --port 9000 +``` + +--- + +## `cloudwright compliance` Checkov scan doesn't run + +**Symptom:** + +The compliance output shows `scanner: builtin` even though you expected Checkov to run. + +**Fix:** + +Checkov must be on PATH: + +```bash +pip install checkov +checkov --version +``` + +Also install the compliance extra: + +```bash +pip install 'cloudwright-ai[compliance]' +``` + +Checkov is auto-detected. You can force it with `--checkov` or skip it with `--no-checkov`. diff --git a/examples/cloudwright-review-demo.gif b/examples/cloudwright-review-demo.gif new file mode 100644 index 0000000..53b9fb3 Binary files /dev/null and b/examples/cloudwright-review-demo.gif differ diff --git a/examples/patient-portal.yaml b/examples/patient-portal.yaml new file mode 100644 index 0000000..7e2c2cb --- /dev/null +++ b/examples/patient-portal.yaml @@ -0,0 +1,41 @@ +name: Patient Portal +version: 1 +provider: aws +region: us-east-1 +components: +- id: api + service: ec2 + provider: aws + label: API Server + tier: 2 + config: + instance_type: t3.large +- id: db + service: rds + provider: aws + label: Patient DB + tier: 3 + config: + engine: postgres + instance_class: db.r5.large + allocated_storage: 200 +- id: cache + service: elasticache + provider: aws + label: Session Cache + tier: 3 + config: + engine: redis +connections: +- source: api + target: db + protocol: TCP + port: 5432 +- source: api + target: cache + protocol: TCP + port: 6379 +metadata: + compliance: + - hipaa + workload_profile: production diff --git a/packages/cli/cloudwright_cli/__init__.py b/packages/cli/cloudwright_cli/__init__.py index 5b60188..e4adfb8 100644 --- a/packages/cli/cloudwright_cli/__init__.py +++ b/packages/cli/cloudwright_cli/__init__.py @@ -1 +1 @@ -__version__ = "1.5.0" +__version__ = "1.6.0" diff --git a/packages/cli/cloudwright_cli/commands/compliance_cmd.py b/packages/cli/cloudwright_cli/commands/compliance_cmd.py index bfc2ff0..5b984c6 100644 --- a/packages/cli/cloudwright_cli/commands/compliance_cmd.py +++ b/packages/cli/cloudwright_cli/commands/compliance_cmd.py @@ -28,12 +28,24 @@ def compliance_scan( ] = None, fail_on: Annotated[str, typer.Option("--fail-on", help="Fail on: critical, high, medium, none")] = "high", output: Annotated[str | None, typer.Option("--output", "-o", help="Write a markdown control report")] = None, + oscal: Annotated[ + bool, + typer.Option("--oscal", "-O", help="Emit OSCAL 1.1.2 component-definition JSON alongside the scan"), + ] = False, + traceability: Annotated[ + bool, + typer.Option("--traceability", help="Show the control traceability chain: component -> resource -> control"), + ] = False, ) -> None: """Scan an ArchSpec and map every finding to framework control IDs. Maps design-stage findings to HIPAA / SOC 2 / PCI-DSS / FedRAMP / GDPR / ISO 27001 / NIST 800-53 controls before any infrastructure exists. Folds in a Checkov deep scan against the exported Terraform when Checkov is on PATH. + + Use --oscal / -O to also emit an OSCAL 1.1.2 component-definition document. + When --output is set the OSCAL JSON is written to .oscal.json; + otherwise it is printed to stdout after the standard report. """ try: from cloudwright import ArchSpec @@ -46,12 +58,34 @@ def compliance_scan( if output: Path(output).write_text(render_markdown(spec, report)) + if oscal: + import json as _json + + from cloudwright.oscal import to_oscal + + scanner = ComplianceScanner() + resolved_fws = scanner.resolve_frameworks(spec, fw_list or None) + oscal_doc = to_oscal(spec, report, resolved_fws) + oscal_text = _json.dumps(oscal_doc, indent=2) + if output: + oscal_path = str(output) + ".oscal.json" + Path(oscal_path).write_text(oscal_text) + if not is_json_mode(ctx): + console.print(f"OSCAL document written to {oscal_path}", style="dim") + else: + print(oscal_text) + if is_json_mode(ctx): if should_stream(ctx): for f in report.findings: emit_stream(f.as_dict()) else: - emit_success(ctx, report.as_dict()) + payload = report.as_dict() + if traceability: + from cloudwright.compliance import build_traceability + + payload["traceability"] = build_traceability(spec, report) + emit_success(ctx, payload) _maybe_exit(report, fail_on) return @@ -79,6 +113,21 @@ def compliance_scan( console.print(f" Remediation: {f.remediation}", style="dim") console.print() + if traceability and report.findings: + from cloudwright.compliance import build_traceability + + chain_table = Table("Component", "Resource", "Controls", "Status", title="Control Traceability") + for row in build_traceability(spec, report): + ctrls = ", ".join(f"{c['framework']} {c['control_id']}" for c in row["controls"]) or "-" + chain_table.add_row( + f"{row['label'] or row['component_id'] or '-'} ({row['service'] or '-'})", + row["resource_type"] or "-", + ctrls, + f"[red]{row['status']}[/red]", + ) + console.print(chain_table) + console.print() + crit = report.critical_count high = report.high_count console.print(f"{len(report.findings)} finding(s) ({crit} critical, {high} high)") diff --git a/packages/cli/cloudwright_cli/commands/cost.py b/packages/cli/cloudwright_cli/commands/cost.py index 6bb7999..e4432ef 100644 --- a/packages/cli/cloudwright_cli/commands/cost.py +++ b/packages/cli/cloudwright_cli/commands/cost.py @@ -1,5 +1,6 @@ from __future__ import annotations +import sys from pathlib import Path from typing import Annotated @@ -30,6 +31,18 @@ def cost( "Sets realistic defaults for request volumes, storage, node counts, and data transfer.", ), ] = None, + carbon: Annotated[ + bool, + typer.Option("--carbon", help="Include a CO2e carbon footprint estimate."), + ] = False, + focus: Annotated[ + bool, + typer.Option("--focus", help="Output cost data as FinOps FOCUS 1.0 CSV."), + ] = False, + output: Annotated[ + Path | None, + typer.Option("-o", "--output", help="Write FOCUS CSV to this file instead of stdout."), + ] = None, ) -> None: """Show cost breakdown for an architecture spec.""" if workload_profile: @@ -43,14 +56,32 @@ def cost( raise typer.Exit(1) spec = ArchSpec.from_file(spec_file) + tier = pricing_tier or "on_demand" # Compute cost estimate if not present if not spec.cost_estimate: engine = CostEngine() - spec.cost_estimate = engine.estimate(spec, workload_profile=workload_profile) + spec.cost_estimate = engine.estimate(spec, pricing_tier=tier, workload_profile=workload_profile) + + # --focus: emit FOCUS CSV and exit + if focus: + from cloudwright.focus import to_focus_csv + + csv_text = to_focus_csv(spec.cost_estimate, pricing_tier=tier) + if output: + output.write_text(csv_text, encoding="utf-8") + console.print(f"FOCUS CSV written to {output}") + else: + sys.stdout.write(csv_text) + return if is_json_mode(ctx): - emit_success(ctx, {"estimate": spec.cost_estimate.model_dump(exclude_none=True)}) + payload: dict = {"estimate": spec.cost_estimate.model_dump(exclude_none=True)} + if carbon: + from cloudwright.carbon import estimate_carbon + + payload["carbon"] = estimate_carbon(spec) + emit_success(ctx, payload) return if compare: @@ -59,31 +90,51 @@ def cost( else: _print_single_cost_table(spec) + if carbon: + from cloudwright.carbon import estimate_carbon + + _print_carbon_table(spec, estimate_carbon(spec)) + def _print_single_cost_table(spec: ArchSpec) -> None: if not spec.cost_estimate: console.print("[yellow]No cost estimate in spec. Run 'cloudwright design' to generate one.[/yellow]") return - table = Table(title=f"Cost Breakdown — {spec.name}", show_footer=True) + est = spec.cost_estimate + region_note = "" + if est.region_multiplier != 1.0: + region_note = f" (region multiplier: {est.region_multiplier:.2f}x vs us-east-1)" + + title = f"Cost Breakdown — {spec.name}{region_note}" + table = Table(title=title, show_footer=True) table.add_column("Component", style="cyan") table.add_column("Service") - table.add_column("Monthly", justify="right", footer=f"${spec.cost_estimate.monthly_total:,.2f}") + table.add_column("Monthly", justify="right", footer=f"${est.monthly_total:,.2f}") + table.add_column("Confidence", justify="center") table.add_column("Notes", style="dim") comp_map = {c.id: c for c in spec.components} - for item in spec.cost_estimate.breakdown: + 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" table.add_row( item.component_id, svc_label, f"${item.monthly:,.2f}", + f"[{conf_style}]{item.confidence}[/{conf_style}]", item.notes, ) console.print(table) + if est.pricing_confidence != "high": + console.print( + "[yellow]Pricing confidence: low[/yellow] — one or more services used formula/fallback " + "pricing, not real catalog data. Treat totals as rough estimates." + ) + def _print_multi_cloud_table(spec: ArchSpec, providers: list[str]) -> None: all_providers = [spec.provider] + [p for p in providers if p != spec.provider] @@ -129,3 +180,29 @@ def _print_multi_cloud_table(spec: ArchSpec, providers: list[str]) -> None: table.add_row("[bold]TOTAL[/bold]", *totals) console.print(table) + + +def _print_carbon_table(spec: ArchSpec, carbon: dict) -> None: + table = Table(title=f"Carbon Estimate — {spec.name} ({carbon['region']})") + table.add_column("Component", style="cyan") + table.add_column("Service") + table.add_column("Watts", justify="right") + table.add_column("kWh/mo", justify="right") + table.add_column("kgCO2e/mo", justify="right") + + for item in carbon["breakdown"]: + table.add_row( + item["component_id"], + item["service"], + f"{item['watts']:.1f}", + f"{item['kwh_per_month']:.2f}", + f"{item['kg_co2e_per_month']:.3f}", + ) + + console.print(table) + console.print( + f"[bold]Total:[/bold] {carbon['total_kg_co2e_per_month']:.3f} kgCO2e/month " + f"[dim](grid: {carbon['grid_intensity_g_per_kwh']} gCO2e/kWh, " + f"PUE: {carbon['assumptions']['pue']})[/dim]" + ) + console.print(f"[dim]{carbon['assumptions']['disclaimer']}[/dim]") diff --git a/packages/cli/cloudwright_cli/commands/drift_cmd.py b/packages/cli/cloudwright_cli/commands/drift_cmd.py index 21a26df..45ef6e1 100644 --- a/packages/cli/cloudwright_cli/commands/drift_cmd.py +++ b/packages/cli/cloudwright_cli/commands/drift_cmd.py @@ -3,7 +3,7 @@ from __future__ import annotations from pathlib import Path -from typing import Annotated +from typing import Annotated, Any import typer from rich.console import Console @@ -24,6 +24,17 @@ def drift( fmt: Annotated[ str, typer.Option("--format", "-f", help="Infrastructure format: auto, terraform, cloudformation") ] = "auto", + remediate: Annotated[ + bool, + typer.Option( + "--remediate", + help="Show cost/quality delta and terraform plan preview to close drift (read-only).", + ), + ] = False, + run_plan: Annotated[ + bool, + typer.Option("--run-plan", help="With --remediate: attempt a real terraform plan (needs credentials)."), + ] = False, ) -> None: """Compare design spec against deployed infrastructure to detect drift.""" try: @@ -39,6 +50,10 @@ def drift( with console.status("Detecting drift..."): report = detect_drift(spec_file, infra_file, infra_format=fmt) + if remediate: + _run_remediate(ctx, report, run_plan=run_plan) + return + if is_json_mode(ctx): result = { "drift_score": report.drift_score, @@ -94,3 +109,61 @@ def drift( raise except Exception as e: handle_error(ctx, e) + + +def _run_remediate(ctx: typer.Context, report: Any, *, run_plan: bool) -> None: + from cloudwright.remediation import remediate as compute_remediation + + with console.status("Computing remediation plan..."): + result = compute_remediation(report.deployed_spec, report.design_spec, run_plan=run_plan) + + if is_json_mode(ctx): + emit_success(ctx, {"remediation": result}) + return + + console.print(Rule("[bold]Cloudwright Remediation Preview[/bold]")) + console.print(Panel(result["summary"], title="Summary")) + + drift_items = result["drift"] + if drift_items: + table = Table(title=f"Changes to close drift ({len(drift_items)})") + table.add_column("Action", style="cyan") + table.add_column("Component") + table.add_column("Detail") + for item in drift_items: + action = item["change"] + cid = item.get("id", "") + detail = "" + if action == "modify": + detail = f"{item.get('field')}: {item.get('from')} -> {item.get('to')}" + elif action == "add": + detail = item.get("service", "") + elif action == "remove": + detail = item.get("service", "") + color = {"add": "green", "remove": "red", "modify": "yellow"}.get(action, "white") + table.add_row(f"[{color}]{action}[/{color}]", cid, detail) + console.print() + console.print(table) + else: + console.print("[green]No drift changes required.[/green]") + + cd = result["cost_delta"] + sign = "+" if cd["delta"] >= 0 else "" + console.print( + f"\n[bold]Cost delta:[/bold] {sign}${cd['delta']:,.2f}/mo (${cd['current']:,.2f} -> ${cd['desired']:,.2f})" + ) + + qd = result["quality_delta"] + q_sign = "+" if qd["delta"] >= 0 else "" + q_color = "green" if qd["delta"] >= 0 else "red" + console.print( + f"[bold]Quality delta:[/bold] [{q_color}]{q_sign}{qd['delta']:.1f} pts[/{q_color}] " + f"(grade {qd['current_grade']} -> {qd['desired_grade']})" + ) + + plan = result["plan"] + plan_color = "green" if plan.get("ok") else "red" + plan_label = "valid" if plan.get("validated") else "not validated" + console.print(f"[bold]Plan ([/bold]{plan['tool']}[bold]):[/bold] [{plan_color}]{plan_label}[/{plan_color}]") + for msg in plan.get("messages", []): + console.print(f" [dim]{msg}[/dim]") diff --git a/packages/cli/cloudwright_cli/commands/review_cmd.py b/packages/cli/cloudwright_cli/commands/review_cmd.py new file mode 100644 index 0000000..83060b4 --- /dev/null +++ b/packages/cli/cloudwright_cli/commands/review_cmd.py @@ -0,0 +1,78 @@ +"""Review an architecture with the deterministic critics (offline).""" + +from __future__ import annotations + +from typing import Annotated + +import typer +from rich.console import Console +from rich.panel import Panel +from rich.table import Table + +from cloudwright_cli.output import emit_success, is_json_mode +from cloudwright_cli.utils import handle_error + +console = Console() + +_SEV_COLOR = {"critical": "red", "high": "red", "medium": "yellow", "low": "cyan"} + + +def review( + ctx: typer.Context, + spec_file: Annotated[str, typer.Argument(help="Path to ArchSpec YAML/JSON file")], + compliance: Annotated[str, typer.Option("--compliance", help="Comma-separated frameworks, e.g. hipaa,soc2")] = "", + well_architected: Annotated[ + bool, typer.Option("--well-architected", help="Include Well-Architected checks") + ] = False, +) -> None: + """Review an architecture: unified scorer + linter + validator findings (no LLM, free).""" + try: + from cloudwright import ArchSpec + from cloudwright.critique import critique + + spec = ArchSpec.from_file(spec_file) + frameworks = [f.strip() for f in compliance.split(",") if f.strip()] or None + report = critique(spec, compliance=frameworks, well_architected=well_architected) + + if is_json_mode(ctx): + emit_success(ctx, {"review": report.as_dict()}) + return + + border = "green" if not report.blocking else "red" + console.print( + Panel( + f"[bold]{report.summary_line()}[/bold]", + title=f"Architecture Review: {spec.name}", + border_style=border, + ) + ) + + if not report.findings: + console.print("[green]No findings. This architecture passes every critic.[/green]") + return + + table = Table(title="Findings (severity-ranked)") + table.add_column("Severity") + table.add_column("Source", style="dim") + table.add_column("Finding") + table.add_column("Fix") + for f in report.findings: + color = _SEV_COLOR.get(f.severity, "white") + table.add_row( + f"[{color}]{f.severity}[/{color}]", + f.source, + f.message, + (f.recommendation or "")[:80], + ) + console.print(table) + + if report.blocking: + console.print( + f"\n[red]{len(report.blocking)} blocking finding(s).[/red] " + "Run `cloudwright design` (repair is on by default) or fix these before deploy." + ) + + except typer.Exit: + raise + except Exception as e: + handle_error(ctx, e) diff --git a/packages/cli/cloudwright_cli/main.py b/packages/cli/cloudwright_cli/main.py index af5dc8a..4f5984f 100644 --- a/packages/cli/cloudwright_cli/main.py +++ b/packages/cli/cloudwright_cli/main.py @@ -22,6 +22,7 @@ from cloudwright_cli.commands.plan_cmd import plan from cloudwright_cli.commands.policy import policy from cloudwright_cli.commands.refresh_cmd import refresh +from cloudwright_cli.commands.review_cmd import review from cloudwright_cli.commands.schema_cmd import schema from cloudwright_cli.commands.score_cmd import score from cloudwright_cli.commands.security_cmd import security_scan @@ -77,6 +78,7 @@ def main( app.command()(plan) app.command()(policy) app.command()(score) +app.command()(review) app.command()(analyze) app.command()(refresh) app.command()(lint) diff --git a/packages/core/cloudwright/__init__.py b/packages/core/cloudwright/__init__.py index b7bb70e..6d25d0d 100644 --- a/packages/core/cloudwright/__init__.py +++ b/packages/core/cloudwright/__init__.py @@ -17,7 +17,7 @@ ValidationResult, ) -__version__ = "1.5.0" +__version__ = "1.6.0" __all__ = [ "Alternative", diff --git a/packages/core/cloudwright/architect.py b/packages/core/cloudwright/architect.py index 0f7cfcb..1c162d8 100644 --- a/packages/core/cloudwright/architect.py +++ b/packages/core/cloudwright/architect.py @@ -2,6 +2,12 @@ from __future__ import annotations +from cloudwright.critique import ( # noqa: F401 + CritiqueFinding, + CritiqueReport, + critique, +) + # Re-export everything for backward compatibility from cloudwright.designer import ( # noqa: F401 Architect, diff --git a/packages/core/cloudwright/carbon.py b/packages/core/cloudwright/carbon.py new file mode 100644 index 0000000..02400f3 --- /dev/null +++ b/packages/core/cloudwright/carbon.py @@ -0,0 +1,267 @@ +"""Carbon footprint estimator for ArchSpec components. + +All numbers are estimates based on publicly available data. Sources: +- Grid carbon intensity: IEA Electricity Map averages (2023), gCO2eq/kWh +- Power draw per component tier: AWS/GCP sustainability reports + ACEEE estimates +- PUE (power usage effectiveness): 1.12 (hyperscale cloud avg, Google/AWS 2023 reports) + +Usage: + from cloudwright.carbon import estimate_carbon + result = estimate_carbon(spec) + # result["total_kg_co2e_per_month"] — total across all components + # result["breakdown"] — per-component list + # result["assumptions"] — named constants used +""" + +from __future__ import annotations + +from cloudwright.spec import ArchSpec + +# --------------------------------------------------------------------------- +# Grid carbon intensity by region (gCO2eq/kWh). +# Source: IEA Electricity Map regional averages, 2023. +# Matched by prefix; unknown regions fall back to a global average. +# --------------------------------------------------------------------------- +_GRID_INTENSITY: dict[str, float] = { + # AWS regions + "us-east-1": 380.0, # Virginia — Mid-Atlantic grid + "us-east-2": 480.0, # Ohio — higher coal mix + "us-west-1": 210.0, # N. California — hydro/wind heavy + "us-west-2": 130.0, # Oregon — ~70% renewable (hydro) + "ca-central-1": 30.0, # Canada — largely hydro + "eu-west-1": 290.0, # Ireland — wind + gas + "eu-west-2": 230.0, # London — offshore wind + "eu-west-3": 55.0, # Paris — nuclear dominant + "eu-central-1": 350.0, # Frankfurt — coal/gas mix + "eu-north-1": 8.0, # Stockholm — almost entirely hydro/nuclear + "ap-southeast-1": 430.0, # Singapore — gas + "ap-southeast-2": 680.0, # Sydney — coal heavy + "ap-northeast-1": 465.0, # Tokyo — post-Fukushima gas/coal + "ap-northeast-2": 415.0, # Seoul + "ap-south-1": 720.0, # Mumbai — coal dominant + "sa-east-1": 75.0, # Sao Paulo — hydro + "me-south-1": 600.0, # Bahrain — gas + "af-south-1": 840.0, # Cape Town — coal dominant + # GCP regions + "us-central1": 490.0, # Iowa + "us-east1": 380.0, + "us-west1": 130.0, + "europe-west1": 130.0, # Belgium — nuclear + "europe-west2": 230.0, + "europe-west3": 350.0, + "europe-west4": 330.0, # Netherlands + "asia-southeast1": 430.0, + "asia-northeast1": 465.0, + "asia-south1": 720.0, + "southamerica-east1": 75.0, + # Azure regions + "eastus": 380.0, + "eastus2": 380.0, + "westus": 210.0, + "westus2": 130.0, + "centralus": 490.0, + "northcentralus": 490.0, + "southcentralus": 420.0, + "canadacentral": 30.0, + "westeurope": 330.0, # Netherlands + "northeurope": 290.0, # Ireland + "uksouth": 230.0, + "ukwest": 230.0, + "germanywestcentral": 350.0, + "francecentral": 55.0, + "southeastasia": 430.0, + "eastasia": 590.0, # Hong Kong + "japaneast": 465.0, + "koreacentral": 415.0, + "centralindia": 720.0, + "brazilsouth": 75.0, + "southafricanorth": 840.0, + "uaenorth": 600.0, +} + +# Prefix fallbacks for regions not in the exact table +_GRID_INTENSITY_PREFIXES: list[tuple[str, float]] = [ + ("us-east", 380.0), + ("us-west", 170.0), + ("us-", 400.0), + ("eu-", 200.0), + ("europe-", 200.0), + ("ap-", 500.0), + ("asia-", 500.0), + ("sa-", 150.0), + ("southamerica-", 150.0), + ("me-", 600.0), + ("af-", 800.0), + ("ca-", 50.0), + ("eastus", 380.0), + ("westus", 170.0), + ("westeurope", 330.0), + ("northeurope", 290.0), + ("southeastasia", 430.0), + ("japaneast", 465.0), + ("brazilsouth", 75.0), + ("southafricanorth", 840.0), +] + +# Global average fallback (IEA 2023 global electricity mix) +_GLOBAL_AVG_INTENSITY = 436.0 # gCO2eq/kWh + +# Cloud PUE — hyperscale average across AWS, GCP, Azure (2023 sustainability reports) +_CLOUD_PUE = 1.12 + +# --------------------------------------------------------------------------- +# Power draw (Watts) per component tier. +# Rough mid-point from ACEEE cloud lifecycle assessments and AWS sustainability +# whitepapers. "tier" here maps to the spec's component tier field. +# --------------------------------------------------------------------------- +_TIER_WATTS: dict[int, float] = { + 0: 5.0, # edge / CDN node — low always-on overhead + 1: 15.0, # load balancer / API gateway — modest + 2: 80.0, # compute (single vCPU-scale instance) + 3: 120.0, # database / cache (memory-intensive, SSD I/O) + 4: 40.0, # storage / data — storage servers, lower compute + 5: 200.0, # analytics / ML (GPU/high-mem workloads) +} +_DEFAULT_TIER_WATTS = 60.0 # fallback for unknown tiers + +# Service-level power overrides that supersede tier-based defaults +_SERVICE_WATTS: dict[str, float] = { + # Serverless — billed per invocation, very low idle + "lambda": 5.0, + "cloud_functions": 5.0, + "azure_functions": 5.0, + # Containers / orchestration + "eks": 300.0, + "gke": 300.0, + "aks": 300.0, + "ecs": 150.0, + "fargate": 80.0, + "cloud_run": 20.0, + "container_apps": 20.0, + # Managed databases + "rds": 100.0, + "aurora": 120.0, + "cloud_sql": 100.0, + "azure_sql": 100.0, + "dynamodb": 40.0, + "cosmos_db": 40.0, + "firestore": 20.0, + # Analytics / ML + "redshift": 400.0, + "bigquery": 200.0, + "synapse": 400.0, + "sagemaker": 250.0, + "vertex_ai": 250.0, + "azure_ml": 250.0, + # Databricks + "databricks_cluster": 500.0, + "databricks_sql_warehouse": 300.0, + "databricks_job": 200.0, + "databricks_pipeline": 200.0, + "databricks_model_serving": 100.0, + # Virtual / meta (no real hardware attributed) + "users": 0.0, + "internet": 0.0, + "external": 0.0, + "client": 0.0, + "browser": 0.0, + "mobile": 0.0, + "vpc": 0.0, + "vnet": 0.0, + "iam": 0.0, +} + +# Hours per month +_HOURS_PER_MONTH = 730.0 + + +def _grid_intensity(region: str) -> float: + """Return gCO2eq/kWh for a region. Falls back to global average.""" + r = (region or "").lower().strip() + if r in _GRID_INTENSITY: + return _GRID_INTENSITY[r] + for prefix, intensity in _GRID_INTENSITY_PREFIXES: + if r.startswith(prefix): + return intensity + return _GLOBAL_AVG_INTENSITY + + +def _component_watts(service: str, tier: int, config: dict) -> float: + """Estimate power draw in Watts for a single component.""" + base = _SERVICE_WATTS.get(service, _TIER_WATTS.get(tier, _DEFAULT_TIER_WATTS)) + # Scale with node/instance count when explicit + count = config.get("count", config.get("node_count", config.get("num_nodes", 1))) + try: + count = int(count) + except (TypeError, ValueError): + count = 1 + return base * max(count, 1) + + +def estimate_carbon(spec: ArchSpec) -> dict: + """Return per-component and total CO2e estimates for an ArchSpec. + + All figures are estimates. Assumptions: + - Power draw per component: see _SERVICE_WATTS / _TIER_WATTS tables + - Grid carbon intensity: IEA regional averages 2023 (gCO2eq/kWh) + - Cloud PUE: 1.12 (hyperscale average, AWS/GCP/Azure 2023 sustainability reports) + - 730 hours/month assumed for always-on components + + Returns a dict with: + total_kg_co2e_per_month: float + region: str + grid_intensity_g_per_kwh: float + breakdown: list[dict] — one entry per component + assumptions: dict — named constants used in this calculation + """ + region = spec.region or "us-east-1" + intensity = _grid_intensity(region) + breakdown = [] + total_kg = 0.0 + + for comp in spec.components: + config = comp.config or {} + watts = _component_watts(comp.service, comp.tier, config) + if watts <= 0: + breakdown.append( + { + "component_id": comp.id, + "service": comp.service, + "watts": 0.0, + "kwh_per_month": 0.0, + "kg_co2e_per_month": 0.0, + "note": "virtual/meta component — no hardware attributed", + } + ) + continue + + kwh = (watts * _HOURS_PER_MONTH * _CLOUD_PUE) / 1000.0 + kg_co2e = (kwh * intensity) / 1000.0 # gCO2e -> kgCO2e + total_kg += kg_co2e + + breakdown.append( + { + "component_id": comp.id, + "service": comp.service, + "watts": round(watts, 1), + "kwh_per_month": round(kwh, 2), + "kg_co2e_per_month": round(kg_co2e, 3), + } + ) + + return { + "total_kg_co2e_per_month": round(total_kg, 3), + "region": region, + "grid_intensity_g_per_kwh": intensity, + "breakdown": breakdown, + "assumptions": { + "pue": _CLOUD_PUE, + "hours_per_month": _HOURS_PER_MONTH, + "grid_intensity_source": "IEA Electricity Map regional averages 2023", + "power_draw_source": "ACEEE cloud lifecycle assessments + AWS/GCP sustainability reports", + "disclaimer": ( + "These are rough estimates. Actual emissions depend on server utilisation, " + "renewable energy certificates, and provider-specific PPA mix." + ), + }, + } diff --git a/packages/core/cloudwright/catalog/formula.py b/packages/core/cloudwright/catalog/formula.py index 32cbcf1..8511bcd 100644 --- a/packages/core/cloudwright/catalog/formula.py +++ b/packages/core/cloudwright/catalog/formula.py @@ -272,7 +272,11 @@ def default_managed_price(service: str, config: dict) -> float: """Fallback pricing when catalog doesn't have specific data.""" base = _FALLBACK_PRICES.get(service, 10.0) if service not in _FALLBACK_PRICES: - log.debug("No fallback price for service '%s', using default $10.00", service) + # $10 placeholder is fabricated — warn so callers can mark confidence=low + log.warning( + "No pricing data for service '%s' — using $10.00 placeholder. This number is not from a real price list.", + service, + ) else: log.debug("Using fallback price for '%s': $%.2f", service, base) # Multiplier from various count-like config keys diff --git a/packages/core/cloudwright/compliance.py b/packages/core/cloudwright/compliance.py index 20cdf43..fac9755 100644 --- a/packages/core/cloudwright/compliance.py +++ b/packages/core/cloudwright/compliance.py @@ -135,6 +135,44 @@ def as_dict(self) -> dict[str, Any]: } +def _resource_type_map() -> dict[str, str]: + """service -> Terraform resource type, merged across provider renderers.""" + res: dict[str, str] = {} + from cloudwright.exporter.terraform import aws, azure, databricks, gcp + + for mod in (aws, gcp, azure, databricks): + res.update(getattr(mod, "RESOURCES", {}) or {}) + return res + + +def build_traceability(spec: "ArchSpec", report: "ComplianceReport") -> list[dict[str, Any]]: + """Control traceability chain: design intent -> component -> IaC resource -> control -> status. + + Auditors (and OSCAL/EU AI Act technical documentation) need to follow a control + from the requirement down to the exact resource that does or does not satisfy it. + Each entry links a finding's component to the Terraform resource it renders to and + the framework control IDs it touches. + """ + comps = {c.id: c for c in spec.components} + res_map = _resource_type_map() + chains: list[dict[str, Any]] = [] + for f in report.findings: + comp = comps.get(f.component_id) if f.component_id else None + chains.append( + { + "component_id": f.component_id, + "service": comp.service if comp else None, + "label": comp.label if comp else None, + "resource_type": res_map.get(comp.service) if comp else None, + "rule": f.rule, + "severity": f.severity, + "controls": [c.as_dict() for c in f.controls], + "status": "violated", + } + ) + return chains + + class ControlCatalog: """Loads and resolves the rule/Checkov -> framework-control mapping.""" diff --git a/packages/core/cloudwright/cost.py b/packages/core/cloudwright/cost.py index 8060d62..1b9bb6d 100644 --- a/packages/core/cloudwright/cost.py +++ b/packages/core/cloudwright/cost.py @@ -41,6 +41,106 @@ } _DEFAULT_EGRESS_RATE = 0.09 +# --------------------------------------------------------------------------- +# Regional price multipliers relative to us-east-1 = 1.00 baseline. +# Source: public AWS/GCP/Azure pricing pages as of 2025. +# Matched by prefix so "eu-west-2" hits "eu-west" if not listed explicitly. +# --------------------------------------------------------------------------- +_REGION_MULTIPLIERS: dict[str, float] = { + # AWS + "us-east-1": 1.00, + "us-east-2": 1.00, + "us-west-1": 1.10, + "us-west-2": 1.02, + "ca-central-1": 1.05, + "eu-west-1": 1.08, + "eu-west-2": 1.10, + "eu-west-3": 1.12, + "eu-central-1": 1.10, + "eu-north-1": 1.05, + "ap-southeast-1": 1.15, + "ap-southeast-2": 1.16, + "ap-northeast-1": 1.18, + "ap-northeast-2": 1.13, + "ap-south-1": 1.10, + "sa-east-1": 1.25, + "me-south-1": 1.20, + "af-south-1": 1.20, + # GCP (region codes) + "us-central1": 1.00, + "us-east1": 1.00, + "us-west1": 1.02, + "europe-west1": 1.08, + "europe-west2": 1.10, + "europe-west3": 1.12, + "europe-west4": 1.08, + "asia-southeast1": 1.15, + "asia-northeast1": 1.18, + "asia-south1": 1.10, + "southamerica-east1": 1.25, + # Azure (region codes) + "eastus": 1.00, + "eastus2": 1.00, + "westus": 1.02, + "westus2": 1.02, + "westus3": 1.05, + "centralus": 1.00, + "northcentralus": 1.00, + "southcentralus": 1.00, + "canadacentral": 1.05, + "westeurope": 1.08, + "northeurope": 1.08, + "uksouth": 1.10, + "ukwest": 1.10, + "germanywestcentral": 1.12, + "francecentral": 1.12, + "southeastasia": 1.15, + "eastasia": 1.15, + "japaneast": 1.18, + "koreacentral": 1.13, + "centralindia": 1.10, + "brazilsouth": 1.25, + "southafricanorth": 1.20, + "uaenorth": 1.20, +} + +# Prefix-based fallbacks when an exact region code isn't in the table above +_REGION_PREFIX_MULTIPLIERS: list[tuple[str, float]] = [ + ("us-east", 1.00), + ("us-west", 1.05), + ("us-", 1.02), + ("eu-", 1.10), + ("europe-", 1.10), + ("ap-", 1.15), + ("asia-", 1.15), + ("sa-", 1.25), + ("southamerica-", 1.25), + ("me-", 1.20), + ("af-", 1.20), + ("ca-", 1.05), + ("eastus", 1.00), + ("westus", 1.02), + ("westeurope", 1.08), + ("northeurope", 1.08), + ("southeastasia", 1.15), + ("japaneast", 1.18), + ("brazilsouth", 1.25), +] + + +def _region_multiplier(region: str) -> float: + """Return a price multiplier for the given region, relative to us-east-1 = 1.00.""" + if not region: + return 1.00 + r = region.lower().strip() + if r in _REGION_MULTIPLIERS: + return _REGION_MULTIPLIERS[r] + for prefix, mult in _REGION_PREFIX_MULTIPLIERS: + if r.startswith(prefix): + return mult + return 1.00 # unknown region — assume baseline + + # --------------------------------------------------------------------------- # Workload profiles — realistic sizing defaults per environment tier # --------------------------------------------------------------------------- @@ -231,10 +331,14 @@ def estimate( node counts, and data transfer that match production workloads. """ breakdown: list[ComponentCost] = [] + region = spec.region or "us-east-1" + rmult = _region_multiplier(region) for comp in spec.components: effective = _apply_profile(comp, workload_profile) if workload_profile else comp - monthly = self._price_component(effective, spec.provider, spec.region, pricing_tier) + monthly, confidence, is_estimated = self._price_component_with_meta( + effective, spec.provider, region, pricing_tier, rmult + ) hourly = round(monthly / 730, 4) if monthly > 0 else None notes = self._cost_notes(effective) breakdown.append( @@ -244,6 +348,8 @@ def estimate( monthly=monthly, hourly=hourly, notes=notes, + confidence=confidence, + estimated=is_estimated, ) ) @@ -251,12 +357,19 @@ 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 + 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" + return CostEstimate( monthly_total=total, breakdown=breakdown, data_transfer_monthly=data_transfer, currency="USD", as_of=date.today().isoformat(), + pricing_confidence=pricing_confidence, + region=region, + region_multiplier=rmult, ) def price( @@ -366,16 +479,42 @@ def _map_instance_config(self, config: dict, from_provider: str, to_provider: st def _price_component( self, comp: Component, default_provider: str, region: str, pricing_tier: str = "on_demand" ) -> float: - """Get monthly cost for a single component using 3-tier resolution + multipliers.""" + """Get monthly cost for a single component. Kept for backward compatibility.""" + monthly, _conf, _est = self._price_component_with_meta( + comp, default_provider, region, pricing_tier, _region_multiplier(region) + ) + return monthly + + def _price_component_with_meta( + self, + comp: Component, + default_provider: str, + region: str, + pricing_tier: str = "on_demand", + region_mult: float = 1.0, + ) -> 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. + 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. + """ provider = comp.provider or default_provider config = comp.config or {} base: float | None = None from_catalog = False + 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) 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 base is None: # Tier 2: registry formula dispatch @@ -387,14 +526,16 @@ def _price_component( merged_config.update(config) result = formula_fn(merged_config) if result is not None and result > 0: - multiplier = _PRICING_MULTIPLIERS.get(pricing_tier, 1.0) - base = result * multiplier + tier_mult = _PRICING_MULTIPLIERS.get(pricing_tier, 1.0) + base = result * tier_mult * region_mult + is_estimated = True if base is None: - # Tier 3: static fallback table + # Tier 3: static fallback — mark as low-confidence estimated base = default_managed_price(comp.service, config) - multiplier = _PRICING_MULTIPLIERS.get(pricing_tier, 1.0) - base = base * multiplier + tier_mult = _PRICING_MULTIPLIERS.get(pricing_tier, 1.0) + base = base * tier_mult * region_mult + is_estimated = True # Post-resolution multipliers (only for non-catalog tiers — catalog handles these internally) if not from_catalog and config.get("multi_az"): @@ -407,7 +548,7 @@ def _price_component( if not has_explicit_count: base *= 3 - return round(base, 2) + return round(base, 2), confidence, is_estimated def _estimate_data_transfer(self, spec: ArchSpec, workload_profile: str | None = None) -> float: """Estimate monthly data transfer (egress) costs from connections.""" diff --git a/packages/core/cloudwright/critique.py b/packages/core/cloudwright/critique.py new file mode 100644 index 0000000..f20106b --- /dev/null +++ b/packages/core/cloudwright/critique.py @@ -0,0 +1,125 @@ +"""Unified architecture critique — the deterministic critic layer. + +Aggregates the three critics that already exist in the tree (scorer, linter, +validator) into a single severity-ranked report. This runs entirely offline (no +LLM) and is the engine behind two things: + +- ``cloudwright review`` — a standalone, free, deterministic architecture review. +- The generate -> critique -> repair loop in :meth:`Architect.design`, where the + blocking findings are fed back to the model so it self-corrects before the spec + is ever returned. The critics were always here; v1.6 wires them into generation. +""" + +from __future__ import annotations + +from dataclasses import asdict, dataclass, field +from typing import TYPE_CHECKING, Any + +from cloudwright.linter import lint +from cloudwright.scorer import Scorer +from cloudwright.validator import Validator + +if TYPE_CHECKING: + from cloudwright.spec import ArchSpec + +_SEVERITY_ORDER = {"critical": 0, "high": 1, "medium": 2, "low": 3, "info": 4} +_LINT_SEVERITY = {"error": "high", "warning": "medium", "info": "low"} +_BLOCKING = ("critical", "high") + + +def _norm_severity(value: str) -> str: + v = (value or "").strip().lower() + return v if v in _SEVERITY_ORDER else "medium" + + +@dataclass +class CritiqueFinding: + severity: str # critical | high | medium | low + source: str # scorer | linter | validator + code: str + message: str + recommendation: str = "" + component: str | None = None + + def as_dict(self) -> dict[str, Any]: + return asdict(self) + + +@dataclass +class CritiqueReport: + score: float + grade: str + findings: list[CritiqueFinding] = field(default_factory=list) + + @property + def blocking(self) -> list[CritiqueFinding]: + return [f for f in self.findings if f.severity in _BLOCKING] + + def summary_line(self) -> str: + b = len(self.blocking) + return f"score {self.score:.0f}/100 (grade {self.grade}), {len(self.findings)} findings, {b} blocking" + + def as_dict(self) -> dict[str, Any]: + return { + "score": round(self.score, 1), + "grade": self.grade, + "findings": [f.as_dict() for f in self.findings], + "blocking_count": len(self.blocking), + "summary": self.summary_line(), + } + + +def critique( + spec: "ArchSpec", + *, + compliance: list[str] | None = None, + well_architected: bool = False, +) -> CritiqueReport: + """Run scorer + linter + validator and merge into one severity-ranked report.""" + result = Scorer().score(spec) + findings: list[CritiqueFinding] = [] + + for w in lint(spec): + findings.append( + CritiqueFinding( + severity=_LINT_SEVERITY.get(w.severity, "medium"), + source="linter", + code=w.rule, + message=w.message, + recommendation=w.recommendation, + component=w.component, + ) + ) + + frameworks = compliance + if frameworks is None and spec.constraints: + frameworks = spec.constraints.compliance + for vr in Validator().validate(spec, compliance=frameworks or [], well_architected=well_architected): + for ch in vr.checks: + if not ch.passed: + findings.append( + CritiqueFinding( + severity=_norm_severity(ch.severity), + source="validator", + code=f"{vr.framework}:{ch.name}", + message=ch.detail or ch.name, + recommendation=ch.recommendation, + ) + ) + + for d in result.dimensions: + if d.score < 60: + sev = "medium" if d.score < 40 else "low" + for rec in d.recommendations[:2]: + findings.append( + CritiqueFinding( + severity=sev, + source="scorer", + code=f"score:{d.name.lower().replace(' ', '_')}", + message=f"{d.name} score {d.score:.0f}/100", + recommendation=rec, + ) + ) + + findings.sort(key=lambda f: _SEVERITY_ORDER.get(f.severity, 5)) + return CritiqueReport(score=result.overall, grade=result.grade, findings=findings) diff --git a/packages/core/cloudwright/designer.py b/packages/core/cloudwright/designer.py index 42fe89b..ec732aa 100644 --- a/packages/core/cloudwright/designer.py +++ b/packages/core/cloudwright/designer.py @@ -28,9 +28,25 @@ _STOPWORDS = {"a", "an", "the", "on", "in", "for", "with", "and", "or", "to", "my", "our", "that", "this", "using"} +_REPAIR_SYSTEM = ( + "You are revising an existing cloud architecture spec to fix specific issues. " + "You receive the current ArchSpec JSON and a list of blocking findings from an " + "automated review. Return ONLY a corrected ArchSpec JSON object that resolves " + "those findings while preserving the user's intent and existing component ids " + "where possible. Add missing safety components (monitoring, WAF, backups, auth, " + "load balancing) when a finding calls for one. Output only the JSON object, " + "starting with {." +) + class Architect: - def __init__(self, llm: BaseLLM | None = None, two_stage: bool = True): + def __init__( + self, + llm: BaseLLM | None = None, + two_stage: bool = True, + repair: bool = True, + max_repair_iters: int = 1, + ): self.llm = llm or get_llm() # Side-channel for the most recent usage dict produced by design()/modify(). # The web routers read this to surface model/tokens/cost in API responses @@ -42,6 +58,12 @@ def __init__(self, llm: BaseLLM | None = None, two_stage: bool = True): # single-shot JSON-schema constraints. Flip to False to use the legacy # single-shot path (kept around for benchmarking and emergency fallback). self.two_stage = two_stage + # v1.6 generate -> critique -> repair: after a spec is produced, the + # deterministic critics (scorer/linter/validator) review it and, when + # blocking (high/critical) findings remain, the model is asked once to + # fix them. Bounded by max_repair_iters; fails safe to the original spec. + self.repair = repair + self.max_repair_iters = max_repair_iters def design(self, description: str, constraints: Constraints | None = None) -> ArchSpec: self.last_usage = {} @@ -73,8 +95,71 @@ def design(self, description: str, constraints: Constraints | None = None) -> Ar if template_result is not None: _, confidence = template_result spec = spec.model_copy(update={"metadata": {**spec.metadata, "template_confidence": confidence}}) + if self.repair: + spec = self._critique_repair(spec, description, constraints) return spec + def _critique_repair(self, spec: ArchSpec, description: str, constraints: Constraints | None) -> ArchSpec: + """Run the deterministic critics and, on blocking findings, repair once.""" + from cloudwright.critique import critique + + try: + report = critique(spec) + except Exception as exc: # critics must never break design() + log.debug("critique skipped: %s", exc) + return spec + + meta = { + "score": round(report.score, 1), + "grade": report.grade, + "findings_before": len(report.findings), + "blocking_before": len(report.blocking), + "repair_iterations": 0, + } + iters = 0 + while report.blocking and iters < self.max_repair_iters: + repaired = self._repair_once(spec, description, constraints, report) + iters += 1 + if repaired is None: + break + try: + new_report = critique(repaired) + except Exception: + break + if len(new_report.blocking) <= len(report.blocking): + spec, report = repaired, new_report + else: + break # repair regressed the spec — keep the prior one + meta["repair_iterations"] = iters + meta["findings_after"] = len(report.findings) + meta["blocking_after"] = len(report.blocking) + return spec.model_copy(update={"metadata": {**spec.metadata, "critique": meta}}) + + def _repair_once( + self, spec: ArchSpec, description: str, constraints: Constraints | None, report + ) -> ArchSpec | None: + """One LLM repair pass: feed the blocking findings back and re-parse.""" + findings_text = "\n".join( + f"- [{f.severity}] {f.message}" + (f" — fix: {f.recommendation}" if f.recommendation else "") + for f in report.blocking[:12] + ) + user = ( + f"Original request:\n{description}\n\n" + f"Current ArchSpec JSON:\n{spec.to_json()}\n\n" + f"Blocking findings to resolve:\n{findings_text}\n\n" + "Return the corrected ArchSpec JSON now." + ) + try: + start = time.perf_counter() + text, usage = self.llm.generate_fast([{"role": "user", "content": user}], _REPAIR_SYSTEM, max_tokens=10000) + data = _extract_json(text) + repaired = _parse_arch_spec(data, constraints) + except Exception as exc: # a failed repair is non-fatal + log.warning("repair pass failed: %s", exc) + return None + self.last_usage = {**self.last_usage, "repair_usage": self._enrich_usage(usage, start)} + return repaired + def _design_two_stage(self, description: str, constraints: Constraints | None) -> ArchSpec: """Two-stage: free-text reasoning -> strict JSON projection.""" # Stage 1: free-text architectural reasoning (Sonnet, no JSON schema). diff --git a/packages/core/cloudwright/exporter/__init__.py b/packages/core/cloudwright/exporter/__init__.py index e6c9ce2..8485e73 100644 --- a/packages/core/cloudwright/exporter/__init__.py +++ b/packages/core/cloudwright/exporter/__init__.py @@ -12,6 +12,7 @@ FORMATS = ( "terraform", + "opentofu", "pulumi-ts", "pulumi-python", "cloudformation", @@ -52,7 +53,13 @@ def _get_all_formats() -> dict[str, object]: return formats -_DANGEROUS_PATTERNS = re.compile(r"[;|&`]|\$\(|\$\{|%\{") +# Reject shell metacharacters AND HCL-structural characters. Numeric exporter +# fields are interpolated without quotes, and string fields without _hcl_quote +# would be too — so a value containing a newline or a brace could close the +# current block and inject a new resource / provisioner. Config values for IaC +# are simple scalars (instance types, engines, counts), so none of these +# characters appear legitimately. +_DANGEROUS_PATTERNS = re.compile(r"[;|&`{}\n\r]|\$\(|\$\{|%\{") def validate_export_config(config: dict, path: str = "") -> None: @@ -94,7 +101,8 @@ def export_spec(spec: ArchSpec, fmt: str, output: str | None = None, output_dir: for comp in spec.components: validate_export_config(comp.config, path=f"component[{comp.id}].config") - if fmt == "terraform": + if fmt in ("terraform", "opentofu", "tofu"): + # OpenTofu consumes the same generated HCL; the alias just signals intent. from cloudwright.exporter.terraform import render content = render(spec) diff --git a/packages/core/cloudwright/exporter/terraform/aws.py b/packages/core/cloudwright/exporter/terraform/aws.py index 7d08b8a..b86546b 100644 --- a/packages/core/cloudwright/exporter/terraform/aws.py +++ b/packages/core/cloudwright/exporter/terraform/aws.py @@ -19,7 +19,7 @@ from typing import TYPE_CHECKING -from cloudwright.exporter.terraform.common import _hcl_quote +from cloudwright.exporter.terraform.common import _hcl_num, _hcl_quote if TYPE_CHECKING: from cloudwright.spec import ArchSpec, Component @@ -88,7 +88,7 @@ def render_resource(c: "Component", spec: "ArchSpec") -> str: f" identifier = {_hcl_quote(c.id)}", f" engine = {_hcl_quote(engine)}", f" instance_class = {_hcl_quote(instance_class)}", - f" allocated_storage = {cfg.get('allocated_storage', 20)}", + f" allocated_storage = {_hcl_num(cfg.get('allocated_storage', 20), 20)}", " username = var.db_username", " password = var.db_password", # Safe-by-default hardening for FedRAMP / HIPAA / PCI baselines. @@ -217,7 +217,7 @@ def render_resource(c: "Component", spec: "ArchSpec") -> str: f" cluster_id = {_hcl_quote(_bucket_name(c))}", f" engine = {_hcl_quote(engine)}", f" node_type = {_hcl_quote(node_type)}", - f" num_cache_nodes = {cfg.get('num_cache_nodes', 1)}", + f" num_cache_nodes = {_hcl_num(cfg.get('num_cache_nodes', 1), 1)}", f" parameter_group_name = {_hcl_quote(f'default.{engine}7')}", " tags = {", f" Name = {_hcl_quote(c.label)}", @@ -276,7 +276,11 @@ def render_resource(c: "Component", spec: "ArchSpec") -> str: f'resource "aws_wafv2_web_acl" "{c.id}" {{', f" name = {_hcl_quote(c.id)}", ' scope = "REGIONAL"', - " default_action { allow {} }", + # Terraform rejects a single-line block that contains a nested block, + # so default_action must be emitted multi-line. + " default_action {", + " allow {}", + " }", " visibility_config {", " cloudwatch_metrics_enabled = true", f" metric_name = {_hcl_quote(c.id)}", @@ -321,7 +325,7 @@ def render_resource(c: "Component", spec: "ArchSpec") -> str: f'resource "aws_ecs_service" "{c.id}_service" {{', f" name = {_hcl_quote(c.id + '-service')}", f" cluster = aws_ecs_cluster.{c.id}.id", - f" desired_count = {cfg.get('desired_count', 1)}", + f" desired_count = {_hcl_num(cfg.get('desired_count', 1), 1)}", f" launch_type = {_hcl_quote(launch_type)}", " task_definition = var.task_definition_arn", ] @@ -393,7 +397,7 @@ def render_resource(c: "Component", spec: "ArchSpec") -> str: lines += [ f'resource "aws_kinesis_stream" "{c.id}" {{', f" name = {_hcl_quote(_bucket_name(c))}", - f" shard_count = {cfg.get('shard_count', 2)}", + f" shard_count = {_hcl_num(cfg.get('shard_count', 2), 2)}", # Enforce server-side encryption with the AWS-managed KMS key. ' encryption_type = "KMS"', ' kms_key_id = "alias/aws/kinesis"', @@ -435,7 +439,7 @@ def render_resource(c: "Component", spec: "ArchSpec") -> str: lines += [ f'resource "aws_ebs_volume" "{c.id}" {{', " availability_zone = data.aws_availability_zones.available.names[0]", - f" size = {cfg.get('size', 100)}", + f" size = {_hcl_num(cfg.get('size', 100), 100)}", ' type = "gp3"', # Encryption at rest enforced by default. " encrypted = true", diff --git a/packages/core/cloudwright/exporter/terraform/azure.py b/packages/core/cloudwright/exporter/terraform/azure.py index ad4c426..798a09e 100644 --- a/packages/core/cloudwright/exporter/terraform/azure.py +++ b/packages/core/cloudwright/exporter/terraform/azure.py @@ -9,7 +9,7 @@ from typing import TYPE_CHECKING -from cloudwright.exporter.terraform.common import _hcl_quote +from cloudwright.exporter.terraform.common import _hcl_num, _hcl_quote if TYPE_CHECKING: from cloudwright.spec import ArchSpec, Component @@ -118,7 +118,7 @@ def render_resource(c: "Component", spec: "ArchSpec") -> str: f" dns_prefix = {_hcl_quote(safe_id)}", " default_node_pool {", ' name = "default"', - f" node_count = {cfg.get('node_count', 1)}", + f" node_count = {_hcl_num(cfg.get('node_count', 1), 1)}", f" vm_size = {_hcl_quote(cfg.get('vm_size', 'Standard_D2_v2'))}", " }", " identity {", @@ -191,7 +191,7 @@ def render_resource(c: "Component", spec: "ArchSpec") -> str: f" name = {_hcl_quote(safe_id)}", f" location = {_LOCATION}", f" resource_group_name = {_RG}", - f" capacity = {cfg.get('capacity', 1)}", + f" capacity = {_hcl_num(cfg.get('capacity', 1), 1)}", ' family = "C"', f" sku_name = {_hcl_quote(cfg.get('sku_name', 'Basic'))}", " tags = {", diff --git a/packages/core/cloudwright/exporter/terraform/common.py b/packages/core/cloudwright/exporter/terraform/common.py index eb30381..d74a7a6 100644 --- a/packages/core/cloudwright/exporter/terraform/common.py +++ b/packages/core/cloudwright/exporter/terraform/common.py @@ -48,6 +48,27 @@ def hcl_string(value: str) -> str: return _hcl_quote(value) +def _hcl_num(value: object, default: float, *, allow_float: bool = False) -> str: + """Return a safe numeric HCL literal for ``value``. + + Numeric config fields are interpolated into HCL without surrounding quotes, + so a string value (e.g. from LLM drift or a hand-edited spec) would be + emitted verbatim and could break out into arbitrary HCL — including a + ``provisioner "local-exec"`` that runs on ``terraform apply``. Coercing to + a real number here makes the numeric paths injection-proof regardless of the + input type; uncoercible values fall back to ``default``. + """ + try: + num = float(value) # type: ignore[arg-type] + if not allow_float: + num = int(num) + else: + num = int(num) if num.is_integer() else num + except (TypeError, ValueError): + num = int(default) if (not allow_float and float(default).is_integer()) else default + return str(num) + + def provider_block(provider: str, spec: "ArchSpec") -> str: if provider == "aws": return f'provider "aws" {{\n region = {_hcl_quote(spec.region)}\n}}' diff --git a/packages/core/cloudwright/exporter/terraform/databricks.py b/packages/core/cloudwright/exporter/terraform/databricks.py index 9b882e4..a6529e7 100644 --- a/packages/core/cloudwright/exporter/terraform/databricks.py +++ b/packages/core/cloudwright/exporter/terraform/databricks.py @@ -9,7 +9,7 @@ from typing import TYPE_CHECKING -from cloudwright.exporter.terraform.common import _hcl_quote +from cloudwright.exporter.terraform.common import _hcl_num, _hcl_quote if TYPE_CHECKING: from cloudwright.spec import ArchSpec, Component @@ -40,7 +40,7 @@ def render_resource(c: "Component", spec: "ArchSpec") -> str: f'resource "databricks_sql_endpoint" "{c.id}" {{', f" name = {_hcl_quote(c.label)}", f" cluster_size = {_hcl_quote(cfg.get('cluster_size', 'Small'))}", - f" auto_stop_mins = {cfg.get('auto_stop_mins', 30)}", + f" auto_stop_mins = {_hcl_num(cfg.get('auto_stop_mins', 30), 30)}", "}", ] @@ -50,8 +50,8 @@ def render_resource(c: "Component", spec: "ArchSpec") -> str: f" cluster_name = {_hcl_quote(c.label)}", f" spark_version = {_hcl_quote(cfg.get('spark_version', '13.3.x-scala2.12'))}", f" node_type_id = {_hcl_quote(cfg.get('node_type_id', 'i3.xlarge'))}", - f" autotermination_minutes = {cfg.get('autotermination_minutes', 60)}", - f" num_workers = {cfg.get('num_workers', 2)}", + f" autotermination_minutes = {_hcl_num(cfg.get('autotermination_minutes', 60), 60)}", + f" num_workers = {_hcl_num(cfg.get('num_workers', 2), 2)}", "}", ] diff --git a/packages/core/cloudwright/exporter/terraform/gcp.py b/packages/core/cloudwright/exporter/terraform/gcp.py index e5baf23..a848184 100644 --- a/packages/core/cloudwright/exporter/terraform/gcp.py +++ b/packages/core/cloudwright/exporter/terraform/gcp.py @@ -9,7 +9,7 @@ from typing import TYPE_CHECKING -from cloudwright.exporter.terraform.common import _hcl_quote +from cloudwright.exporter.terraform.common import _hcl_num, _hcl_quote if TYPE_CHECKING: from cloudwright.spec import ArchSpec, Component @@ -90,7 +90,7 @@ def render_resource(c: "Component", spec: "ArchSpec") -> str: f'resource "google_container_cluster" "{c.id}" {{', f" name = {_hcl_quote(safe_id)}", f" location = {_hcl_quote(cfg.get('location', 'us-central1'))}", - f" initial_node_count = {cfg.get('initial_node_count', 1)}", + f" initial_node_count = {_hcl_num(cfg.get('initial_node_count', 1), 1)}", " node_config {", f" machine_type = {_hcl_quote(cfg.get('machine_type', 'e2-medium'))}", " }", @@ -113,7 +113,7 @@ def render_resource(c: "Component", spec: "ArchSpec") -> str: " }", " }", " service_config {", - f" max_instance_count = {cfg.get('max_instances', 10)}", + f" max_instance_count = {_hcl_num(cfg.get('max_instances', 10), 10)}", " }", "}", ] @@ -146,7 +146,7 @@ def render_resource(c: "Component", spec: "ArchSpec") -> str: f'resource "google_redis_instance" "{c.id}" {{', f" name = {_hcl_quote(safe_id)}", ' tier = "BASIC"', - f" memory_size_gb = {cfg.get('memory_size_gb', 1)}", + f" memory_size_gb = {_hcl_num(cfg.get('memory_size_gb', 1), 1)}", f" region = {_hcl_quote(cfg.get('region', 'us-central1'))}", "}", ] diff --git a/packages/core/cloudwright/focus.py b/packages/core/cloudwright/focus.py new file mode 100644 index 0000000..cb43823 --- /dev/null +++ b/packages/core/cloudwright/focus.py @@ -0,0 +1,213 @@ +"""FinOps FOCUS 1.0 CSV exporter for CostEstimate line items. + +FOCUS (FinOps Open Cost and Usage Specification) defines a standard schema for +cloud billing data. Spec: https://focus.finops.org/ + +Column mapping: + BilledCost — actual monthly charge for this line item + EffectiveCost — same as BilledCost (no amortisation applied here) + ServiceName — cloud service name (e.g. "ec2", "rds") + ServiceCategory — FOCUS category inferred from service name + ResourceId — component_id from the ArchSpec + RegionId — region from the estimate + ChargePeriodStart — first day of current month (ISO 8601) + ChargePeriodEnd — last day of current month (ISO 8601) + BillingCurrency — always "USD" + PricingUnit — "Month" + PricingQuantity — 1.0 + ChargeType — "Usage" + PricingCategory — "Standard" (on_demand) or "Committed" (reserved) + PricingConfidence — per-line confidence from the cost engine ("high"/"low") +""" + +from __future__ import annotations + +import csv +import io +from calendar import monthrange +from datetime import date + +from cloudwright.spec import CostEstimate + +# FOCUS 1.0 required + recommended columns we emit +_FOCUS_COLUMNS = [ + "BilledCost", + "EffectiveCost", + "ServiceName", + "ServiceCategory", + "ResourceId", + "RegionId", + "ChargePeriodStart", + "ChargePeriodEnd", + "BillingCurrency", + "PricingUnit", + "PricingQuantity", + "ChargeType", + "PricingCategory", + "PricingConfidence", +] + +# Rough FOCUS ServiceCategory mapping by service keyword +_SERVICE_CATEGORY: dict[str, str] = { + "ec2": "Compute", + "compute_engine": "Compute", + "virtual_machines": "Compute", + "ecs": "Compute", + "eks": "Compute", + "gke": "Compute", + "aks": "Compute", + "fargate": "Compute", + "cloud_run": "Compute", + "container_apps": "Compute", + "app_engine": "Compute", + "app_service": "Compute", + "lambda": "Compute", + "cloud_functions": "Compute", + "azure_functions": "Compute", + "rds": "Databases", + "aurora": "Databases", + "cloud_sql": "Databases", + "azure_sql": "Databases", + "dynamodb": "Databases", + "cosmos_db": "Databases", + "firestore": "Databases", + "spanner": "Databases", + "elasticache": "Databases", + "memorystore": "Databases", + "azure_cache": "Databases", + "s3": "Storage", + "cloud_storage": "Storage", + "blob_storage": "Storage", + "ebs": "Storage", + "cloudfront": "Networking", + "cloud_cdn": "Networking", + "azure_cdn": "Networking", + "alb": "Networking", + "nlb": "Networking", + "app_gateway": "Networking", + "azure_lb": "Networking", + "cloud_load_balancing": "Networking", + "api_gateway": "Networking", + "api_management": "Networking", + "nat_gateway": "Networking", + "cloud_nat": "Networking", + "route53": "Networking", + "cloud_dns": "Networking", + "azure_dns": "Networking", + "sqs": "Integration", + "pub_sub": "Integration", + "service_bus": "Integration", + "sns": "Integration", + "event_hubs": "Integration", + "kinesis": "Integration", + "eventbridge": "Integration", + "event_grid": "Integration", + "redshift": "Analytics", + "bigquery": "Analytics", + "synapse": "Analytics", + "dataflow": "Analytics", + "sagemaker": "AI and Machine Learning", + "vertex_ai": "AI and Machine Learning", + "azure_ml": "AI and Machine Learning", + "databricks_cluster": "Analytics", + "databricks_sql_warehouse": "Analytics", + "databricks_job": "Analytics", + "databricks_pipeline": "Analytics", + "databricks_model_serving": "AI and Machine Learning", + "kms": "Security", + "cloud_kms": "Security", + "key_vault": "Security", + "secrets_manager": "Security", + "secret_manager": "Security", + "waf": "Security", + "cloud_armor": "Security", + "azure_waf": "Security", + "guardduty": "Security", + "security_hub": "Security", + "cloudwatch": "Management and Governance", + "cloud_logging": "Management and Governance", + "cloud_monitoring": "Management and Governance", + "azure_monitor": "Management and Governance", + "cloudtrail": "Management and Governance", + "config": "Management and Governance", +} + + +def _service_category(service: str) -> str: + return _SERVICE_CATEGORY.get(service, "Other") + + +def _charge_period() -> tuple[str, str]: + """Return (ChargePeriodStart, ChargePeriodEnd) for the current month.""" + today = date.today() + start = today.replace(day=1) + last_day = monthrange(today.year, today.month)[1] + end = today.replace(day=last_day) + return start.isoformat(), end.isoformat() + + +def to_focus_csv(estimate: CostEstimate, pricing_tier: str = "on_demand") -> str: + """Serialise a CostEstimate to a FOCUS 1.0 compliant CSV string. + + Each line item in estimate.breakdown becomes one row. The data-transfer + sub-total is added as a synthetic "DataTransfer" service row when non-zero. + + Args: + estimate: A CostEstimate produced by CostEngine.estimate(). + pricing_tier: The pricing tier used to produce the estimate. Controls + PricingCategory ("Standard" for on_demand, "Committed" for reserved). + + Returns: + A UTF-8 CSV string with FOCUS 1.0 column headers. + """ + period_start, period_end = _charge_period() + region = estimate.region or "us-east-1" + currency = estimate.currency or "USD" + pricing_category = "Standard" if pricing_tier == "on_demand" else "Committed" + + buf = io.StringIO() + writer = csv.DictWriter(buf, fieldnames=_FOCUS_COLUMNS, lineterminator="\n") + writer.writeheader() + + for item in estimate.breakdown: + writer.writerow( + { + "BilledCost": round(item.monthly, 4), + "EffectiveCost": round(item.monthly, 4), + "ServiceName": item.service, + "ServiceCategory": _service_category(item.service), + "ResourceId": item.component_id, + "RegionId": region, + "ChargePeriodStart": period_start, + "ChargePeriodEnd": period_end, + "BillingCurrency": currency, + "PricingUnit": "Month", + "PricingQuantity": 1.0, + "ChargeType": "Usage", + "PricingCategory": pricing_category, + "PricingConfidence": item.confidence, + } + ) + + # Add data-transfer line if non-zero + if estimate.data_transfer_monthly > 0: + writer.writerow( + { + "BilledCost": round(estimate.data_transfer_monthly, 4), + "EffectiveCost": round(estimate.data_transfer_monthly, 4), + "ServiceName": "DataTransfer", + "ServiceCategory": "Networking", + "ResourceId": "data-transfer", + "RegionId": region, + "ChargePeriodStart": period_start, + "ChargePeriodEnd": period_end, + "BillingCurrency": currency, + "PricingUnit": "Month", + "PricingQuantity": 1.0, + "ChargeType": "Usage", + "PricingCategory": pricing_category, + "PricingConfidence": "low", # always estimated from connection metadata + } + ) + + return buf.getvalue() diff --git a/packages/core/cloudwright/oscal.py b/packages/core/cloudwright/oscal.py new file mode 100644 index 0000000..ef7fbf5 --- /dev/null +++ b/packages/core/cloudwright/oscal.py @@ -0,0 +1,199 @@ +"""OSCAL 1.1.2 component-definition export for Cloudwright compliance results. + +Converts a ComplianceReport + ArchSpec into a machine-readable OSCAL +component-definition document. FedRAMP's 20x/OSCAL direction makes this +the interoperability surface competitors don't have. + +Control IDs from compliance_controls.yaml are already NIST-shaped for +FedRAMP/NIST-800-53 (e.g. "SC-28", "AC-3"). For HIPAA/SOC2/PCI-DSS/GDPR/ISO27001 +the control IDs are kept verbatim and annotated with a source-framework prop +so validators know they're not NIST identifiers. +""" + +from __future__ import annotations + +import uuid +from datetime import datetime, timezone +from typing import TYPE_CHECKING, Any + +if TYPE_CHECKING: + from cloudwright.compliance import ComplianceReport + from cloudwright.spec import ArchSpec + +_OSCAL_VERSION = "1.1.2" +_CW_VERSION = "1.6.0" + +# Frameworks whose control IDs are already NIST SP 800-53 style. +_NIST_SHAPED = {"FedRAMP", "NIST-800-53"} + + +def _det_uuid(spec_name: str, frameworks: list[str]) -> str: + """Deterministic uuid5 from spec name + sorted framework list. + + Stable across calls with the same inputs — required for reproducible tests + and idempotent CI artifact generation. + """ + seed = f"{spec_name}|{','.join(sorted(frameworks))}" + return str(uuid.uuid5(uuid.NAMESPACE_DNS, seed)) + + +def _component_uuid(spec_name: str, component_id: str) -> str: + seed = f"{spec_name}::{component_id}" + return str(uuid.uuid5(uuid.NAMESPACE_DNS, seed)) + + +def _req_uuid(spec_name: str, component_id: str, control_id: str, framework: str) -> str: + seed = f"{spec_name}::{component_id}::{framework}::{control_id}" + return str(uuid.uuid5(uuid.NAMESPACE_DNS, seed)) + + +def _normalize_control_id(control_id: str, framework: str) -> str: + """Return a lowercase NIST-style control ID when the framework uses NIST IDs. + + Non-NIST IDs (HIPAA CFR citations, SOC2 criteria, etc.) are kept verbatim + because forcibly lowercasing them would make them unrecognizable. + """ + if framework in _NIST_SHAPED: + return control_id.lower() + return control_id + + +def to_oscal(spec: ArchSpec, scan_result: ComplianceReport, frameworks: list[str]) -> dict[str, Any]: + """Return a valid OSCAL 1.1.2 component-definition document as a dict. + + Args: + spec: The architecture specification being assessed. + scan_result: The ComplianceReport produced by ComplianceScanner.scan(). + frameworks: The list of canonical framework names used during the scan + (e.g. ["HIPAA", "FedRAMP"]). + + Returns: + A dict that serialises to valid OSCAL 1.1.2 component-definition JSON. + """ + doc_uuid = _det_uuid(spec.name, frameworks) + now = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ") + + # Build a fast lookup: (component_id, framework, control_id) -> worst severity + # A control is "not-satisfied" when any finding references it. + failing: dict[tuple[str | None, str, str], str] = {} + for finding in scan_result.findings: + for ctrl in finding.controls: + key = (finding.component_id, ctrl.framework, ctrl.control_id) + prev = failing.get(key) + if prev is None: + failing[key] = finding.severity + else: + _rank = {"critical": 0, "high": 1, "medium": 2, "low": 3} + if _rank.get(finding.severity, 4) < _rank.get(prev, 4): + failing[key] = finding.severity + + components = [] + for comp in spec.components: + ctrl_impls = _control_implementations_for(spec.name, comp, frameworks, scan_result, failing) + components.append( + { + "uuid": _component_uuid(spec.name, comp.id), + "type": "service", + "title": comp.label or comp.id, + "description": comp.description or f"{comp.service} ({comp.provider})", + "props": [ + {"name": "provider", "value": comp.provider}, + {"name": "service", "value": comp.service}, + ], + "control-implementations": ctrl_impls, + } + ) + + return { + "component-definition": { + "uuid": doc_uuid, + "metadata": { + "title": f"Cloudwright Compliance — {spec.name}", + "last-modified": now, + "version": _CW_VERSION, + "oscal-version": _OSCAL_VERSION, + "props": [ + {"name": "generator", "value": "cloudwright-ai"}, + {"name": "frameworks", "value": ", ".join(frameworks)}, + ], + }, + "components": components, + } + } + + +def _control_implementations_for( + spec_name: str, + comp: Any, + frameworks: list[str], + scan_result: ComplianceReport, + failing: dict[tuple[str | None, str, str], str], +) -> list[dict]: + """Build the control-implementations array for one architecture component.""" + # Gather all (framework, control_id) pairs relevant to this component: + # - controls from findings scoped to this component + # - controls from findings with no component scope (architecture-wide) + seen: dict[tuple[str, str], str] = {} # (framework, ctrl) -> worst severity + + for finding in scan_result.findings: + if finding.component_id not in (comp.id, None): + continue + for ctrl in finding.controls: + if ctrl.framework not in frameworks: + continue + key = (ctrl.framework, ctrl.control_id) + sev_key = (finding.component_id, ctrl.framework, ctrl.control_id) + sev = failing.get(sev_key, finding.severity) + prev = seen.get(key) + if prev is None: + seen[key] = sev + else: + _rank = {"critical": 0, "high": 1, "medium": 2, "low": 3} + if _rank.get(sev, 4) < _rank.get(prev, 4): + seen[key] = sev + + if not seen: + return [] + + # Group by framework + by_fw: dict[str, list[tuple[str, str]]] = {} + for (fw, ctrl), sev in seen.items(): + by_fw.setdefault(fw, []).append((ctrl, sev)) + + impls = [] + for fw in frameworks: + reqs = by_fw.get(fw) + if not reqs: + continue + + implemented_reqs = [] + for ctrl_id, sev in reqs: + normalized = _normalize_control_id(ctrl_id, fw) + props = [ + {"name": "framework", "value": fw}, + {"name": "severity", "value": sev}, + ] + if fw not in _NIST_SHAPED: + # Non-NIST control IDs need source annotation for validators + props.append({"name": "control-id-source", "value": fw}) + + implemented_reqs.append( + { + "uuid": _req_uuid(spec_name, comp.id, ctrl_id, fw), + "control-id": normalized, + "description": f"Cloudwright finding for control {ctrl_id} ({fw})", + "props": props, + "implementation-status": {"state": "not-satisfied"}, + } + ) + + impls.append( + { + "uuid": _req_uuid(spec_name, comp.id, fw, "impl"), + "source": f"https://cloudwright.ai/frameworks/{fw.lower()}", + "description": f"{fw} control implementation for {comp.id}", + "implemented-requirements": implemented_reqs, + } + ) + + return impls diff --git a/packages/core/cloudwright/parsing.py b/packages/core/cloudwright/parsing.py index c8e6902..3611265 100644 --- a/packages/core/cloudwright/parsing.py +++ b/packages/core/cloudwright/parsing.py @@ -42,12 +42,17 @@ def _extract_json(text: str) -> dict: arr_start = text.find("[") candidates = [i for i in (obj_start, arr_start) if i != -1] if not candidates: + # The full response is the single most useful artifact for reproducing a + # parse failure, so log it in full (recoverable via --debug) before + # raising a short message. + log.debug("LLM response with no JSON object (full):\n%s", text) raise ValueError(f"No JSON object found in LLM response: {text[:300]}") start = min(candidates) try: parsed, _end = _JSON_DECODER.raw_decode(text[start:]) except json.JSONDecodeError as exc: + log.debug("LLM response with invalid JSON (full):\n%s", text) raise ValueError(f"Unterminated or invalid JSON in LLM response: {text[:300]}") from exc return parsed @@ -132,6 +137,12 @@ def _profile_requires_ha(spec: ArchSpec, constraints: Constraints | None) -> boo profile = "" if spec.metadata and isinstance(spec.metadata, dict): profile = str(spec.metadata.get("workload_profile", "")).lower() + # Compliance frameworks override the workload profile — a HIPAA/PCI/FedRAMP + # workload gets HA even when someone labelled it a sandbox. This check MUST + # come before the _NON_HA_PROFILES early-return or the invariant is silently + # defeated for sandbox/dev/test profiles. + if constraints and any(f.lower() in _HA_REQUIRING_FRAMEWORKS for f in constraints.compliance): + return True if profile in _NON_HA_PROFILES: return False if profile in _HA_PROFILES: @@ -139,9 +150,6 @@ def _profile_requires_ha(spec: ArchSpec, constraints: Constraints | None) -> boo if constraints is None: # No signal either way — default to production posture (back-compat). return True - # Compliance frameworks always pull in HA. - if any(f.lower() in _HA_REQUIRING_FRAMEWORKS for f in constraints.compliance): - return True if constraints.availability and constraints.availability >= 0.995: return True if constraints.throughput_rps and constraints.throughput_rps >= 1000: @@ -156,13 +164,14 @@ def _profile_requires_encryption(spec: ArchSpec, constraints: Constraints | None profile = "" if spec.metadata and isinstance(spec.metadata, dict): profile = str(spec.metadata.get("workload_profile", "")).lower() + # Compliance frameworks override the workload profile — encryption-at-rest is + # non-negotiable under HIPAA/PCI/SOC2/FedRAMP/GDPR/ISO even if the spec is + # labelled a sandbox. This MUST precede the _NON_HA_PROFILES early-return. + if constraints and any(f.lower() in _ENCRYPTION_REQUIRING_FRAMEWORKS for f in constraints.compliance): + return True if profile in _NON_HA_PROFILES: # Sandboxes get whatever the LLM picked — no forced encryption override. return False - if constraints is None: - return True # back-compat default - if any(f.lower() in _ENCRYPTION_REQUIRING_FRAMEWORKS for f in constraints.compliance): - return True return True # default true — better safe than encrypted-after-the-breach diff --git a/packages/core/cloudwright/patterns.py b/packages/core/cloudwright/patterns.py new file mode 100644 index 0000000..dc43f0c --- /dev/null +++ b/packages/core/cloudwright/patterns.py @@ -0,0 +1,166 @@ +"""Compliance-gated component patterns. + +Maps templates and approved modules to the compliance frameworks their +component sets actually cover. Tags are conservative: a framework is only +listed when the pattern's components address that framework's core technical +controls (encryption, HA, audit logging, access control, etc.). + +Supported frameworks: hipaa, soc2, pci-dss, fedramp, iso27001, gdpr. +""" + +from __future__ import annotations + +from typing import Any + +# --------------------------------------------------------------------------- +# Pattern registry +# +# Each entry captures the pattern source (template key or module id), a +# display name, the frameworks it satisfies, and a per-framework justification. +# +# Rationale for framework inclusion: +# +# HIPAA — needs encryption-at-rest + in-transit, access controls, audit logs, +# and HA (uptime standard). Patterns with multi-AZ/HA + encryption on +# all data tiers qualify. +# SOC 2 — availability, confidentiality, and security. Multi-AZ, HTTPS, +# encryption, and access controls broadly satisfy trust service criteria. +# PCI-DSS — narrow: requires WAF, network segmentation (alb/gateway), encryption, +# and TLS on every hop. Only patterns with an explicit WAF or gateway +# with WAF config qualify. +# FedRAMP — requires FIPS-level encryption, HA across AZs, audit trails. +# Patterns with multi-AZ encrypted managed services qualify at a +# Moderate baseline; Databricks patterns do not (no FedRAMP ATOs). +# ISO 27001 — broad information security management. HTTPS, encryption, backup, +# access controls, and HA are the technical pillars. +# GDPR — data protection by design: encryption-at-rest, encryption-in-transit, +# backup, and access controls. Does not require WAF. Most encrypted +# multi-AZ patterns qualify. +# --------------------------------------------------------------------------- + +_PATTERNS: list[dict[str, Any]] = [ + { + "name": "3-Tier Web Application (AWS)", + "source": "template:3-tier-web-aws", + "frameworks": { + "soc2": "Multi-AZ RDS + HTTPS CDN/ALB + encryption satisfies availability and confidentiality criteria.", + "hipaa": "Multi-AZ RDS with encryption + backup covers PHI durability and access control requirements.", + "fedramp": "Multi-AZ managed RDS with encryption meets FedRAMP Moderate availability and data-protection controls.", + "iso27001": "Encrypted RDS + HTTPS + backup + security groups address A.12 (operations security) and A.14 (secure development) controls.", + "gdpr": "Encryption-at-rest and in-transit + backup aligns with GDPR Article 32 technical safeguards.", + }, + }, + { + "name": "Web Application (Azure)", + "source": "template:web-app-azure", + "frameworks": { + "soc2": "App Gateway WAF + HTTPS CDN + Multi-AZ SQL + encryption covers availability and security trust criteria.", + "hipaa": "Encrypted multi-AZ Azure SQL + WAF-backed gateway provides PHI protection and audit controls.", + "pci-dss": "App Gateway with WAF enabled (waf: True) + HTTPS on every hop + encrypted SQL meets PCI-DSS requirements for cardholder-data environments.", + "fedramp": "Multi-AZ Azure SQL with encryption meets FedRAMP Moderate data protection; WAF adds perimeter control.", + "iso27001": "WAF + encryption + backup + HTTPS satisfies A.13 (communications security) and A.12 controls.", + "gdpr": "Encrypted SQL + WAF + backup meets GDPR Article 32 technical safeguards.", + }, + }, + { + "name": "Microservices Platform (AWS)", + "source": "template:microservices-aws", + "frameworks": { + "soc2": "ECS Fargate + encrypted RDS multi-AZ + encrypted ElastiCache + SQS encryption covers availability and confidentiality.", + "hipaa": "Encryption on all data tiers (RDS, ElastiCache, SQS) + multi-AZ RDS meets HIPAA technical safeguard requirements.", + "fedramp": "Multi-AZ RDS with encryption + encrypted messaging + managed container platform meets FedRAMP Moderate baseline.", + "iso27001": "Full encryption stack + multi-AZ + backup satisfies A.10 (cryptography) and A.17 (business continuity) controls.", + "gdpr": "Encryption-at-rest and in-transit on all data tiers + backup meets GDPR Article 32 obligations.", + }, + }, + { + "name": "Kubernetes Platform (AWS EKS)", + "source": "template:kubernetes-aws", + "frameworks": { + "soc2": "EKS + encrypted RDS multi-AZ + encrypted ECR + HTTPS ingress covers availability and confidentiality criteria.", + "hipaa": "Multi-AZ encrypted RDS + encrypted container images (ECR scan-on-push) + HTTPS meets HIPAA safeguards.", + "fedramp": "Multi-AZ encrypted managed database + private container registry meets FedRAMP Moderate baseline.", + "iso27001": "Encrypted RDS + ECR image scanning + multi-AZ + HTTPS aligns with ISO 27001 A.12 and A.14 controls.", + "gdpr": "Encrypted storage + HTTPS + backup meets GDPR Article 32 technical safeguards.", + }, + }, + { + "name": "Data Warehouse (AWS)", + "source": "template:data-warehouse-aws", + "frameworks": { + "soc2": "Encrypted Kinesis + encrypted S3 + encrypted Redshift multi-AZ + Athena covers availability and confidentiality.", + "hipaa": "Full encryption stack (Kinesis, S3, Redshift) + multi-AZ + backup meets HIPAA data-at-rest and transit requirements.", + "fedramp": "Encrypted managed streaming + S3 + multi-AZ Redshift meets FedRAMP Moderate data-protection controls.", + "iso27001": "Encryption across all tiers + backup satisfies A.10 and A.17 controls.", + "gdpr": "Encrypted storage and streaming + backup meets GDPR Article 32 for large-scale data processing.", + }, + }, + { + "name": "AWS Three-Tier Web (Module)", + "source": "module:aws-three-tier-web", + "frameworks": { + "soc2": "Multi-AZ RDS + HTTPS CDN/ALB covers availability and confidentiality trust criteria.", + "iso27001": "HTTPS + multi-AZ managed database aligns with A.12 and A.14 controls.", + "gdpr": "HTTPS in-transit + multi-AZ persistence meets GDPR Article 32 baseline.", + }, + }, + { + "name": "AWS Serverless API (Module)", + "source": "module:aws-serverless-api", + "frameworks": { + "soc2": "DynamoDB encryption + backup + HTTPS API Gateway meets confidentiality and availability criteria.", + "gdpr": "DynamoDB encryption + backup provides GDPR Article 32 data protection for serverless APIs.", + }, + }, + { + "name": "Azure Three-Tier Web (Module)", + "source": "module:azure-three-tier-web", + "frameworks": { + "soc2": "App Gateway WAF (WAF_v2 SKU) + HTTPS CDN + Azure SQL covers security and availability trust criteria.", + "hipaa": "WAF-backed ingress + managed SQL with backup provides HIPAA technical safeguard controls.", + "pci-dss": "App Gateway WAF_v2 SKU provides WAF on every inbound connection; HTTPS on all hops meets PCI-DSS network-security requirements.", + "iso27001": "WAF + HTTPS + managed SQL satisfies A.13 and A.12 controls.", + "gdpr": "HTTPS + WAF + managed SQL with backup meets GDPR Article 32 technical safeguards.", + }, + }, +] + +# Build a flat lookup: framework -> sorted list of matching patterns +_BY_FRAMEWORK: dict[str, list[dict[str, Any]]] = {} +for _p in _PATTERNS: + for _fw in _p["frameworks"]: + _BY_FRAMEWORK.setdefault(_fw, []).append(_p) + + +def suggest_compliant_patterns(framework: str) -> list[dict[str, Any]]: + """Return patterns pre-blessed for the given compliance framework. + + Patterns are returned in descending order of how many frameworks they + satisfy (broader coverage first). Only patterns that honestly cover the + framework's core technical controls are included. + + Args: + framework: Lowercase framework name — hipaa, soc2, pci-dss, + fedramp, iso27001, or gdpr. + + Returns: + List of dicts with keys: name, source, frameworks (list), why (str). + Empty list when the framework is unknown or no patterns qualify. + """ + fw = framework.lower().strip() + matches = _BY_FRAMEWORK.get(fw, []) + + results: list[dict[str, Any]] = [] + for pattern in matches: + results.append( + { + "name": pattern["name"], + "source": pattern["source"], + "frameworks": sorted(pattern["frameworks"].keys()), + "why": pattern["frameworks"][fw], + } + ) + + # Rank by breadth of compliance coverage (most frameworks first) + results.sort(key=lambda r: len(r["frameworks"]), reverse=True) + return results diff --git a/packages/core/cloudwright/planner.py b/packages/core/cloudwright/planner.py index e452e55..003363f 100644 --- a/packages/core/cloudwright/planner.py +++ b/packages/core/cloudwright/planner.py @@ -26,6 +26,43 @@ _PLAN_RE = re.compile(r"Plan:\s+(\d+) to add,\s+(\d+) to change,\s+(\d+) to destroy") _NO_CHANGES_RE = re.compile(r"No changes\.|0 to add, 0 to change, 0 to destroy") +# LLM/app secrets that terraform and pulumi never need. Kept out of the +# subprocess environment so they cannot surface in provider error output. +_APP_SECRET_KEYS = frozenset({"ANTHROPIC_API_KEY", "ANTHROPIC_AUTH_TOKEN", "OPENAI_API_KEY", "CLOUDWRIGHT_API_KEY"}) +# Only credential-shaped keys are merged from a project .env into the subprocess. +_CLOUD_CRED_PREFIXES = ( + "AWS_", + "GOOGLE_", + "GCLOUD_", + "CLOUDSDK_", + "AZURE_", + "ARM_", + "DATABRICKS_", + "TF_VAR_", + "TF_", + "PULUMI_", +) +_SECRET_KEY_RE = re.compile(r"KEY|TOKEN|SECRET|PASSWORD|CREDENTIAL", re.I) + + +def _secret_values() -> set[str]: + """Values of every secret-shaped env var, for redacting subprocess output.""" + vals: set[str] = set() + for env in (dict(os.environ), _subprocess_env()): + for key, val in env.items(): + if val and len(val) >= 8 and _SECRET_KEY_RE.search(key): + vals.add(val) + return vals + + +def _scrub(text: str) -> str: + """Redact any secret-shaped env value that leaked into subprocess output.""" + if not text: + return text + for val in _secret_values(): + text = text.replace(val, "***REDACTED***") + return text + @dataclass class PlanResult: @@ -53,7 +90,7 @@ def as_dict(self) -> dict[str, Any]: def _tail(text: str, n: int = 40) -> str: lines = (text or "").strip().splitlines() - return "\n".join(lines[-n:]) + return _scrub("\n".join(lines[-n:])) def _run(cmd: list[str], cwd: str, timeout: int, env: dict | None = None) -> subprocess.CompletedProcess: @@ -69,8 +106,13 @@ def _run(cmd: list[str], cwd: str, timeout: int, env: dict | None = None) -> sub def _subprocess_env() -> dict[str, str]: - """Process env plus any cloud credentials defined in a project .env.""" - env = dict(os.environ) + """Process env (minus LLM/app secrets) plus cloud creds from a project .env. + + terraform/pulumi never need the LLM API key, so app secrets are stripped from + the subprocess environment to keep them out of any provider error output, and + only credential-shaped keys are merged from a project ``.env``. + """ + env = {k: v for k, v in os.environ.items() if k not in _APP_SECRET_KEYS} for base in (Path.cwd(), Path(__file__).resolve().parents[3]): dotenv = base / ".env" if dotenv.is_file(): @@ -80,30 +122,51 @@ def _subprocess_env() -> dict[str, str]: continue key, _, val = line.partition("=") key = key.strip() - if key and key not in env: + if not key or key in env or key in _APP_SECRET_KEYS: + continue + if key.startswith(_CLOUD_CRED_PREFIXES): env[key] = val.strip().strip('"').strip("'") break return env +def _terraform_binary() -> tuple[str | None, str]: + """Resolve the IaC binary, preferring OpenTofu. + + OpenTofu (`tofu`) is a drop-in for the same generated HCL, so honour it when + present (or when CLOUDWRIGHT_TF_BINARY points at one). Falls back to + `terraform`. Returns (path_or_None, tool_label). + """ + override = os.environ.get("CLOUDWRIGHT_TF_BINARY", "").strip() + if override: + path = shutil.which(override) or (override if Path(override).is_file() else None) + return path, ("opentofu" if "tofu" in override else "terraform") + tofu = shutil.which("tofu") + if tofu: + return tofu, "opentofu" + return shutil.which("terraform"), "terraform" + + def plan_terraform( spec: ArchSpec, *, run_plan: bool = True, timeout: int = 180, ) -> PlanResult: - """`terraform init -backend=false` + `validate` (+ optional `plan`).""" + """`terraform`/`tofu` init -backend=false + validate (+ optional plan).""" from cloudwright.exporter import export_spec - tf = shutil.which("terraform") + tf, tool = _terraform_binary() if not tf: return PlanResult( - tool="terraform", + tool=tool, available=False, validated=False, plan_ran=False, ok=False, - messages=["terraform binary not found on PATH. Install Terraform to enable plan/preview."], + messages=[ + "Neither tofu nor terraform found on PATH. Install OpenTofu or Terraform to enable plan/preview." + ], ) env = _subprocess_env() @@ -112,7 +175,7 @@ def plan_terraform( export_spec(spec, "terraform", output_dir=tmp) except Exception as exc: return PlanResult( - tool="terraform", + tool=tool, available=True, validated=False, plan_ran=False, @@ -135,7 +198,7 @@ def plan_terraform( else: init_msg = "terraform init failed (provider download / network?)." return PlanResult( - tool="terraform", + tool=tool, available=True, validated=False, plan_ran=False, @@ -151,7 +214,7 @@ def plan_terraform( else: messages.append("terraform validate: configuration is INVALID.") return PlanResult( - tool="terraform", + tool=tool, available=True, validated=False, plan_ran=False, @@ -162,7 +225,7 @@ def plan_terraform( if not run_plan: return PlanResult( - tool="terraform", + tool=tool, available=True, validated=True, plan_ran=False, @@ -193,7 +256,7 @@ def plan_terraform( summary = None messages.append("terraform plan: completed.") return PlanResult( - tool="terraform", + tool=tool, available=True, validated=True, plan_ran=True, @@ -221,7 +284,7 @@ def plan_terraform( reason = "terraform plan did not complete (see output)." messages.append(reason) return PlanResult( - tool="terraform", + tool=tool, available=True, validated=True, plan_ran=False, diff --git a/packages/core/cloudwright/remediation.py b/packages/core/cloudwright/remediation.py new file mode 100644 index 0000000..4cf486d --- /dev/null +++ b/packages/core/cloudwright/remediation.py @@ -0,0 +1,118 @@ +"""Agentic drift -> remediation — closes the gap between current and desired spec. + +Read-only: computes what *would* happen if the desired spec replaced the current +one. Never applies changes. Degrades gracefully when terraform/tofu is absent. +""" + +from __future__ import annotations + +from typing import TYPE_CHECKING, Any + +if TYPE_CHECKING: + from cloudwright.spec import ArchSpec + + +def remediate( + current_spec: "ArchSpec", + desired_spec: "ArchSpec", + *, + run_plan: bool = False, + skip_plan: bool = False, +) -> dict[str, Any]: + """Compute the full remediation picture between current and desired spec. + + Args: + current_spec: The spec reflecting what is currently deployed. + desired_spec: The target spec to converge toward. + run_plan: When True, attempt a real terraform plan (needs credentials). + When False (default), only run init + validate — no credentials needed. + + Returns: + A dict with keys: + - drift: list of change dicts from the diff + - cost_delta: {"current": float, "desired": float, "delta": float, "currency": str} + - quality_delta: {"current": float, "desired": float, "delta": float, + "current_grade": str, "desired_grade": str} + - plan: PlanResult.as_dict() + - summary: human-readable summary string + """ + from cloudwright.cost import CostEngine + from cloudwright.critique import critique + from cloudwright.differ import Differ + from cloudwright.planner import plan_terraform + + # 1. Compute drift/diff between current and desired + differ = Differ() + diff = differ.diff(current_spec, desired_spec) + + drift_items: list[dict[str, Any]] = [] + for comp in diff.added: + drift_items.append({"change": "add", "id": comp.id, "service": comp.service}) + for comp in diff.removed: + drift_items.append({"change": "remove", "id": comp.id, "service": comp.service}) + for ch in diff.changed: + drift_items.append( + { + "change": "modify", + "id": ch.component_id, + "field": ch.field, + "from": ch.old_value, + "to": ch.new_value, + } + ) + + # 2. Cost delta + engine = CostEngine() + current_estimate = engine.estimate(current_spec) + desired_estimate = engine.estimate(desired_spec) + delta = round(desired_estimate.monthly_total - current_estimate.monthly_total, 2) + cost_delta: dict[str, Any] = { + "current": current_estimate.monthly_total, + "desired": desired_estimate.monthly_total, + "delta": delta, + "currency": "USD", + } + + # 3. Quality delta via critique (deterministic, no LLM) + current_report = critique(current_spec) + desired_report = critique(desired_spec) + quality_delta: dict[str, Any] = { + "current": round(current_report.score, 1), + "desired": round(desired_report.score, 1), + "delta": round(desired_report.score - current_report.score, 1), + "current_grade": current_report.grade, + "desired_grade": desired_report.grade, + } + + # 4. Terraform/tofu plan preview of the desired spec (read-only). Skippable + # so callers (and tests) can get drift+cost+quality without invoking the + # IaC toolchain. + if skip_plan: + plan_dict: dict[str, Any] = {"skipped": True, "validated": False} + plan_validated = False + else: + plan_result = plan_terraform(desired_spec, run_plan=run_plan) + plan_dict = plan_result.as_dict() + plan_validated = plan_result.validated + + # 5. Build summary + n_drift = len(drift_items) + cost_sign = "+" if delta >= 0 else "" + quality_sign = "+" if quality_delta["delta"] >= 0 else "" + plan_ok = "skipped" if skip_plan else ("valid" if plan_validated else "not validated") + summary = ( + f"{n_drift} change(s) to close drift. " + f"Cost: {cost_sign}${delta:,.2f}/mo " + f"(${current_estimate.monthly_total:,.2f} -> ${desired_estimate.monthly_total:,.2f}). " + f"Quality: {quality_sign}{quality_delta['delta']:.1f} pts " + f"({current_report.grade} -> {desired_report.grade}). " + f"Plan: {plan_ok}." + ) + + return { + "drift": drift_items, + "cost_delta": cost_delta, + "quality_delta": quality_delta, + "plan": plan_dict, + "summary": summary, + } diff --git a/packages/core/cloudwright/spec.py b/packages/core/cloudwright/spec.py index 44c65ff..21a05a5 100644 --- a/packages/core/cloudwright/spec.py +++ b/packages/core/cloudwright/spec.py @@ -93,6 +93,8 @@ class ComponentCost(BaseModel): monthly: float hourly: float | None = None notes: str = "" + confidence: str = "high" # "high" = real catalog row; "low" = formula/fallback + estimated: bool = False # True when price comes from a fallback, not catalog data class CostEstimate(BaseModel): @@ -101,6 +103,9 @@ class CostEstimate(BaseModel): data_transfer_monthly: float = 0.0 currency: str = "USD" as_of: str = Field(default_factory=lambda: date.today().isoformat()) + pricing_confidence: str = "high" # "high" only when every line item is high + region: str = "us-east-1" + region_multiplier: float = 1.0 # multiplier applied relative to us-east-1 baseline class Alternative(BaseModel): diff --git a/packages/core/pyproject.toml b/packages/core/pyproject.toml index b0e3550..58af9a1 100644 --- a/packages/core/pyproject.toml +++ b/packages/core/pyproject.toml @@ -29,10 +29,10 @@ dependencies = [ ] [project.optional-dependencies] -cli = ["cloudwright-ai-cli==1.5.0"] -web = ["cloudwright-ai-cli==1.5.0", "cloudwright-ai-web==1.5.0"] -mcp = ["cloudwright-ai-mcp==1.5.0"] -all = ["cloudwright-ai-cli==1.5.0", "cloudwright-ai-web==1.5.0", "cloudwright-ai-mcp==1.5.0", "databricks-sdk>=0.38.0"] +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"] pdf = ["weasyprint", "markdown2"] databricks = ["databricks-sdk>=0.38.0"] live-import = [ diff --git a/packages/core/tests/test_cost_v160.py b/packages/core/tests/test_cost_v160.py new file mode 100644 index 0000000..58b5066 --- /dev/null +++ b/packages/core/tests/test_cost_v160.py @@ -0,0 +1,457 @@ +"""Tests for v1.6.0 cost engine improvements: +- Regional price multipliers +- Pricing confidence per line item +- Carbon footprint estimator +- FOCUS CSV export +""" + +from __future__ import annotations + +import csv +import io + +import pytest +from cloudwright.spec import ArchSpec, Component, Connection + + +def _simple_spec(region: str = "us-east-1", provider: str = "aws") -> ArchSpec: + return ArchSpec( + name="Test", + provider=provider, + region=region, + components=[ + Component( + id="web", + service="ec2", + provider=provider, + label="Web", + tier=2, + config={"instance_type": "t3.medium"}, + ), + Component( + id="db", + service="rds", + provider=provider, + label="DB", + tier=3, + config={"instance_class": "db.t3.medium", "storage_gb": 50}, + ), + ], + connections=[], + ) + + +def _fallback_spec() -> ArchSpec: + """Spec with a service that has no catalog row — forces fallback pricing.""" + return ArchSpec( + name="Fallback", + provider="aws", + region="us-east-1", + components=[ + Component( + id="custom", + service="definitely_unknown_service_xyz", + provider="aws", + label="Unknown", + tier=2, + config={}, + ), + ], + connections=[], + ) + + +class TestRegionMultiplier: + def test_eu_west_costs_more_than_us_east(self): + from cloudwright.cost import CostEngine + + engine = CostEngine() + us = engine.estimate(_simple_spec(region="us-east-1")) + eu = engine.estimate(_simple_spec(region="eu-west-1")) + # eu-west-1 multiplier is 1.08 — formula/fallback tiers get it applied + # catalog tiers (ec2/rds with instance class) may not differ if catalog has exact pricing + # but at least the region multiplier should be recorded + assert eu.region_multiplier > us.region_multiplier + + def test_sa_east_costs_more_than_us_east(self): + """sa-east-1 has a 1.25 multiplier for fallback-priced services.""" + from cloudwright.cost import CostEngine + + # Use a spec with only fallback-priced services so multiplier is clearly applied + spec_us = ArchSpec( + name="SA Test US", + provider="aws", + region="us-east-1", + components=[ + Component(id="q", service="sqs", provider="aws", label="Q", tier=2, config={}), + ], + connections=[], + ) + spec_sa = spec_us.model_copy(update={"region": "sa-east-1", "name": "SA Test SA"}) + + engine = CostEngine() + us_est = engine.estimate(spec_us) + sa_est = engine.estimate(spec_sa) + assert sa_est.monthly_total > us_est.monthly_total + + def test_region_multiplier_recorded_on_estimate(self): + from cloudwright.cost import CostEngine + + engine = CostEngine() + est = engine.estimate(_simple_spec(region="eu-west-1")) + assert est.region == "eu-west-1" + assert est.region_multiplier == pytest.approx(1.08, rel=1e-3) + + def test_us_east_multiplier_is_baseline(self): + from cloudwright.cost import CostEngine + + engine = CostEngine() + est = engine.estimate(_simple_spec(region="us-east-1")) + assert est.region_multiplier == pytest.approx(1.00, rel=1e-3) + + def test_unknown_region_falls_back_to_1x(self): + from cloudwright.cost import _region_multiplier + + assert _region_multiplier("totally-unknown-region-99") == 1.00 + + def test_region_multiplier_helper(self): + from cloudwright.cost import _region_multiplier + + assert _region_multiplier("us-east-1") == pytest.approx(1.00) + assert _region_multiplier("eu-west-1") == pytest.approx(1.08) + assert _region_multiplier("sa-east-1") == pytest.approx(1.25) + assert _region_multiplier("ap-southeast-1") == pytest.approx(1.15) + + def test_prefix_fallback_eu(self): + """A region like eu-west-9 (fictional) should hit the eu- prefix.""" + from cloudwright.cost import _region_multiplier + + m = _region_multiplier("eu-west-9") + assert m > 1.00 # eu prefix is 1.10 + + +class TestPricingConfidence: + def test_unknown_service_marked_low_confidence(self): + from cloudwright.cost import CostEngine + + engine = CostEngine() + est = engine.estimate(_fallback_spec()) + item = est.breakdown[0] + assert item.confidence == "low" + assert item.estimated is True + + def test_unknown_service_marks_overall_low(self): + from cloudwright.cost import CostEngine + + engine = CostEngine() + est = engine.estimate(_fallback_spec()) + assert est.pricing_confidence == "low" + + def test_estimate_has_confidence_fields(self): + from cloudwright.cost import CostEngine + + engine = CostEngine() + est = engine.estimate(_simple_spec()) + assert hasattr(est, "pricing_confidence") + for item in est.breakdown: + assert item.confidence in ("high", "low") + assert isinstance(item.estimated, bool) + + def test_catalog_backed_service_confidence(self): + """ec2 with a known instance type should come from catalog (high confidence).""" + from cloudwright.cost import CostEngine + + spec = ArchSpec( + name="EC2 Test", + provider="aws", + region="us-east-1", + components=[ + Component( + id="web", + service="ec2", + provider="aws", + label="Web", + tier=2, + config={"instance_type": "t3.medium"}, + ), + ], + connections=[], + ) + engine = CostEngine() + est = engine.estimate(spec) + item = next(i for i in est.breakdown if i.component_id == "web") + # t3.medium is in the catalog — should be high confidence + assert item.confidence == "high" + assert item.estimated is False + + def test_warning_logged_for_unknown_service(self, caplog): + import logging + + from cloudwright.cost import CostEngine + + with caplog.at_level(logging.WARNING, logger="cloudwright.catalog.formula"): + engine = CostEngine() + engine.estimate(_fallback_spec()) + + assert any("definitely_unknown_service_xyz" in r.message for r in caplog.records) + + def test_mixed_spec_aggregate_confidence(self): + """A spec with one unknown and one catalog service should be low overall.""" + from cloudwright.cost import CostEngine + + spec = 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=[], + ) + engine = CostEngine() + est = engine.estimate(spec) + assert est.pricing_confidence == "low" + + +class TestCarbonEstimate: + def _simple_carbon_spec(self) -> ArchSpec: + return ArchSpec( + name="Carbon Test", + provider="aws", + region="us-east-1", + components=[ + Component(id="web", service="ec2", provider="aws", label="Web", tier=2, config={}), + Component(id="db", service="rds", provider="aws", label="DB", tier=3, config={}), + ], + connections=[], + ) + + def test_total_is_positive(self): + from cloudwright.carbon import estimate_carbon + + result = estimate_carbon(self._simple_carbon_spec()) + assert result["total_kg_co2e_per_month"] > 0 + + def test_scales_with_component_count(self): + from cloudwright.carbon import estimate_carbon + + one = ArchSpec( + name="One", + provider="aws", + region="us-east-1", + components=[ + Component(id="w", service="ec2", provider="aws", label="W", tier=2, config={}), + ], + connections=[], + ) + two = ArchSpec( + name="Two", + provider="aws", + region="us-east-1", + components=[ + Component(id="w", service="ec2", provider="aws", label="W", tier=2, config={}), + Component(id="d", service="rds", provider="aws", label="D", tier=3, config={}), + ], + connections=[], + ) + r1 = estimate_carbon(one) + r2 = estimate_carbon(two) + assert r2["total_kg_co2e_per_month"] > r1["total_kg_co2e_per_month"] + + def test_breakdown_length_matches_components(self): + from cloudwright.carbon import estimate_carbon + + result = estimate_carbon(self._simple_carbon_spec()) + assert len(result["breakdown"]) == 2 + + def test_breakdown_has_required_fields(self): + from cloudwright.carbon import estimate_carbon + + result = estimate_carbon(self._simple_carbon_spec()) + for item in result["breakdown"]: + assert "component_id" in item + assert "service" in item + assert "kg_co2e_per_month" in item + + def test_virtual_component_is_zero(self): + from cloudwright.carbon import estimate_carbon + + spec = ArchSpec( + name="Virtual", + provider="aws", + region="us-east-1", + components=[ + Component(id="users", service="users", provider="aws", label="Users", tier=0, config={}), + ], + connections=[], + ) + result = estimate_carbon(spec) + assert result["total_kg_co2e_per_month"] == 0.0 + + def test_high_carbon_region_costs_more(self): + """ap-south-1 (Mumbai) has higher grid intensity than us-west-2 (Oregon).""" + from cloudwright.carbon import estimate_carbon + + spec_clean = ArchSpec( + name="Clean", + provider="aws", + region="us-west-2", + components=[ + Component(id="w", service="ec2", provider="aws", label="W", tier=2, config={}), + ], + connections=[], + ) + spec_dirty = spec_clean.model_copy(update={"region": "ap-south-1", "name": "Dirty"}) + + clean = estimate_carbon(spec_clean) + dirty = estimate_carbon(spec_dirty) + assert dirty["total_kg_co2e_per_month"] > clean["total_kg_co2e_per_month"] + + def test_assumptions_dict_present(self): + from cloudwright.carbon import estimate_carbon + + result = estimate_carbon(self._simple_carbon_spec()) + assert "assumptions" in result + assert "pue" in result["assumptions"] + assert "disclaimer" in result["assumptions"] + + def test_empty_spec_returns_zero(self): + from cloudwright.carbon import estimate_carbon + + spec = ArchSpec(name="Empty", provider="aws", region="us-east-1", components=[], connections=[]) + result = estimate_carbon(spec) + assert result["total_kg_co2e_per_month"] == 0.0 + + +class TestFocusCsv: + def _sample_estimate(self): + from cloudwright.cost import CostEngine + + spec = ArchSpec( + name="FOCUS Test", + 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="store", + service="s3", + provider="aws", + label="Storage", + tier=4, + config={"storage_gb": 100}, + ), + ], + connections=[ + Connection(source="web", target="store", estimated_monthly_gb=50.0), + ], + ) + return CostEngine().estimate(spec) + + def test_csv_has_focus_headers(self): + from cloudwright.focus import _FOCUS_COLUMNS, to_focus_csv + + csv_text = to_focus_csv(self._sample_estimate()) + reader = csv.DictReader(io.StringIO(csv_text)) + for col in _FOCUS_COLUMNS: + assert col in (reader.fieldnames or []), f"Missing FOCUS column: {col}" + + def test_one_row_per_component(self): + from cloudwright.focus import to_focus_csv + + est = self._sample_estimate() + csv_text = to_focus_csv(est) + rows = list(csv.DictReader(io.StringIO(csv_text))) + # 2 components + 1 data transfer row + assert len(rows) == 3 + + def test_data_transfer_row_present(self): + from cloudwright.focus import to_focus_csv + + csv_text = to_focus_csv(self._sample_estimate()) + rows = list(csv.DictReader(io.StringIO(csv_text))) + services = [r["ServiceName"] for r in rows] + assert "DataTransfer" in services + + def test_billed_cost_matches_estimate(self): + from cloudwright.focus import to_focus_csv + + est = self._sample_estimate() + csv_text = to_focus_csv(est) + rows = list(csv.DictReader(io.StringIO(csv_text))) + total_billed = sum(float(r["BilledCost"]) for r in rows) + assert total_billed == pytest.approx(est.monthly_total, rel=1e-3) + + def test_billing_currency_is_usd(self): + from cloudwright.focus import to_focus_csv + + csv_text = to_focus_csv(self._sample_estimate()) + rows = list(csv.DictReader(io.StringIO(csv_text))) + assert all(r["BillingCurrency"] == "USD" for r in rows) + + def test_charge_period_start_before_end(self): + from cloudwright.focus import to_focus_csv + + csv_text = to_focus_csv(self._sample_estimate()) + rows = list(csv.DictReader(io.StringIO(csv_text))) + for row in rows: + assert row["ChargePeriodStart"] <= row["ChargePeriodEnd"] + + def test_resource_id_matches_component_id(self): + from cloudwright.focus import to_focus_csv + + est = self._sample_estimate() + csv_text = to_focus_csv(est) + rows = list(csv.DictReader(io.StringIO(csv_text))) + component_ids = {r["ResourceId"] for r in rows if r["ServiceName"] != "DataTransfer"} + expected = {item.component_id for item in est.breakdown} + assert component_ids == expected + + def test_no_data_transfer_row_when_zero(self): + """If there's no egress, no DataTransfer row should appear.""" + from cloudwright.cost import CostEngine + from cloudwright.focus import to_focus_csv + + spec = ArchSpec( + name="No Egress", + provider="aws", + region="us-east-1", + components=[ + Component(id="w", service="ec2", provider="aws", label="W", tier=2, config={}), + ], + connections=[], + ) + est = CostEngine().estimate(spec) + csv_text = to_focus_csv(est) + rows = list(csv.DictReader(io.StringIO(csv_text))) + assert all(r["ServiceName"] != "DataTransfer" for r in rows) + + def test_pricing_confidence_column_present(self): + from cloudwright.focus import to_focus_csv + + csv_text = to_focus_csv(self._sample_estimate()) + rows = list(csv.DictReader(io.StringIO(csv_text))) + for row in rows: + assert row["PricingConfidence"] in ("high", "low") diff --git a/packages/core/tests/test_critique.py b/packages/core/tests/test_critique.py new file mode 100644 index 0000000..5b3be96 --- /dev/null +++ b/packages/core/tests/test_critique.py @@ -0,0 +1,118 @@ +"""v1.6.0 generate -> critique -> repair loop.""" + +from cloudwright.critique import CritiqueFinding, CritiqueReport, critique +from cloudwright.designer import Architect +from cloudwright.spec import ArchSpec, Component + + +def _flawed_spec() -> ArchSpec: + # A bare public-ish DB + compute with none of the safety scaffolding: this + # trips multiple linter rules (no monitoring, no LB, no backup, ...). + return 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), + ], + ) + + +class TestCritiqueDeterministic: + def test_returns_score_grade_findings(self): + report = critique(_flawed_spec()) + assert 0 <= report.score <= 100 + assert report.grade in {"A", "B", "C", "D", "F"} + assert report.findings, "a bare 2-component spec should surface lint findings" + # findings are severity-ranked (criticals/highs first) + order = {"critical": 0, "high": 1, "medium": 2, "low": 3} + sevs = [order.get(f.severity, 4) for f in report.findings] + assert sevs == sorted(sevs) + + def test_blocking_is_high_and_critical_only(self): + report = critique(_flawed_spec()) + assert all(f.severity in ("critical", "high") for f in report.blocking) + + def test_compliance_findings_included(self): + report = critique(_flawed_spec(), compliance=["hipaa"]) + assert any(f.source == "validator" for f in report.findings) + + def test_as_dict_shape(self): + d = critique(_flawed_spec()).as_dict() + assert {"score", "grade", "findings", "blocking_count", "summary"} <= set(d) + + +class _FakeLLM: + model_name = "fake" + pricing = {"input": 0.0, "output": 0.0} + + def __init__(self): + self.calls = 0 + + def generate_fast(self, messages, system, max_tokens=0): + self.calls += 1 + repaired = ( + '{"name":"repaired","components":[' + '{"id":"web","service":"ec2","provider":"aws","label":"Web","tier":2},' + '{"id":"mon","service":"cloudwatch","provider":"aws","label":"Monitoring","tier":1}' + "]}" + ) + return repaired, {"input_tokens": 10, "output_tokens": 20, "model": "fake"} + + +class TestRepairLoop: + def test_repair_runs_when_blocking_and_keeps_better_spec(self, monkeypatch): + import cloudwright.critique as crit + + before = CritiqueReport( + score=40.0, + grade="F", + findings=[ + CritiqueFinding("high", "linter", "no_monitoring", "No monitoring"), + CritiqueFinding("high", "linter", "no_backup", "No backup"), + ], + ) + after = CritiqueReport(score=80.0, grade="B", findings=[]) + reports = iter([before, after]) + monkeypatch.setattr(crit, "critique", lambda *a, **k: next(reports)) + + arch = Architect(llm=_FakeLLM(), repair=True, max_repair_iters=1) + out = arch._critique_repair(_flawed_spec(), "web app", None) + + meta = out.metadata["critique"] + assert meta["blocking_before"] == 2 + assert meta["repair_iterations"] == 1 + assert meta["blocking_after"] == 0 + assert out.name == "repaired" # the better spec was kept + + def test_no_repair_when_no_blocking(self, monkeypatch): + import cloudwright.critique as crit + + clean = CritiqueReport(score=90.0, grade="A", findings=[]) + monkeypatch.setattr(crit, "critique", lambda *a, **k: clean) + + llm = _FakeLLM() + arch = Architect(llm=llm, repair=True) + out = arch._critique_repair(_flawed_spec(), "web app", None) + + assert llm.calls == 0 # no LLM repair call when nothing is blocking + assert out.metadata["critique"]["repair_iterations"] == 0 + + def test_repair_kept_only_if_not_worse(self, monkeypatch): + import cloudwright.critique as crit + + before = CritiqueReport(score=40.0, grade="F", findings=[CritiqueFinding("high", "linter", "x", "X")]) + worse = CritiqueReport( + score=20.0, + grade="F", + findings=[ + CritiqueFinding("high", "linter", "x", "X"), + CritiqueFinding("critical", "linter", "y", "Y"), + ], + ) + reports = iter([before, worse]) + monkeypatch.setattr(crit, "critique", lambda *a, **k: next(reports)) + + arch = Architect(llm=_FakeLLM(), repair=True, max_repair_iters=1) + original = _flawed_spec() + out = arch._critique_repair(original, "web app", None) + assert out.name == "flawed" # regressed repair discarded diff --git a/packages/core/tests/test_oscal.py b/packages/core/tests/test_oscal.py new file mode 100644 index 0000000..e2e7921 --- /dev/null +++ b/packages/core/tests/test_oscal.py @@ -0,0 +1,136 @@ +from __future__ import annotations + +from cloudwright.compliance import ComplianceScanner +from cloudwright.oscal import to_oscal +from cloudwright.spec import ArchSpec, Component, Constraints + + +def _component(id: str, service: str, config: dict | None = None, tier: int = 2) -> Component: + return Component(id=id, service=service, provider="aws", label=id, tier=tier, config=config or {}) + + +def _spec(components, compliance: list[str] | None = None) -> ArchSpec: + return ArchSpec( + name="Test", + provider="aws", + region="us-east-1", + constraints=Constraints(compliance=compliance or []), + components=components, + ) + + +class TestToOscalStructure: + def test_returns_component_definition(self): + spec = _spec([_component("db", "rds")], ["HIPAA"]) + report = ComplianceScanner().scan(spec, frameworks=["HIPAA"], run_checkov=False) + doc = to_oscal(spec, report, ["HIPAA"]) + assert "component-definition" in doc + + def test_metadata_oscal_version(self): + spec = _spec([_component("db", "rds")], ["HIPAA"]) + report = ComplianceScanner().scan(spec, frameworks=["HIPAA"], run_checkov=False) + doc = to_oscal(spec, report, ["HIPAA"]) + assert doc["component-definition"]["metadata"]["oscal-version"] == "1.1.2" + + def test_metadata_version(self): + spec = _spec([_component("db", "rds")], ["HIPAA"]) + report = ComplianceScanner().scan(spec, frameworks=["HIPAA"], run_checkov=False) + doc = to_oscal(spec, report, ["HIPAA"]) + assert doc["component-definition"]["metadata"]["version"] == "1.6.0" + + def test_uuid_present(self): + spec = _spec([_component("db", "rds")], ["HIPAA"]) + report = ComplianceScanner().scan(spec, frameworks=["HIPAA"], run_checkov=False) + doc = to_oscal(spec, report, ["HIPAA"]) + assert doc["component-definition"]["uuid"] + + def test_components_length_matches_spec(self): + components = [ + _component("web", "ec2"), + _component("db", "rds", {"backup": True, "multi_az": True}, tier=3), + _component("cache", "elasticache"), + ] + spec = _spec(components, ["HIPAA"]) + report = ComplianceScanner().scan(spec, frameworks=["HIPAA"], run_checkov=False) + doc = to_oscal(spec, report, ["HIPAA"]) + assert len(doc["component-definition"]["components"]) == len(spec.components) + + +class TestDeterministicUuid: + def test_uuid_stable_across_calls(self): + spec = _spec([_component("db", "rds")], ["HIPAA"]) + report = ComplianceScanner().scan(spec, frameworks=["HIPAA"], run_checkov=False) + doc1 = to_oscal(spec, report, ["HIPAA"]) + doc2 = to_oscal(spec, report, ["HIPAA"]) + assert doc1["component-definition"]["uuid"] == doc2["component-definition"]["uuid"] + + def test_uuid_differs_for_different_spec_names(self): + spec_a = ArchSpec(name="Alpha", provider="aws", components=[_component("db", "rds")]) + spec_b = ArchSpec(name="Beta", provider="aws", components=[_component("db", "rds")]) + report_a = ComplianceScanner().scan(spec_a, frameworks=["HIPAA"], run_checkov=False) + report_b = ComplianceScanner().scan(spec_b, frameworks=["HIPAA"], run_checkov=False) + doc_a = to_oscal(spec_a, report_a, ["HIPAA"]) + doc_b = to_oscal(spec_b, report_b, ["HIPAA"]) + assert doc_a["component-definition"]["uuid"] != doc_b["component-definition"]["uuid"] + + def test_uuid_differs_for_different_frameworks(self): + spec = _spec([_component("db", "rds")], ["HIPAA"]) + report = ComplianceScanner().scan(spec, frameworks=["HIPAA"], run_checkov=False) + doc_hipaa = to_oscal(spec, report, ["HIPAA"]) + doc_fedramp = to_oscal(spec, report, ["FedRAMP"]) + assert doc_hipaa["component-definition"]["uuid"] != doc_fedramp["component-definition"]["uuid"] + + +class TestNotSatisfiedFindings: + def test_hipaa_unencrypted_store_yields_not_satisfied(self): + # RDS without encryption flag triggers missing_encryption -> HIPAA 164.312(a)(2)(iv) + spec = _spec([_component("db", "rds", {"backup": True, "multi_az": True}, tier=3)], ["HIPAA"]) + report = ComplianceScanner().scan(spec, frameworks=["HIPAA"], run_checkov=False) + + doc = to_oscal(spec, report, ["HIPAA"]) + components = doc["component-definition"]["components"] + + # Collect all implemented-requirements across all components + all_reqs = [] + for comp in components: + for impl in comp.get("control-implementations", []): + all_reqs.extend(impl.get("implemented-requirements", [])) + + not_satisfied = [r for r in all_reqs if r["implementation-status"]["state"] == "not-satisfied"] + assert not_satisfied, "expected at least one not-satisfied requirement" + + # The encryption control for HIPAA should appear + control_ids = {r["control-id"] for r in not_satisfied} + # HIPAA control kept verbatim (not NIST-shaped) + assert "164.312(a)(2)(iv)" in control_ids + + def test_fedramp_control_ids_lowercased(self): + spec = _spec([_component("db", "rds", {"backup": True, "multi_az": True}, tier=3)], ["FedRAMP"]) + report = ComplianceScanner().scan(spec, frameworks=["FedRAMP"], run_checkov=False) + doc = to_oscal(spec, report, ["FedRAMP"]) + + all_reqs = [] + for comp in doc["component-definition"]["components"]: + for impl in comp.get("control-implementations", []): + all_reqs.extend(impl.get("implemented-requirements", [])) + + # FedRAMP is NIST-shaped so SC-28 should become sc-28 + control_ids = {r["control-id"] for r in all_reqs} + assert "sc-28" in control_ids + assert "SC-28" not in control_ids + + def test_clean_spec_has_no_not_satisfied(self): + spec = _spec( + [_component("db", "rds", {"encryption": True, "backup": True, "multi_az": True}, tier=3)], + ["HIPAA"], + ) + report = ComplianceScanner().scan(spec, frameworks=["HIPAA"], run_checkov=False) + doc = to_oscal(spec, report, ["HIPAA"]) + + all_reqs = [] + for comp in doc["component-definition"]["components"]: + for impl in comp.get("control-implementations", []): + all_reqs.extend(impl.get("implemented-requirements", [])) + + not_satisfied = [r for r in all_reqs if r["implementation-status"]["state"] == "not-satisfied"] + assert not_satisfied == [] diff --git a/packages/core/tests/test_patterns.py b/packages/core/tests/test_patterns.py new file mode 100644 index 0000000..734edc3 --- /dev/null +++ b/packages/core/tests/test_patterns.py @@ -0,0 +1,93 @@ +"""Tests for cloudwright.patterns — no LLM or cloud calls.""" + +from __future__ import annotations + +from cloudwright.patterns import suggest_compliant_patterns + + +def test_hipaa_returns_at_least_one_pattern(): + results = suggest_compliant_patterns("hipaa") + assert len(results) >= 1 + + +def test_hipaa_patterns_all_include_hipaa(): + results = suggest_compliant_patterns("hipaa") + for pattern in results: + assert "hipaa" in pattern["frameworks"], f"{pattern['name']} missing hipaa in frameworks" + + +def test_soc2_returns_at_least_one_pattern(): + results = suggest_compliant_patterns("soc2") + assert len(results) >= 1 + + +def test_soc2_patterns_all_include_soc2(): + results = suggest_compliant_patterns("soc2") + for pattern in results: + assert "soc2" in pattern["frameworks"] + + +def test_pci_dss_returns_at_least_one_pattern(): + results = suggest_compliant_patterns("pci-dss") + assert len(results) >= 1 + + +def test_pci_dss_patterns_all_include_pci_dss(): + results = suggest_compliant_patterns("pci-dss") + for pattern in results: + assert "pci-dss" in pattern["frameworks"] + + +def test_fedramp_returns_at_least_one_pattern(): + results = suggest_compliant_patterns("fedramp") + assert len(results) >= 1 + + +def test_iso27001_returns_at_least_one_pattern(): + results = suggest_compliant_patterns("iso27001") + assert len(results) >= 1 + + +def test_gdpr_returns_at_least_one_pattern(): + results = suggest_compliant_patterns("gdpr") + assert len(results) >= 1 + + +def test_unknown_framework_returns_empty(): + assert suggest_compliant_patterns("unknown-framework") == [] + assert suggest_compliant_patterns("") == [] + assert suggest_compliant_patterns("sox") == [] + + +def test_result_dict_has_required_keys(): + results = suggest_compliant_patterns("soc2") + for pattern in results: + assert "name" in pattern + assert "source" in pattern + assert "frameworks" in pattern + assert "why" in pattern + assert isinstance(pattern["frameworks"], list) + assert isinstance(pattern["why"], str) + assert len(pattern["why"]) > 0 + + +def test_results_ranked_by_coverage_breadth(): + # Patterns with more frameworks should appear first + results = suggest_compliant_patterns("soc2") + if len(results) >= 2: + first_count = len(results[0]["frameworks"]) + last_count = len(results[-1]["frameworks"]) + assert first_count >= last_count + + +def test_case_insensitive_lookup(): + lower = suggest_compliant_patterns("hipaa") + upper = suggest_compliant_patterns("HIPAA") + mixed = suggest_compliant_patterns("HiPaA") + assert lower == upper == mixed + + +def test_source_field_has_expected_prefix(): + for fw in ("hipaa", "soc2", "pci-dss", "fedramp", "iso27001", "gdpr"): + for pattern in suggest_compliant_patterns(fw): + assert pattern["source"].startswith(("template:", "module:")) diff --git a/packages/core/tests/test_remediation.py b/packages/core/tests/test_remediation.py new file mode 100644 index 0000000..941a95d --- /dev/null +++ b/packages/core/tests/test_remediation.py @@ -0,0 +1,129 @@ +"""Tests for cloudwright.remediation — no real LLM, cloud, or terraform calls. + +The plan step shells out to terraform/tofu (slow + network), so these tests use +skip_plan=True or monkeypatch the planner; one fast path exercises the +binary-absent branch directly. +""" + +from __future__ import annotations + +from cloudwright.remediation import remediate +from cloudwright.spec import ArchSpec, Component, Connection + + +def _small_spec() -> ArchSpec: + return ArchSpec( + name="Small", + provider="aws", + region="us-east-1", + components=[ + Component( + id="web", service="ec2", provider="aws", label="Web", tier=2, config={"instance_type": "t3.micro"} + ), + ], + ) + + +def _large_spec() -> ArchSpec: + return ArchSpec( + name="Large", + provider="aws", + region="us-east-1", + components=[ + Component( + id="web", + service="ec2", + provider="aws", + label="Web", + tier=2, + config={"instance_type": "m5.large", "count": 3}, + ), + Component( + id="db", + service="rds", + provider="aws", + label="DB", + tier=3, + config={ + "engine": "postgres", + "instance_class": "db.r5.large", + "multi_az": True, + "allocated_storage": 500, + }, + ), + Component( + id="cache", + service="elasticache", + provider="aws", + label="Cache", + tier=3, + config={"node_type": "cache.r5.large", "engine": "redis"}, + ), + ], + connections=[ + Connection(source="web", target="db", label="SQL", protocol="TCP", port=5432), + Connection(source="web", target="cache", label="Redis", protocol="TCP", port=6379), + ], + ) + + +def test_remediate_returns_required_keys(): + result = remediate(_small_spec(), _large_spec(), skip_plan=True) + assert {"drift", "cost_delta", "quality_delta", "plan", "summary"} <= set(result) + + +def test_remediate_drift_reflects_differences(): + result = remediate(_small_spec(), _large_spec(), skip_plan=True) + assert "add" in {item["change"] for item in result["drift"]} + + +def test_remediate_cost_delta_positive_for_larger_desired(): + cd = remediate(_small_spec(), _large_spec(), skip_plan=True)["cost_delta"] + assert cd["desired"] > cd["current"] + assert cd["delta"] > 0 + assert cd["currency"] == "USD" + + +def test_remediate_quality_delta_keys(): + qd = remediate(_small_spec(), _large_spec(), skip_plan=True)["quality_delta"] + assert {"current", "desired", "delta", "current_grade", "desired_grade"} <= set(qd) + + +def test_remediate_plan_keys_with_mocked_planner(monkeypatch): + from cloudwright import planner + from cloudwright.planner import PlanResult + + stub = PlanResult(tool="terraform", available=True, validated=True, plan_ran=False, ok=True, messages=["stub"]) + monkeypatch.setattr(planner, "plan_terraform", lambda spec, **k: stub) + plan = remediate(_small_spec(), _large_spec())["plan"] + assert {"tool", "available", "validated", "ok", "messages"} <= set(plan) + assert plan["validated"] is True + + +def test_remediate_no_raise_when_terraform_absent(monkeypatch): + # binary-absent branch is fast (no subprocess); plan reflects unavailability. + import shutil + + original = shutil.which + + def patched_which(name, *a, **k): + if name in ("terraform", "tofu"): + return None + return original(name, *a, **k) + + monkeypatch.setattr(shutil, "which", patched_which) + result = remediate(_small_spec(), _large_spec()) + assert result["plan"]["available"] is False + assert result["summary"] + + +def test_remediate_identical_specs_no_drift(): + spec = _small_spec() + result = remediate(spec, spec, skip_plan=True) + assert result["drift"] == [] + assert result["cost_delta"]["delta"] == 0.0 + + +def test_remediate_summary_is_string(): + result = remediate(_small_spec(), _large_spec(), skip_plan=True) + assert isinstance(result["summary"], str) and result["summary"] diff --git a/packages/core/tests/test_two_stage_prompting.py b/packages/core/tests/test_two_stage_prompting.py index 8a68ec4..3bb3d2f 100644 --- a/packages/core/tests/test_two_stage_prompting.py +++ b/packages/core/tests/test_two_stage_prompting.py @@ -95,7 +95,9 @@ def test_stage2_returns_valid_json(self): def test_design_calls_both_stages(self): llm = _two_stage_mock_llm() - architect = Architect(llm=llm, two_stage=True) + # repair=False isolates the two-stage call pattern; the v1.6 critique/repair + # loop (which can add a generate_fast call) is covered by test_critique.py. + architect = Architect(llm=llm, two_stage=True, repair=False) spec = architect.design("Build a serverless orders API on AWS") @@ -138,7 +140,7 @@ def test_design_falls_back_to_single_shot_when_disabled(self): {"input_tokens": 800, "output_tokens": 600, "model": "claude-sonnet-4-6"}, ) - architect = Architect(llm=llm, two_stage=False) + architect = Architect(llm=llm, two_stage=False, repair=False) spec = architect.design("Build a serverless orders API on AWS") assert llm.generate.call_count == 1 diff --git a/packages/core/tests/test_v160_hardening.py b/packages/core/tests/test_v160_hardening.py new file mode 100644 index 0000000..06321eb --- /dev/null +++ b/packages/core/tests/test_v160_hardening.py @@ -0,0 +1,130 @@ +"""v1.6.0 Tier-0 credibility hardening regressions. + +Covers: Terraform exporter injection hardening (numeric coercion + validator), +the WAF multi-line fix, the compliance-overrides-workload-profile invariant, and +the `cloudwright plan` subprocess secret scoping. +""" + +import pytest +from cloudwright.exporter import export_spec, validate_export_config +from cloudwright.exporter.terraform.common import _hcl_num +from cloudwright.parsing import _profile_requires_encryption, _profile_requires_ha +from cloudwright.spec import ArchSpec, Component, Constraints + + +def _spec(component: Component, **meta) -> ArchSpec: + return ArchSpec(name="t", components=[component], metadata=meta) + + +class TestNumericCoercion: + def test_int_string_coerced(self): + assert _hcl_num("20", 20) == "20" + + def test_real_int_passthrough(self): + assert _hcl_num(50, 20) == "50" + + def test_uncoercible_falls_back_to_default(self): + assert _hcl_num("100abc", 20) == "20" + assert _hcl_num(None, 7) == "7" + assert _hcl_num({"x": 1}, 3) == "3" + + def test_float_truncated_when_int_required(self): + assert _hcl_num("20.9", 20) == "20" + + +class TestExportValidator: + def test_rejects_newline_brace_injection(self): + payload = '20\n provisioner "local-exec" {\n command = "id"\n }' + with pytest.raises(ValueError): + validate_export_config({"allocated_storage": payload}) + + def test_rejects_bare_braces(self): + with pytest.raises(ValueError): + validate_export_config({"x": "a{b}"}) + + def test_allows_clean_scalar(self): + validate_export_config({"engine": "postgres", "instance_class": "db.t3.medium"}) + + +class TestExporterInjectionProof: + def test_string_numeric_field_is_coerced_not_injected(self): + # A string value that survives the validator (no metachars) must still be + # emitted as a number, never as raw HCL. + spec = _spec( + Component( + id="db", + service="rds", + provider="aws", + label="DB", + tier=3, + config={"engine": "postgres", "allocated_storage": "9999"}, + ) + ) + tf = export_spec(spec, "terraform") + assert "allocated_storage = 9999" in tf + assert "provisioner" not in tf + assert "local-exec" not in tf + + def test_waf_default_action_is_multiline(self): + spec = _spec(Component(id="acl", service="waf", provider="aws", label="ACL", tier=1)) + tf = export_spec(spec, "terraform") + # single-line nested block is what Terraform rejects + assert "default_action { allow {} }" not in tf + assert "default_action {\n allow {}" in tf + + +class TestComplianceOverridesProfile: + def test_sandbox_plus_hipaa_forces_encryption_and_ha(self): + spec = _spec( + Component(id="db", service="rds", provider="aws", label="DB", tier=3), + workload_profile="sandbox", + ) + c = Constraints(compliance=["hipaa"]) + assert _profile_requires_encryption(spec, c) is True + assert _profile_requires_ha(spec, c) is True + + def test_plain_sandbox_does_not_force(self): + spec = _spec( + Component(id="db", service="rds", provider="aws", label="DB", tier=3), + workload_profile="sandbox", + ) + c = Constraints(compliance=[]) + assert _profile_requires_encryption(spec, c) is False + assert _profile_requires_ha(spec, c) is False + + +class TestOpenTofuParity: + def test_opentofu_format_matches_terraform(self): + spec = _spec(Component(id="web", service="ec2", provider="aws", label="Web", tier=2)) + assert export_spec(spec, "opentofu") == export_spec(spec, "terraform") + assert export_spec(spec, "tofu") == export_spec(spec, "terraform") + + def test_binary_resolution_prefers_override(self, monkeypatch, tmp_path): + from cloudwright import planner + + fake = tmp_path / "tofu" + fake.write_text("#!/bin/sh\n") + fake.chmod(0o755) + monkeypatch.setenv("CLOUDWRIGHT_TF_BINARY", str(fake)) + path, label = planner._terraform_binary() + assert label == "opentofu" + assert path == str(fake) + + +class TestPlanSecretScoping: + def test_subprocess_env_strips_llm_key(self, monkeypatch): + from cloudwright import planner + + monkeypatch.setenv("ANTHROPIC_API_KEY", "sk-ant-secret-value-1234") + monkeypatch.setenv("AWS_ACCESS_KEY_ID", "AKIAEXAMPLE") + env = planner._subprocess_env() + assert "ANTHROPIC_API_KEY" not in env + assert env.get("AWS_ACCESS_KEY_ID") == "AKIAEXAMPLE" + + def test_scrub_redacts_secret_values(self, monkeypatch): + from cloudwright import planner + + monkeypatch.setenv("AWS_SECRET_ACCESS_KEY", "verylongsecretvalue0987654321") + out = planner._scrub("error using verylongsecretvalue0987654321 to auth") + assert "verylongsecretvalue0987654321" not in out + assert "REDACTED" in out diff --git a/packages/core/tests/test_v160_traceability.py b/packages/core/tests/test_v160_traceability.py new file mode 100644 index 0000000..d78a3ba --- /dev/null +++ b/packages/core/tests/test_v160_traceability.py @@ -0,0 +1,35 @@ +"""v1.6.0 control traceability chain.""" + +from cloudwright.compliance import ComplianceScanner, build_traceability +from cloudwright.spec import ArchSpec, Component + + +def _hipaa_spec() -> ArchSpec: + return ArchSpec( + name="trace", + components=[ + Component(id="db", service="rds", provider="aws", label="Patient DB", tier=3, config={}), + ], + metadata={"compliance": ["hipaa"]}, + ) + + +def test_traceability_links_component_resource_control(): + spec = _hipaa_spec() + report = ComplianceScanner().scan(spec, frameworks=["hipaa"], run_checkov=False) + chain = build_traceability(spec, report) + assert chain, "an unencrypted HIPAA DB should produce at least one finding chain" + db_rows = [r for r in chain if r["component_id"] == "db"] + assert db_rows + row = db_rows[0] + assert row["service"] == "rds" + assert row["resource_type"] == "aws_db_instance" # mapped via the exporter resource map + assert row["status"] == "violated" + + +def test_traceability_entries_carry_controls(): + spec = _hipaa_spec() + report = ComplianceScanner().scan(spec, frameworks=["hipaa"], run_checkov=False) + chain = build_traceability(spec, report) + # at least one chain entry references a framework control id + assert any(r["controls"] for r in chain) diff --git a/packages/mcp/cloudwright_mcp/__init__.py b/packages/mcp/cloudwright_mcp/__init__.py index 5b60188..e4adfb8 100644 --- a/packages/mcp/cloudwright_mcp/__init__.py +++ b/packages/mcp/cloudwright_mcp/__init__.py @@ -1 +1 @@ -__version__ = "1.5.0" +__version__ = "1.6.0" diff --git a/packages/web/cloudwright_web/__init__.py b/packages/web/cloudwright_web/__init__.py index 3b54a17..91db08f 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.5.0" +__version__ = "1.6.0" def __getattr__(name: str): diff --git a/packages/web/cloudwright_web/static/assets/index-C9JIGemf.js b/packages/web/cloudwright_web/static/assets/index-C9JIGemf.js deleted file mode 100644 index b1d9e0b..0000000 --- a/packages/web/cloudwright_web/static/assets/index-C9JIGemf.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 ep(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var tp={exports:{}},Ns={},np={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"),cy=Symbol.for("react.portal"),dy=Symbol.for("react.fragment"),fy=Symbol.for("react.strict_mode"),py=Symbol.for("react.profiler"),hy=Symbol.for("react.provider"),gy=Symbol.for("react.context"),my=Symbol.for("react.forward_ref"),yy=Symbol.for("react.suspense"),xy=Symbol.for("react.memo"),vy=Symbol.for("react.lazy"),jc=Symbol.iterator;function wy(e){return e===null||typeof e!="object"?null:(e=jc&&e[jc]||e["@@iterator"],typeof e=="function"?e:null)}var rp={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},op=Object.assign,ip={};function br(e,t,n){this.props=e,this.context=t,this.refs=ip,this.updater=n||rp}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 sp(){}sp.prototype=br.prototype;function su(e,t,n){this.props=e,this.context=t,this.refs=ip,this.updater=n||rp}var lu=su.prototype=new sp;lu.constructor=su;op(lu,br.prototype);lu.isPureReactComponent=!0;var Mc=Array.isArray,lp=Object.prototype.hasOwnProperty,au={current:null},ap={key:!0,ref:!0,__self:!0,__source:!0};function up(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)lp.call(t,r)&&!ap.hasOwnProperty(r)&&(o[r]=t[r]);var l=arguments.length-2;if(l===1)o.children=n;else if(1>>1,B=b[O];if(0>>1;Oo(Y,$))Xo(Q,Y)?(b[O]=Q,b[X]=$,O=X):(b[O]=Y,b[V]=$,O=V);else if(Xo(Q,$))b[O]=Q,b[X]=$,O=X;else break e}}return N}function o(b,N){var $=b.sortIndex-N.sortIndex;return $!==0?$:b.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,d=3,x=!1,y=!1,w=!1,_=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(b){for(var N=n(u);N!==null;){if(N.callback===null)r(u);else if(N.startTime<=b)r(u),N.sortIndex=N.expirationTime,t(a,N);else break;N=n(u)}}function v(b){if(w=!1,h(b),!y)if(n(a)!==null)y=!0,P(S);else{var N=n(u);N!==null&&L(v,N.startTime-b)}}function S(b,N){y=!1,w&&(w=!1,m(j),j=-1),x=!0;var $=d;try{for(h(N),c=n(a);c!==null&&(!(c.expirationTime>N)||b&&!z());){var O=c.callback;if(typeof O=="function"){c.callback=null,d=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&&L(v,V.startTime-N),W=!1}return W}finally{c=null,d=$,x=!1}}var k=!1,C=null,j=-1,I=5,A=-1;function z(){return!(e.unstable_now()-Ab||125O?(b.sortIndex=$,t(u,b),n(a)===null&&b===n(u)&&(w?(m(j),j=-1):w=!0,L(v,$-O))):(b.sortIndex=B,t(a,b),y||x||(y=!0,P(S))),b},e.unstable_shouldYield=z,e.unstable_wrapCallback=function(b){var N=d;return function(){var $=d;d=N;try{return b.apply(this,arguments)}finally{d=$}}}})(gp);hp.exports=gp;var Py=hp.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 Ty=M,Xe=Py;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,Iy=/^[: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]*$/,Pc={},Tc={};function Ry(e){return ql.call(Tc,e)?!0:ql.call(Pc,e)?!1:Iy.test(e)?Tc[e]=!0:(Pc[e]=!0,!1)}function Ly(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 Ay(e,t,n,r){if(t===null||typeof t>"u"||Ly(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 cu=/[\-:]([a-z])/g;function du(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(cu,du);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(cu,du);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(cu,du);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 fu(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{ll=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?Xr(e):""}function $y(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=al(e.type,!1),e;case 11:return e=al(e.type.render,!1),e;case 1:return e=al(e.type,!0),e;default:return""}}function ta(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 Zl:return"Profiler";case pu:return"StrictMode";case Jl:return"Suspense";case ea:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case xp:return(e.displayName||"Context")+".Consumer";case yp:return(e._context.displayName||"Context")+".Provider";case hu:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case gu:return t=e.displayName||null,t!==null?t:ta(e.type)||"Memo";case Xt:t=e._payload,e=e._init;try{return ta(e(t))}catch{}}return null}function Dy(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 ta(t);case 8:return t===pu?"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 wp(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function Oy(e){var t=wp(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 Jo(e){e._valueTracker||(e._valueTracker=Oy(e))}function Sp(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=wp(e)?e.checked?"true":"false":e.value),e=r,e!==n?(t.setValue(e),!0):!1}function Yi(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 na(e,t){var n=t.checked;return me({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:n??e._wrapperState.initialChecked})}function Rc(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 kp(e,t){t=t.checked,t!=null&&fu(e,"checked",t,!1)}function ra(e,t){kp(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")?oa(e,t.type,n):t.hasOwnProperty("defaultValue")&&oa(e,t.type,cn(t.defaultValue)),t.checked==null&&t.defaultChecked!=null&&(e.defaultChecked=!!t.defaultChecked)}function Lc(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 oa(e,t,n){(t!=="number"||Yi(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=ei.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},By=["Webkit","ms","Moz","O"];Object.keys(Jr).forEach(function(e){By.forEach(function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),Jr[t]=Jr[e]})});function bp(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 Np(e,t){e=e.style;for(var n in t)if(t.hasOwnProperty(n)){var r=n.indexOf("--")===0,o=bp(n,t[n],r);n==="float"&&(n="cssFloat"),r?e.setProperty(n,o):e[n]=o}}var Fy=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 la(e,t){if(t){if(Fy[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 aa(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 ua=null;function mu(e){return e=e.target||e.srcElement||window,e.correspondingUseElement&&(e=e.correspondingUseElement),e.nodeType===3?e.parentNode:e}var ca=null,or=null,ir=null;function Dc(e){if(e=Fo(e)){if(typeof ca!="function")throw Error(F(280));var t=e.stateNode;t&&(t=Ts(t),ca(e.stateNode,e.type,t))}}function jp(e){or?ir?ir.push(e):ir=[e]:or=e}function Mp(){if(or){var e=or,t=ir;if(ir=or=null,Dc(e),t)for(e=0;e>>=0,e===0?32:31-(Zy(e)/Jy|0)|0}var ti=64,ni=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 Ki(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 rx(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),Xc=" ",Qc=!1;function Gp(e,t){switch(e){case"keyup":return Px.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Kp(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var Un=!1;function Ix(e,t){switch(e){case"compositionend":return Kp(t);case"keypress":return t.which!==32?null:(Qc=!0,Xc);case"textInput":return e=t.data,e===Xc&&Qc?null:e;default:return null}}function Rx(e,t){if(Un)return e==="compositionend"||!Eu&&Gp(e,t)?(e=Xp(),Ti=Su=Zt=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=Zc(n)}}function eh(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?eh(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function th(){for(var e=window,t=Yi();t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href=="string"}catch{n=!1}if(n)e=t.contentWindow;else break;t=Yi(e.document)}return t}function Cu(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 Vx(e){var t=th(),n=e.focusedElem,r=e.selectionRange;if(t!==n&&n&&n.ownerDocument&&eh(n.ownerDocument.documentElement,n)){if(r!==null&&Cu(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=Jc(n,i);var s=Jc(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,ma=null,ro=null,ya=!1;function ed(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;ya||Yn==null||Yn!==Yi(r)||(r=Yn,"selectionStart"in r&&Cu(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=Ji(ma,"onSelect"),0Gn||(e.current=_a[Gn],_a[Gn]=null,Gn--)}function ae(e,t){Gn++,_a[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 ts(){ce(Be),ce(Te)}function ld(e,t,n){if(Te.current!==dn)throw Error(F(168));ae(Te,t),ae(Be,n)}function ch(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,Dy(e)||"Unknown",o));return me({},n,r)}function ns(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||dn,Nn=Te.current,ae(Te,e),ae(Be,Be.current),!0}function ad(e,t,n){var r=e.stateNode;if(!r)throw Error(F(169));n?(e=ch(e,t,Nn),r.__reactInternalMemoizedMergedChildContext=e,ce(Be),ce(Te),ae(Te,e)):ce(Be),ae(Be,n)}var Pt=null,Is=!1,kl=!1;function dh(e){Pt===null?Pt=[e]:Pt.push(e)}function t1(e){Is=!0,dh(e)}function hn(){if(!kl&&Pt!==null){kl=!0;var e=0,t=se;try{var n=Pt;for(se=1;e>=s,o-=s,Tt=1<<32-ft(t)+o|n<j?(I=C,C=null):I=C.sibling;var A=d(m,C,h[j],v);if(A===null){C===null&&(C=I);break}e&&C&&A.alternate===null&&t(m,C),g=i(A,g,j),k===null?S=A:k.sibling=A,k=A,C=I}if(j===h.length)return n(m,C),de&&mn(m,j),S;if(C===null){for(;jj?(I=C,C=null):I=C.sibling;var z=d(m,C,A.value,v);if(z===null){C===null&&(C=I);break}e&&C&&z.alternate===null&&t(m,C),g=i(z,g,j),k===null?S=z:k.sibling=z,k=z,C=I}if(A.done)return n(m,C),de&&mn(m,j),S;if(C===null){for(;!A.done;j++,A=h.next())A=c(m,A.value,v),A!==null&&(g=i(A,g,j),k===null?S=A:k.sibling=A,k=A);return de&&mn(m,j),S}for(C=r(m,C);!A.done;j++,A=h.next())A=x(C,m,j,A.value,v),A!==null&&(e&&A.alternate!==null&&C.delete(A.key===null?j:A.key),g=i(A,g,j),k===null?S=A:k.sibling=A,k=A);return e&&C.forEach(function(D){return t(m,D)}),de&&mn(m,j),S}function _(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 Zo:e:{for(var S=h.key,k=g;k!==null;){if(k.key===S){if(S=h.type,S===Wn){if(k.tag===7){n(m,k.sibling),g=o(k,h.props.children),g.return=m,m=g;break e}}else if(k.elementType===S||typeof S=="object"&&S!==null&&S.$$typeof===Xt&&dd(S)===k.type){n(m,k.sibling),g=o(k,h.props),g.ref=Dr(m,k,h),g.return=m,m=g;break e}n(m,k);break}else t(m,k);k=k.sibling}h.type===Wn?(g=En(h.props.children,m.mode,v,h.key),g.return=m,m=g):(v=Bi(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(k=h.key;g!==null;){if(g.key===k)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=zl(h,m.mode,v),g.return=m,m=g}return s(m);case Xt:return k=h._init,_(m,g,k(h._payload),v)}if(Qr(h))return y(m,g,h,v);if(Ir(h))return w(m,g,h,v);ui(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=Ml(h,m.mode,v),g.return=m,m=g),s(m)):n(m,g)}return _}var hr=gh(!0),mh=gh(!1),is=pn(null),ss=null,Zn=null,Mu=null;function zu(){Mu=Zn=ss=null}function Pu(e){var t=is.current;ce(is),e._currentValue=t}function ba(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){ss=e,Mu=Zn=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(Mu!==e)if(e={context:e,memoizedValue:t,next:null},Zn===null){if(ss===null)throw Error(F(308));Zn=e,ss.dependencies={lanes:0,firstContext:e}}else Zn=Zn.next=e;return t}var wn=null;function Tu(e){wn===null?wn=[e]:wn.push(e)}function yh(e,t,n,r){var o=t.interleaved;return o===null?(n.next=n,Tu(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 Iu(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,interleaved:null,lanes:0},effects:null}}function xh(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,Tu(r)):(t.next=o.next,o.next=t),r.interleaved=t,Dt(e,n)}function Ri(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,xu(e,n)}}function fd(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 ls(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 pd(e,t,n){if(e=t.effects,t.effects=null,e!==null)for(t=0;tn?n:4,e(!0);var r=El.transition;El.transition={};try{e(!1),t()}finally{se=n,El.transition=r}}function Lh(){return rt().memoizedState}function i1(e,t,n){var r=ln(e);if(n={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null},Ah(e))$h(t,n);else if(n=yh(e,t,n,r),n!==null){var o=Re();pt(n,e,r,o),Dh(n,t,r)}}function s1(e,t,n){var r=ln(e),o={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null};if(Ah(e))$h(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,Tu(t)):(o.next=a.next,a.next=o),t.interleaved=o;return}}catch{}finally{}n=yh(e,t,o,r),n!==null&&(o=Re(),pt(n,e,r,o),Dh(n,t,r))}}function Ah(e){var t=e.alternate;return e===ge||t!==null&&t===ge}function $h(e,t){oo=us=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function Dh(e,t,n){if(n&4194240){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,xu(e,n)}}var cs={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},l1={readContext:nt,useCallback:function(e,t){return wt().memoizedState=[e,t===void 0?null:t],e},useContext:nt,useEffect:gd,useImperativeHandle:function(e,t,n){return n=n!=null?n.concat([e]):null,Ai(4194308,4,zh.bind(null,t,e),n)},useLayoutEffect:function(e,t){return Ai(4194308,4,e,t)},useInsertionEffect:function(e,t){return Ai(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=i1.bind(null,ge,e),[r.memoizedState,e]},useRef:function(e){var t=wt();return e={current:e},t.memoizedState=e},useState:hd,useDebugValue:Fu,useDeferredValue:function(e){return wt().memoizedState=e},useTransition:function(){var e=hd(!1),t=e[0];return e=o1.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||kh(r,t,n)}o.memoizedState=n;var i={value:n,getSnapshot:t};return o.queue=i,gd(Eh.bind(null,r,i,e),[e]),r.flags|=2048,bo(9,_h.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,Qh(e,t,!1,!1),t.stateNode=e;e:{switch(s=aa(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=as(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 Xu(),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 g1(e,t){switch(Nu(t),t.tag){case 1:return Fe(t.type)&&ts(),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return gr(),ce(Be),ce(Te),Au(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 5:return Lu(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 Pu(t.type._context),null;case 22:case 23:return Xu(),null;case 24:return null;default:return null}}var di=!1,Pe=!1,m1=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 La(e,t,n){try{n()}catch(r){ye(e,t,r)}}var bd=!1;function y1(e,t){if(xa=qi,e=th(),Cu(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(va={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,_=y.memoizedState,m=t.stateNode,g=m.getSnapshotBeforeUpdate(t.elementType===t.type?w:it(t.type,w),_);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=bd,bd=!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&&La(t,n,i)}o=o.next}while(o!==r)}}function As(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 Aa(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 qh(e){var t=e.alternate;t!==null&&(e.alternate=null,qh(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[ka],delete t[Jx],delete t[e1])),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 Zh(e){return e.tag===5||e.tag===3||e.tag===4}function Nd(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||Zh(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 $a(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=es));else if(r!==4&&(e=e.child,e!==null))for($a(e,t,n),e=e.sibling;e!==null;)$a(e,t,n),e=e.sibling}function Da(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(Da(e,t,n),e=e.sibling;e!==null;)Da(e,t,n),e=e.sibling}var Ce=null,st=!1;function Wt(e,t,n){for(n=n.child;n!==null;)Jh(e,t,n),n=n.sibling}function Jh(e,t,n){if(_t&&typeof _t.onCommitFiberUnmount=="function")try{_t.onCommitFiberUnmount(js,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?Sl(e.parentNode,n):e.nodeType===1&&Sl(e,n),mo(e)):Sl(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)&&La(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 jd(e){var t=e.updateQueue;if(t!==null){e.updateQueue=null;var n=e.stateNode;n===null&&(n=e.stateNode=new m1),t.forEach(function(r){var o=b1.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*v1(r/1960))-r,10e?16:e,Jt===null)var r=!1;else{if(e=Jt,Jt=null,ps=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()-Uu?_n(e,0):Wu|=n),He(e,t)}function lg(e,t){t===0&&(e.mode&1?(t=ni,ni<<=1,!(ni&130023424)&&(ni=4194304)):t=1);var n=Re();e=Dt(e,t),e!==null&&(Oo(e,t,n),He(e,n))}function C1(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),lg(e,n)}function b1(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),lg(e,n)}var ag;ag=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,p1(e,t,n);De=!!(e.flags&131072)}else De=!1,de&&t.flags&1048576&&fh(t,os,t.index);switch(t.lanes=0,t.tag){case 2:var r=t.type;$i(e,t),e=t.pendingProps;var o=fr(t,Te.current);lr(t,n),o=Du(null,t,r,e,o,n);var i=Ou();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,ns(t)):i=!1,t.memoizedState=o.state!==null&&o.state!==void 0?o.state:null,Iu(t),o.updater=Ls,t.stateNode=o,o._reactInternals=t,ja(t,r,e,n),t=Pa(null,t,r,!0,i,n)):(t.tag=0,de&&i&&bu(t),Ie(null,t,o,n),t=t.child),t;case 16:r=t.elementType;e:{switch($i(e,t),e=t.pendingProps,o=r._init,r=o(r._payload),t.type=r,o=t.tag=j1(r),e=it(r,e),o){case 0:t=za(null,t,r,e,n);break e;case 1:t=_d(null,t,r,e,n);break e;case 11:t=Sd(null,t,r,e,n);break e;case 14:t=kd(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),za(e,t,r,o,n);case 1:return r=t.type,o=t.pendingProps,o=t.elementType===r?o:it(r,o),_d(e,t,r,o,n);case 3:e:{if(Uh(t),e===null)throw Error(F(387));r=t.pendingProps,i=t.memoizedState,o=i.element,xh(e,t),ls(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(Ue=rn(t.stateNode.containerInfo.firstChild),Ye=t,de=!0,at=null,n=mh(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 vh(t),e===null&&Ca(t),r=t.type,o=t.pendingProps,i=e!==null?e.memoizedProps:null,s=o.children,wa(r,o)?s=null:i!==null&&wa(r,i)&&(t.flags|=32),Wh(e,t),Ie(e,t,s,n),t.child;case 6:return e===null&&Ca(t),null;case 13:return Yh(e,t,n);case 4:return Ru(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),Sd(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(is,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),ba(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),ba(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),kd(e,t,r,o,n);case 15:return Hh(e,t,t.type,t.pendingProps,n);case 17:return r=t.type,o=t.pendingProps,o=t.elementType===r?o:it(r,o),$i(e,t),t.tag=1,Fe(r)?(e=!0,ns(t)):e=!1,lr(t,n),Oh(t,r,o),ja(t,r,o,n),Pa(null,t,r,!0,e,n);case 19:return Xh(e,t,n);case 22:return Vh(e,t,n)}throw Error(F(156,t.tag))};function ug(e,t){return Ap(e,t)}function N1(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 N1(e,t,n,r)}function Gu(e){return e=e.prototype,!(!e||!e.isReactComponent)}function j1(e){if(typeof e=="function")return Gu(e)?1:0;if(e!=null){if(e=e.$$typeof,e===hu)return 11;if(e===gu)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 Bi(e,t,n,r,o,i){var s=2;if(r=e,typeof e=="function")Gu(e)&&(s=1);else if(typeof e=="string")s=5;else e:switch(e){case Wn:return En(n.children,o,i,t);case pu:s=8,o|=8;break;case Zl:return e=et(12,n,t,o|2),e.elementType=Zl,e.lanes=i,e;case Jl:return e=et(13,n,t,o),e.elementType=Jl,e.lanes=i,e;case ea:return e=et(19,n,t,o),e.elementType=ea,e.lanes=i,e;case vp:return Ds(n,o,i,t);default:if(typeof e=="object"&&e!==null)switch(e.$$typeof){case yp:s=10;break e;case xp:s=9;break e;case hu:s=11;break e;case gu: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 Ds(e,t,n,r){return e=et(22,e,r,t),e.elementType=vp,e.lanes=n,e.stateNode={isHidden:!1},e}function Ml(e,t,n){return e=et(6,e,null,t),e.lanes=n,e}function zl(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 M1(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=cl(0),this.expirationTimes=cl(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=cl(0),this.identifierPrefix=r,this.onRecoverableError=o,this.mutableSourceEagerHydrationData=null}function Ku(e,t,n,r,o,i,s,l,a){return e=new M1(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},Iu(i),e}function z1(e,t,n){var r=3"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(pg)}catch(e){console.error(e)}}pg(),pp.exports=Ge;var L1=pp.exports,Ad=L1;Kl.createRoot=Ad.createRoot,Kl.hydrateRoot=Ad.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 Vs(){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}})}Fi.prototype=Vs.prototype={constructor:Fi,on:function(e,t){var n=this._,r=$1(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)),Dd.hasOwnProperty(t)?{space:Dd[t],local:e}:e}function O1(e){return function(){var t=this.ownerDocument,n=this.namespaceURI;return n===Va&&t.documentElement.namespaceURI===Va?t.createElement(e):t.createElementNS(n,e)}}function B1(e){return function(){return this.ownerDocument.createElementNS(e.space,e.local)}}function hg(e){var t=Ws(e);return(t.local?B1:O1)(t)}function F1(){}function ec(e){return e==null?F1:function(){return this.querySelector(e)}}function H1(e){typeof e!="function"&&(e=ec(e));for(var t=this._groups,n=t.length,r=new Array(n),o=0;o=h&&(h=g+1);!(S=_[h])&&++h=0;)(s=r[o])&&(i&&s.compareDocumentPosition(i)^4&&i.parentNode.insertBefore(s,i),i=s);return this}function pv(e){e||(e=hv);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 gv(){var e=arguments[0];return arguments[0]=this,e.apply(null,arguments),this}function mv(){return Array.from(this)}function yv(){for(var e=this._groups,t=0,n=e.length;t1?this.each((t==null?jv:typeof t=="function"?zv:Mv)(e,t,n??"")):xr(this.node(),e)}function xr(e,t){return e.style.getPropertyValue(t)||vg(e).getComputedStyle(e,null).getPropertyValue(t)}function Tv(e){return function(){delete this[e]}}function Iv(e,t){return function(){this[e]=t}}function Rv(e,t){return function(){var n=t.apply(this,arguments);n==null?delete this[e]:this[e]=n}}function Lv(e,t){return arguments.length>1?this.each((t==null?Tv:typeof t=="function"?Rv:Iv)(e,t)):this.node()[e]}function wg(e){return e.trim().split(/^|\s+/)}function tc(e){return e.classList||new Sg(e)}function Sg(e){this._node=e,this._names=wg(e.getAttribute("class")||"")}Sg.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 kg(e,t){for(var n=tc(e),r=-1,o=t.length;++r=0&&(n=t.slice(r+1),t=t.slice(0,r)),{type:t,name:n}})}function uw(e){return function(){var t=this.__on;if(t){for(var n=0,r=-1,o=t.length,i;n()=>e;function Wa(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}})}Wa.prototype.on=function(){var e=this._.on.apply(this._,arguments);return e===this._?this:e};function vw(e){return!e.ctrlKey&&!e.button}function ww(){return this.parentNode}function Sw(e,t){return t??{x:e.x,y:e.y}}function kw(){return navigator.maxTouchPoints||"ontouchstart"in this}function jg(){var e=vw,t=ww,n=Sw,r=kw,o={},i=Vs("start","drag","end"),s=0,l,a,u,p,c=0;function d(v){v.on("mousedown.drag",x).filter(r).on("touchstart.drag",_).on("touchmove.drag",m,xw).on("touchend.drag touchcancel.drag",g).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function x(v,S){if(!(p||!e.call(this,v,S))){var k=h(this,t.call(this,v,S),v,S,"mouse");k&&(We(v.view).on("mousemove.drag",y,jo).on("mouseup.drag",w,jo),bg(v.view),Pl(v),u=!1,l=v.clientX,a=v.clientY,k("start",v))}}function y(v){if(ur(v),!u){var S=v.clientX-l,k=v.clientY-a;u=S*S+k*k>c}o.mouse("drag",v)}function w(v){We(v.view).on("mousemove.drag mouseup.drag",null),Ng(v.view,u),ur(v),o.mouse("end",v)}function _(v,S){if(e.call(this,v,S)){var k=v.changedTouches,C=t.call(this,v,S),j=k.length,I,A;for(I=0;I>8&15|t>>4&240,t>>4&15|t&240,(t&15)<<4|t&15,1):n===8?gi(t>>24&255,t>>16&255,t>>8&255,(t&255)/255):n===4?gi(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=Ew.exec(e))?new Oe(t[1],t[2],t[3],1):(t=Cw.exec(e))?new Oe(t[1]*255/100,t[2]*255/100,t[3]*255/100,1):(t=bw.exec(e))?gi(t[1],t[2],t[3],t[4]):(t=Nw.exec(e))?gi(t[1]*255/100,t[2]*255/100,t[3]*255/100,t[4]):(t=jw.exec(e))?Ud(t[1],t[2]/100,t[3]/100,1):(t=Mw.exec(e))?Ud(t[1],t[2]/100,t[3]/100,t[4]):Od.hasOwnProperty(e)?Hd(Od[e]):e==="transparent"?new Oe(NaN,NaN,NaN,0):null}function Hd(e){return new Oe(e>>16&255,e>>8&255,e&255,1)}function gi(e,t,n,r){return r<=0&&(e=t=n=NaN),new Oe(e,t,n,r)}function Tw(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 Ua(e,t,n,r){return arguments.length===1?Tw(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}nc(Oe,Ua,Mg(Wo,{brighter(e){return e=e==null?ys:Math.pow(ys,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),xs(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:Vd,formatHex:Vd,formatHex8:Iw,formatRgb:Wd,toString:Wd}));function Vd(){return`#${kn(this.r)}${kn(this.g)}${kn(this.b)}`}function Iw(){return`#${kn(this.r)}${kn(this.g)}${kn(this.b)}${kn((isNaN(this.opacity)?1:this.opacity)*255)}`}function Wd(){const e=xs(this.opacity);return`${e===1?"rgb(":"rgba("}${Cn(this.r)}, ${Cn(this.g)}, ${Cn(this.b)}${e===1?")":`, ${e})`}`}function xs(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 Ud(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 zg(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 Rw(e,t,n,r){return arguments.length===1?zg(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}nc(ut,Rw,Mg(Wo,{brighter(e){return e=e==null?ys:Math.pow(ys,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(Tl(e>=240?e-240:e+120,o,r),Tl(e,o,r),Tl(e<120?e+240:e-120,o,r),this.opacity)},clamp(){return new ut(Yd(this.h),mi(this.s),mi(this.l),xs(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=xs(this.opacity);return`${e===1?"hsl(":"hsla("}${Yd(this.h)}, ${mi(this.s)*100}%, ${mi(this.l)*100}%${e===1?")":`, ${e})`}`}}));function Yd(e){return e=(e||0)%360,e<0?e+360:e}function mi(e){return Math.max(0,Math.min(1,e||0))}function Tl(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 rc=e=>()=>e;function Lw(e,t){return function(n){return e+n*t}}function Aw(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 $w(e){return(e=+e)==1?Pg:function(t,n){return n-t?Aw(t,n,e):rc(isNaN(t)?n:t)}}function Pg(e,t){var n=t-e;return n?Lw(e,n):rc(isNaN(e)?t:e)}const vs=function e(t){var n=$w(t);function r(o,i){var s=n((o=Ua(o)).r,(i=Ua(i)).r),l=n(o.g,i.g),a=n(o.b,i.b),u=Pg(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 Dw(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=Il.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,_;++y=0&&e._call.call(void 0,t),e=e._next;--vr}function Gd(){In=(Ss=Po.now())+Us,vr=qr=0;try{Jw()}finally{vr=0,t2(),In=0}}function e2(){var e=Po.now(),t=e-Ss;t>Lg&&(Us-=t,Ss=e)}function t2(){for(var e,t=ws,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:ws=n);Zr=e,Qa(r)}function Qa(e){if(!vr){qr&&(qr=clearTimeout(qr));var t=e-In;t>24?(e<1/0&&(qr=setTimeout(Gd,e-Po.now()-Us)),Fr&&(Fr=clearInterval(Fr))):(Fr||(Ss=Po.now(),Fr=setInterval(e2,Lg)),vr=1,Ag(Gd))}}function Kd(e,t,n){var r=new ks;return t=t==null?0:+t,r.restart(o=>{r.stop(),e(o+t)},t,n),r}var n2=Vs("start","end","cancel","interrupt"),r2=[],Dg=0,qd=1,Ga=2,Vi=3,Zd=4,Ka=5,Wi=6;function Ys(e,t,n,r,o,i){var s=e.__transition;if(!s)e.__transition={};else if(n in s)return;o2(e,n,{name:t,index:r,group:o,on:n2,tween:r2,time:i.time,delay:i.delay,duration:i.duration,ease:i.ease,timer:null,state:Dg})}function ic(e,t){var n=gt(e,t);if(n.state>Dg)throw new Error("too late; already scheduled");return n}function Nt(e,t){var n=gt(e,t);if(n.state>Vi)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 o2(e,t,n){var r=e.__transition,o;r[t]=n,n.timer=$g(i,0,n.time);function i(u){n.state=qd,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!==qd)return a();for(p in r)if(x=r[p],x.name===n.name){if(x.state===Vi)return Kd(s);x.state===Zd?(x.state=Wi,x.timer.stop(),x.on.call("interrupt",e,e.__data__,x.index,x.group),delete r[p]):+pGa&&r.state=0&&(t=t.slice(0,n)),!t||t==="start"})}function R2(e,t,n){var r,o,i=I2(t)?ic:Nt;return function(){var s=i(this,e),l=s.on;l!==r&&(o=(r=l).copy()).on(t,n),s.on=o}}function L2(e,t){var n=this._id;return arguments.length<2?gt(this.node(),n).on.on(e):this.each(R2(n,e,t))}function A2(e){return function(){var t=this.parentNode;for(var n in this.__transition)if(+n!==e)return;t&&t.removeChild(this)}}function $2(){return this.on("end.remove",A2(this._id))}function D2(e){var t=this._name,n=this._id;typeof e!="function"&&(e=ec(e));for(var r=this._groups,o=r.length,i=new Array(o),s=0;s()=>e;function uS(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 Xs=new Rt(1,0,0);Hg.prototype=Rt.prototype;function Hg(e){for(;!e.__zoom;)if(!(e=e.parentNode))return Xs;return e.__zoom}function Rl(e){e.stopImmediatePropagation()}function Hr(e){e.preventDefault(),e.stopImmediatePropagation()}function cS(e){return(!e.ctrlKey||e.type==="wheel")&&!e.button}function dS(){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 Jd(){return this.__zoom||Xs}function fS(e){return-e.deltaY*(e.deltaMode===1?.05:e.deltaMode?1:.002)*(e.ctrlKey?10:1)}function pS(){return navigator.maxTouchPoints||"ontouchstart"in this}function hS(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 Vg(){var e=cS,t=dS,n=hS,r=fS,o=pS,i=[0,1/0],s=[[-1/0,-1/0],[1/0,1/0]],l=250,a=Hi,u=Vs("start","zoom","end"),p,c,d,x=500,y=150,w=0,_=10;function m(E){E.property("__zoom",Jd).on("wheel.zoom",j,{passive:!1}).on("mousedown.zoom",I).on("dblclick.zoom",A).filter(o).on("touchstart.zoom",z).on("touchmove.zoom",D).on("touchend.zoom touchcancel.zoom",R).style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}m.transform=function(E,T,P,L){var b=E.selection?E.selection():E;b.property("__zoom",Jd),E!==b?S(E,T,P,L):b.interrupt().each(function(){k(this,arguments).event(L).start().zoom(null,typeof T=="function"?T.apply(this,arguments):T).end()})},m.scaleBy=function(E,T,P,L){m.scaleTo(E,function(){var b=this.__zoom.k,N=typeof T=="function"?T.apply(this,arguments):T;return b*N},P,L)},m.scaleTo=function(E,T,P,L){m.transform(E,function(){var b=t.apply(this,arguments),N=this.__zoom,$=P==null?v(b):typeof P=="function"?P.apply(this,arguments):P,O=N.invert($),B=typeof T=="function"?T.apply(this,arguments):T;return n(h(g(N,B),$,O),b,s)},P,L)},m.translateBy=function(E,T,P,L){m.transform(E,function(){return n(this.__zoom.translate(typeof T=="function"?T.apply(this,arguments):T,typeof P=="function"?P.apply(this,arguments):P),t.apply(this,arguments),s)},null,L)},m.translateTo=function(E,T,P,L,b){m.transform(E,function(){var N=t.apply(this,arguments),$=this.__zoom,O=L==null?v(N):typeof L=="function"?L.apply(this,arguments):L;return n(Xs.translate(O[0],O[1]).scale($.k).translate(typeof T=="function"?-T.apply(this,arguments):-T,typeof P=="function"?-P.apply(this,arguments):-P),N,s)},L,b)};function g(E,T){return T=Math.max(i[0],Math.min(i[1],T)),T===E.k?E:new Rt(T,E.x,E.y)}function h(E,T,P){var L=T[0]-P[0]*E.k,b=T[1]-P[1]*E.k;return L===E.x&&b===E.y?E:new Rt(E.k,L,b)}function v(E){return[(+E[0][0]+ +E[1][0])/2,(+E[0][1]+ +E[1][1])/2]}function S(E,T,P,L){E.on("start.zoom",function(){k(this,arguments).event(L).start()}).on("interrupt.zoom end.zoom",function(){k(this,arguments).event(L).end()}).tween("zoom",function(){var b=this,N=arguments,$=k(b,N).event(L),O=t.apply(b,N),B=P==null?v(O):typeof P=="function"?P.apply(b,N):P,W=Math.max(O[1][0]-O[0][0],O[1][1]-O[0][1]),V=b.__zoom,Y=typeof T=="function"?T.apply(b,N):T,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 k(E,T,P){return!P&&E.__zooming||new C(E,T)}function C(E,T){this.that=E,this.args=T,this.active=0,this.sourceEvent=null,this.extent=t.apply(E,T),this.taps=0}C.prototype={event:function(E){return E&&(this.sourceEvent=E),this},start:function(){return++this.active===1&&(this.that.__zooming=this,this.emit("start")),this},zoom:function(E,T){return this.mouse&&E!=="mouse"&&(this.mouse[1]=T.invert(this.mouse[0])),this.touch0&&E!=="touch"&&(this.touch0[1]=T.invert(this.touch0[0])),this.touch1&&E!=="touch"&&(this.touch1[1]=T.invert(this.touch1[0])),this.that.__zoom=T,this.emit("zoom"),this},end:function(){return--this.active===0&&(delete this.that.__zooming,this.emit("end")),this},emit:function(E){var T=We(this.that).datum();u.call(E,this.that,new uS(E,{sourceEvent:this.sourceEvent,target:m,transform:this.that.__zoom,dispatch:u}),T)}};function j(E,...T){if(!e.apply(this,arguments))return;var P=k(this,T).event(E),L=this.__zoom,b=Math.max(i[0],Math.min(i[1],L.k*Math.pow(2,r.apply(this,arguments)))),N=lt(E);if(P.wheel)(P.mouse[0][0]!==N[0]||P.mouse[0][1]!==N[1])&&(P.mouse[1]=L.invert(P.mouse[0]=N)),clearTimeout(P.wheel);else{if(L.k===b)return;P.mouse=[N,L.invert(N)],Ui(this),P.start()}Hr(E),P.wheel=setTimeout($,y),P.zoom("mouse",n(h(g(L,b),P.mouse[0],P.mouse[1]),P.extent,s));function $(){P.wheel=null,P.end()}}function I(E,...T){if(d||!e.apply(this,arguments))return;var P=E.currentTarget,L=k(this,T,!0).event(E),b=We(E.view).on("mousemove.zoom",B,!0).on("mouseup.zoom",W,!0),N=lt(E,P),$=E.clientX,O=E.clientY;bg(E.view),Rl(E),L.mouse=[N,this.__zoom.invert(N)],Ui(this),L.start();function B(V){if(Hr(V),!L.moved){var Y=V.clientX-$,X=V.clientY-O;L.moved=Y*Y+X*X>w}L.event(V).zoom("mouse",n(h(L.that.__zoom,L.mouse[0]=lt(V,P),L.mouse[1]),L.extent,s))}function W(V){b.on("mousemove.zoom mouseup.zoom",null),Ng(V.view,L.moved),Hr(V),L.event(V).end()}}function A(E,...T){if(e.apply(this,arguments)){var P=this.__zoom,L=lt(E.changedTouches?E.changedTouches[0]:E,this),b=P.invert(L),N=P.k*(E.shiftKey?.5:2),$=n(h(g(P,N),L,b),t.apply(this,T),s);Hr(E),l>0?We(this).transition().duration(l).call(S,$,L,E):We(this).call(m.transform,$,L,E)}}function z(E,...T){if(e.apply(this,arguments)){var P=E.touches,L=P.length,b=k(this,T,E.changedTouches.length===L).event(E),N,$,O,B;for(Rl(E),$=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]],Wg=["Enter"," ","Escape"],Ug={"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 Yg={inProgress:!1,isValid:null,from:null,fromHandle:null,fromPosition:null,fromNode:null,to:null,toHandle:null,toPosition:null,toNode:null,pointer:null};var qt;(function(e){e.Bezier="default",e.Straight="straight",e.Step="step",e.SmoothStep="smoothstep",e.SimpleBezier="simplebezier"})(qt||(qt={}));var _s;(function(e){e.Arrow="arrow",e.ArrowClosed="arrowclosed"})(_s||(_s={}));var Z;(function(e){e.Left="left",e.Top="top",e.Right="right",e.Bottom="bottom"})(Z||(Z={}));const ef={[Z.Left]:Z.Right,[Z.Right]:Z.Left,[Z.Top]:Z.Bottom,[Z.Bottom]:Z.Top};function Xg(e){return e===null?null:e?"valid":"invalid"}const Qg=e=>"id"in e&&"source"in e&&"target"in e,gS=e=>"id"in e&&"position"in e&&!("source"in e)&&!("target"in e),lc=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}},mS=(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):lc(o)?o:t.nodeLookup.get(o.id));const l=s?Es(s,t.nodeOrigin):{x:0,y:0,x2:0,y2:0};return Qs(r,l)},{x:1/0,y:1/0,x2:-1/0,y2:-1/0});return Gs(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=Qs(n,Es(o)),r=!0)}),r?Gs(n):{x:0,y:0,width:0,height:0}},ac=(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)),_=(x??0)*(y??0),m=i&&w>0;(!u.internals.handleBounds||m||w>=_||u.dragging)&&a.push(u)}return a},yS=(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 xS(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 vS({nodes:e,width:t,height:n,panZoom:r,minZoom:o,maxZoom:i},s){if(e.size===0)return Promise.resolve(!0);const l=xS(e,s),a=Yo(l),u=uc(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 Gg({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 wS({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=yS(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 Kg(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 tf=(e,t,n)=>en?-Sr(Math.abs(e-n),1,t)/t:0,qg=(e,t,n=15,r=40)=>{const o=tf(e.x,r,t.width-r)*n,i=tf(e.y,r,t.height-r)*n;return[o,i]},Qs=(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}),Gs=({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}=lc(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}},Es=(e,t=[0,0])=>{var o,i;const{x:n,y:r}=lc(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)}},Zg=(e,t)=>Gs(Qs(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)},nf=e=>ct(e.width)&&ct(e.height)&&ct(e.x)&&ct(e.y),ct=e=>!isNaN(e)&&isFinite(e),SS=(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},Cs=({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 kS(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 _S(e,t,n,r,o,i){const{x:s,y:l}=Cs(e,[t,n,r]),{x:a,y:u}=Cs({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 uc=(e,t,n,r,o,i)=>{const s=kS(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=_S(e,x,y,p,t,n),_={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-_.left+_.right,y:y-_.top+_.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 Jg(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 e0(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 rf(e,t){if(e.size!==t.size)return!1;for(const n of e)if(!t.has(n))return!1;return!0}function ES(){let e,t;return{promise:new Promise((r,o)=>{e=r,t=o}),resolve:e,reject:t}}function CS(e){return{...Ug,...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 cc=e=>({width:e.offsetWidth,height:e.offsetHeight}),t0=e=>{var t;return((t=e==null?void 0:e.getRootNode)==null?void 0:t.call(e))||(window==null?void 0:window.document)},bS=["INPUT","SELECT","TEXTAREA"];function n0(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:bS.includes(t.nodeName)||t.hasAttribute("contenteditable")||!!t.closest(".nokey")}const r0=e=>"clientX"in e,dt=(e,t)=>{var i,s;const n=r0(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)}},of=(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,...cc(s)}})};function o0({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 vi(e,t){return e>=0?.5*e:t*25*Math.sqrt(-e)}function sf({pos:e,x1:t,y1:n,x2:r,y2:o,c:i}){switch(e){case Z.Left:return[t-vi(t-r,i),n];case Z.Right:return[t+vi(r-t,i),n];case Z.Top:return[t,n-vi(n-o,i)];case Z.Bottom:return[t,n+vi(o-n,i)]}}function i0({sourceX:e,sourceY:t,sourcePosition:n=Z.Bottom,targetX:r,targetY:o,targetPosition:i=Z.Top,curvature:s=.25}){const[l,a]=sf({pos:n,x1:e,y1:t,x2:r,y2:o,c:s}),[u,p]=sf({pos:i,x1:r,y1:o,x2:e,y2:t,c:s}),[c,d,x,y]=o0({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 s0({sourceX:e,sourceY:t,targetX:n,targetY:r}){const o=Math.abs(n-e)/2,i=n0}const MS=({source:e,sourceHandle:t,target:n,targetHandle:r})=>`xy-edge__${e}${t||""}-${n}${r||""}`,zS=(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)),PS=(e,t,n={})=>{if(!e.source||!e.target)return t;const r=n.getEdgeId||MS;let o;return Qg(e)?o={...e}:o={...e,id:r(e)},zS(o,t)?t:(o.sourceHandle===null&&delete o.sourceHandle,o.targetHandle===null&&delete o.targetHandle,t.concat(o))};function l0({sourceX:e,sourceY:t,targetX:n,targetY:r}){const[o,i,s,l]=s0({sourceX:e,sourceY:t,targetX:n,targetY:r});return[`M ${e},${t}L ${n},${r}`,o,i,s,l]}const lf={[Z.Left]:{x:-1,y:0},[Z.Right]:{x:1,y:0},[Z.Top]:{x:0,y:-1},[Z.Bottom]:{x:0,y:1}},TS=({source:e,sourcePosition:t=Z.Bottom,target:n})=>t===Z.Left||t===Z.Right?e.xMath.sqrt(Math.pow(t.x-e.x,2)+Math.pow(t.y-e.y,2));function IS({source:e,sourcePosition:t=Z.Bottom,target:n,targetPosition:r=Z.Top,center:o,offset:i,stepPosition:s}){const l=lf[t],a=lf[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=TS({source:u,sourcePosition:t,target:p}),d=c.x!==0?"x":"y",x=c[d];let y=[],w,_;const m={x:0,y:0},g={x:0,y:0},[,,h,v]=s0({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,_=o.y??(u.y+p.y)/2):(w=o.x??(u.x+p.x)/2,_=o.y??u.y+(p.y-u.y)*s);const k=[{x:w,y:u.y},{x:w,y:p.y}],C=[{x:u.x,y:_},{x:p.x,y:_}];l[d]===x?y=d==="x"?k:C:y=d==="x"?C:k}else{const k=[{x:u.x,y:p.y}],C=[{x:p.x,y:u.y}];if(d==="x"?y=l.x===x?C:k:y=l.y===x?k:C,t===r){const D=Math.abs(e[d]-n[d]);if(D<=i){const R=Math.min(i-1,i-D);l[d]===x?m[d]=(u[d]>e[d]?-1:1)*R:g[d]=(p[d]>n[d]?-1:1)*R}}if(t!==r){const D=d==="x"?"y":"x",R=l[d]===a[D],E=u[D]>p[D],T=u[D]=z?(w=(j.x+I.x)/2,_=y[0].y):(w=y[0].x,_=(j.y+I.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,_,h,v]}function RS(e,t,n,r){const o=Math.min(af(e,t)/2,af(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 Ja(e,t){return e?typeof e=="string"?e:`${t?`${t}__`:""}${Object.keys(e).sort().map(r=>`${r}=${e[r]}`).join("&")}`:""}function AS(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=Ja(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 a0=1e3,$S=10,dc={nodeOrigin:[0,0],nodeExtent:To,elevateNodesOnSelect:!0,zIndexMode:"basic",defaults:{}},DS={...dc,checkEquality:!0};function fc(e,t){const n={...e};for(const r in t)t[r]!==void 0&&(n[r]=t[r]);return n}function OS(e,t,n){const r=fc(dc,n);for(const o of e.values())if(o.parentId)hc(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 BS(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 pc(e){return e==="manual"}function eu(e,t,n,r={}){var u,p;const o=fc(DS,r),i={i:0},s=new Map(t),l=o!=null&&o.elevateNodesOnSelect&&!pc(o.zIndexMode)?a0: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:BS(c,d),z:u0(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&&hc(d,t,n,r,i)}return a}function FS(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 hc(e,t,n,r,o){const{elevateNodesOnSelect:i,nodeOrigin:s,nodeExtent:l,zIndexMode:a}=fc(dc,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}FS(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*$S),o&&p.internals.rootParentIndex!==void 0&&(o.i=p.internals.rootParentIndex);const c=i&&!pc(a)?a0:0,{x:d,y:x,z:y}=HS(e,p,s,l,c,a),{positionAbsolute:w}=e.internals,_=d!==w.x||x!==w.y;(_||y!==e.internals.z)&&t.set(e.id,{...e,internals:{...e.internals,positionAbsolute:_?{x:d,y:x}:w,z:y}})}function u0(e,t,n){const r=ct(e.zIndex)?e.zIndex:0;return pc(n)?r:r+(e.selected?t:0)}function HS(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=Kg(c,a,t));const d=u0(e,o,i),x=t.internals.z??0;return{x:c.x,y:c.y,z:x>=d?x+1:d}}function gc(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=Zg(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(S=>S.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=gc(d,t,n,o);u.push(...x)}return{changes:u,updatedInternals:a}}async function WS({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 ff(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 c0(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}`;ff("source",a,p,e,o,s),ff("target",a,u,e,i,l),t.set(r.id,r)}}function d0(e,t){if(!e.parentId)return!1;const n=t.get(e.parentId);return n?n.selected?!0:d0(n,t):!1}function pf(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 US(e,t,n,r){const o=new Map;for(const[i,s]of e)if((s.selected||s.id===r)&&(!s.parentId||!d0(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 Ll({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 YS({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 XS({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 _({noDragClassName:g,handleSelector:h,domNode:v,isSelectable:S,nodeId:k,nodeClickDistance:C=0}){d=We(v);function j({x:D,y:R}){const{nodeLookup:E,nodeExtent:T,snapGrid:P,snapToGrid:L,nodeOrigin:b,onNodeDrag:N,onSelectionDrag:$,onError:O,updateNodePositions:B}=t();i={x:D,y:R};let W=!1;const V=l.size>1,Y=V&&T?qa(Yo(l)):null,X=V&&L?YS({dragItems:l,snapGrid:P,x:D,y:R}):null;for(const[Q,H]of l){if(!E.has(Q))continue;let K={x:D-H.distance.x,y:R-H.distance.y};L&&(K=X?{x:Math.round(K.x+X.x),y:Math.round(K.y+X.y)}:Xo(K,P));let ee=null;if(V&&T&&!H.extent&&Y){const{positionAbsolute:q}=H.internals,re=q.x-Y.x+T[0][0],le=q.x+H.measured.width-Y.x2+T[1][0],ie=q.y-Y.y+T[0][1],je=q.y+H.measured.height-Y.y2+T[1][1];ee=[[re,ie],[le,je]]}const{position:G,positionAbsolute:J}=Gg({nodeId:Q,nextPosition:K,nodeLookup:E,nodeExtent:ee||T,nodeOrigin:b,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||N||!k&&$))){const[Q,H]=Ll({nodeId:k,dragItems:l,nodeLookup:E});r==null||r(w,l,Q,H),N==null||N(w,Q,H),k||$==null||$(w,H)}}async function I(){if(!p)return;const{transform:D,panBy:R,autoPanSpeed:E,autoPanOnNodeDrag:T}=t();if(!T){a=!1,cancelAnimationFrame(s);return}const[P,L]=qg(u,p,E);(P!==0||L!==0)&&(i.x=(i.x??0)-P/D[2],i.y=(i.y??0)-L/D[2],await R({x:P,y:L})&&j(i)),s=requestAnimationFrame(I)}function A(D){var V;const{nodeLookup:R,multiSelectionActive:E,nodesDraggable:T,transform:P,snapGrid:L,snapToGrid:b,selectNodesOnDrag:N,onNodeDragStart:$,onSelectionDragStart:O,unselectNodesAndEdges:B}=t();c=!0,(!N||!S)&&!E&&k&&((V=R.get(k))!=null&&V.selected||B()),S&&N&&k&&(e==null||e(k));const W=uo(D.sourceEvent,{transform:P,snapGrid:L,snapToGrid:b,containerBounds:p});if(i=W,l=US(R,T,W,k),l.size>0&&(n||$||!k&&O)){const[Y,X]=Ll({nodeId:k,dragItems:l,nodeLookup:R});n==null||n(D.sourceEvent,l,Y,X),$==null||$(D.sourceEvent,Y,X),k||O==null||O(D.sourceEvent,X)}}const z=jg().clickDistance(C).on("start",D=>{const{domNode:R,nodeDragThreshold:E,transform:T,snapGrid:P,snapToGrid:L}=t();p=(R==null?void 0:R.getBoundingClientRect())||null,x=!1,y=!1,w=D.sourceEvent,E===0&&A(D),i=uo(D.sourceEvent,{transform:T,snapGrid:P,snapToGrid:L,containerBounds:p}),u=dt(D.sourceEvent,p)}).on("drag",D=>{const{autoPanOnNodeDrag:R,transform:E,snapGrid:T,snapToGrid:P,nodeDragThreshold:L,nodeLookup:b}=t(),N=uo(D.sourceEvent,{transform:E,snapGrid:T,snapToGrid:P,containerBounds:p});if(w=D.sourceEvent,(D.sourceEvent.type==="touchmove"&&D.sourceEvent.touches.length>1||k&&!b.has(k))&&(x=!0),!x){if(!a&&R&&c&&(a=!0,I()),!c){const $=dt(D.sourceEvent,p),O=$.x-u.x,B=$.y-u.y;Math.sqrt(O*O+B*B)>L&&A(D)}(i.x!==N.xSnapped||i.y!==N.ySnapped)&&l&&c&&(u=dt(D.sourceEvent,p),j(N))}}).on("end",D=>{if(!(!c||x)&&(a=!1,c=!1,cancelAnimationFrame(s),l.size>0)){const{nodeLookup:R,updateNodePositions:E,onNodeDragStop:T,onSelectionDragStop:P}=t();if(y&&(E(l,!1),y=!1),o||T||!k&&P){const[L,b]=Ll({nodeId:k,dragItems:l,nodeLookup:R,dragging:!1});o==null||o(D.sourceEvent,l,L,b),T==null||T(D.sourceEvent,L,b),k||P==null||P(D.sourceEvent,b)}}}).filter(D=>{const R=D.target;return!D.button&&(!g||!pf(R,`.${g}`,v))&&(!h||pf(R,h,v))});d.call(z)}function m(){d==null||d.on(".drag",null)}return{update:_,destroy:m}}function QS(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 GS=250;function KS(e,t,n,r){var l,a;let o=[],i=1/0;const s=QS(e,n,t+GS);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 f0(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 p0(e,t){return e||(t!=null&&t.classList.contains("target")?"target":t!=null&&t.classList.contains("source")?"source":null)}function qS(e,t){let n=null;return t?n=!0:e&&!t&&(n=!1),n}const h0=()=>!0;function ZS(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:_,isValidConnection:m=h0,onReconnectEnd:g,updateConnection:h,getTransform:v,getFromHandle:S,autoPanSpeed:k,dragThreshold:C=1,handleDomNode:j}){const I=t0(e.target);let A=0,z;const{x:D,y:R}=dt(e),E=p0(i,j),T=l==null?void 0:l.getBoundingClientRect();let P=!1;if(!T||!E)return;const L=f0(o,E,r,a,t);if(!L)return;let b=dt(e,T),N=!1,$=null,O=!1,B=null;function W(){if(!p||!T)return;const[G,J]=qg(b,T,k);d({x:G,y:J}),A=requestAnimationFrame(W)}const V={...L,nodeId:o,type:E,position:L.position},Y=a.get(o);let Q={inProgress:!0,isValid:null,from:Ln(Y,V,Z.Left,!0),fromHandle:V,fromPosition:V.position,fromNode:Y,to:b,toHandle:null,toPosition:ef[V.position],toNode:null,pointer:b};function H(){P=!0,h(Q),y==null||y(e,{nodeId:o,handleId:r,handleType:E})}C===0&&H();function K(G){if(!P){const{x:je,y:Vt}=dt(G),jt=je-D,gn=Vt-R;if(!(jt*jt+gn*gn>C*C))return;H()}if(!S()||!V){ee(G);return}const J=v();b=dt(G,T),z=KS(Qo(b,J,!1,[1,1]),n,a,V),N||(W(),N=!0);const q=g0(G,{handle:z,connectionMode:t,fromNodeId:o,fromHandleId:r,fromType:s?"target":"source",isValidConnection:m,doc:I,lib:u,flowId:c,nodeLookup:a});B=q.handleDomNode,$=q.connection,O=qS(!!z,q.isValid);const re=a.get(o),le=re?Ln(re,V,Z.Left,!0):Q.from,ie={...Q,from:le,isValid:O,to:q.toHandle&&O?Cs({x:q.toHandle.x,y:q.toHandle.y},J):b,toHandle:q.toHandle,toPosition:O&&q.toHandle?q.toHandle.position:ef[V.position],toNode:q.toHandle?a.get(q.toHandle.nodeId):null,pointer:b};h(ie),Q=ie}function ee(G){if(!("touches"in G&&G.touches.length>0)){if(P){(z||B)&&$&&O&&(w==null||w($));const{inProgress:J,...q}=Q,re={...q,toPosition:Q.toHandle?Q.toPosition:null};_==null||_(G,re),i&&(g==null||g(G,re))}x(),cancelAnimationFrame(A),N=!1,O=!1,$=null,B=null,I.removeEventListener("mousemove",K),I.removeEventListener("mouseup",ee),I.removeEventListener("touchmove",K),I.removeEventListener("touchend",ee)}}I.addEventListener("mousemove",K),I.addEventListener("mouseup",ee),I.addEventListener("touchmove",K),I.addEventListener("touchend",ee)}function g0(e,{handle:t,connectionMode:n,fromNodeId:r,fromHandleId:o,fromType:i,doc:s,lib:l,flowId:a,isValidConnection:u=h0,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),_=w!=null&&w.classList.contains(`${l}-flow__handle`)?w:d,m={handleDomNode:_,isValid:!1,connection:null,toHandle:null};if(_){const g=p0(void 0,_),h=_.getAttribute("data-nodeid"),v=_.getAttribute("data-handleid"),S=_.classList.contains("connectable"),k=_.classList.contains("connectableend");if(!h||!g)return m;const C={source:c?h:r,sourceHandle:c?v:o,target:c?r:h,targetHandle:c?o:v};m.connection=C;const I=S&&k&&(n===wr.Strict?c&&g==="source"||!c&&g==="target":h!==r||v!==o);m.isValid=I&&u(C),m.toHandle=f0(h,g,v,p,n,!0)}return m}const tu={onPointerDown:ZS,isValid:g0};function JS({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(),S=h.sourceEvent.ctrlKey&&Lo()?10:1,k=-h.sourceEvent.deltaY*(h.sourceEvent.deltaMode===1?.05:h.sourceEvent.deltaMode?1:.002)*p,C=v[2]*Math.pow(2,k*S);t.scaleTo(C)};let w=[0,0];const _=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 S=[h.sourceEvent.clientX??h.sourceEvent.touches[0].clientX,h.sourceEvent.clientY??h.sourceEvent.touches[0].clientY],k=[S[0]-w[0],S[1]-w[1]];w=S;const C=r()*Math.max(v[2],Math.log(v[2]))*(x?-1:1),j={x:v[0]-k[0]*C,y:v[1]-k[1]*C},I=[[0,0],[a,u]];t.setViewportConstrained({x:j.x,y:j.y,zoom:v[2]},I,l)},g=Vg().on("start",_).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 Ks=e=>({x:e.x,y:e.y,zoom:e.k}),Al=({x:e,y:t,zoom:n})=>Xs.translate(e,t).scale(n),tr=(e,t)=>e.target.closest(`.${t}`),m0=(e,t)=>t===2&&Array.isArray(e)&&e.includes(2),ek=e=>((e*=2)<=1?e*e*e:(e-=2)*e*e+2)/2,$l=(e,t=0,n=ek,r=()=>{})=>{const o=typeof t=="number"&&t>0;return o||r(),o?e.transition().duration(t).ease(n).on("end",r):e},y0=e=>{const t=e.ctrlKey&&Lo()?10:1;return-e.deltaY*(e.deltaMode===1?.05:e.deltaMode?1:.002)*t};function tk({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 _=lt(p),m=y0(p),g=c*Math.pow(2,m);r.scaleTo(n,g,_,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=Ks(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 nk({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 rk({zoomPanValues:e,onDraggingChange:t,onPanZoomStart:n}){return r=>{var i,s,l;if((i=r.sourceEvent)!=null&&i.internal)return;const o=Ks(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 ok({zoomPanValues:e,panOnDrag:t,onPaneContextMenu:n,onTransformChange:r,onPanZoom:o}){return i=>{var s,l;e.usedRightMouseButton=!!(n&&m0(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,Ks(i.transform)))}}function ik({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&&m0(t,e.mouseButton??0)&&!e.usedRightMouseButton&&s.sourceEvent&&i(s.sourceEvent),e.usedRightMouseButton=!1,r(!1),o)){const a=Ks(s.transform);e.prevViewport=a,clearTimeout(e.timerId),e.timerId=setTimeout(()=>{o==null||o(s.sourceEvent,a)},n?150:0)}}}function sk({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 _;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"&&((_=c.touches)==null?void 0:_.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 lk({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=Vg().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(y0);function w(z,D){return d?new Promise(R=>{c==null||c.interpolate((D==null?void 0:D.interpolate)==="linear"?ao:Hi).transform($l(d,D==null?void 0:D.duration,D==null?void 0:D.ease,()=>R(!0)),z)}):Promise.resolve(!1)}function _({noWheelClassName:z,noPanClassName:D,onPaneContextMenu:R,userSelectionActive:E,panOnScroll:T,panOnDrag:P,panOnScrollMode:L,panOnScrollSpeed:b,preventScrolling:N,zoomOnPinch:$,zoomOnScroll:O,zoomOnDoubleClick:B,zoomActivationKeyPressed:W,lib:V,onTransformChange:Y,connectionInProgress:X,paneClickDistance:Q,selectionOnDrag:H}){E&&!u.isZoomingOrPanning&&m();const K=T&&!W&&!E;c.clickDistance(H?1/0:!ct(Q)||Q<0?0:Q);const ee=K?tk({zoomPanValues:u,noWheelClassName:z,d3Selection:d,d3Zoom:c,panOnScrollMode:L,panOnScrollSpeed:b,zoomOnPinch:$,onPanZoomStart:s,onPanZoom:i,onPanZoomEnd:l}):nk({noWheelClassName:z,preventScrolling:N,d3ZoomHandler:x});if(d.on("wheel.zoom",ee,{passive:!1}),!E){const J=rk({zoomPanValues:u,onDraggingChange:a,onPanZoomStart:s});c.on("start",J);const q=ok({zoomPanValues:u,panOnDrag:P,onPaneContextMenu:!!R,onPanZoom:i,onTransformChange:Y});c.on("zoom",q);const re=ik({zoomPanValues:u,panOnDrag:P,panOnScroll:T,onPaneContextMenu:R,onPanZoomEnd:l,onDraggingChange:a});c.on("end",re)}const G=sk({zoomActivationKeyPressed:W,panOnDrag:P,zoomOnScroll:O,panOnScroll:T,zoomOnDoubleClick:B,zoomOnPinch:$,userSelectionActive:E,noPanClassName:D,noWheelClassName:z,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(z,D,R){const E=Al(z),T=c==null?void 0:c.constrain()(E,D,R);return T&&await w(T),new Promise(P=>P(T))}async function h(z,D){const R=Al(z);return await w(R,D),new Promise(E=>E(R))}function v(z){if(d){const D=Al(z),R=d.property("__zoom");(R.k!==z.zoom||R.x!==z.x||R.y!==z.y)&&(c==null||c.transform(d,D,null,{sync:!0}))}}function S(){const z=d?Hg(d.node()):{x:0,y:0,k:1};return{x:z.x,y:z.y,zoom:z.k}}function k(z,D){return d?new Promise(R=>{c==null||c.interpolate((D==null?void 0:D.interpolate)==="linear"?ao:Hi).scaleTo($l(d,D==null?void 0:D.duration,D==null?void 0:D.ease,()=>R(!0)),z)}):Promise.resolve(!1)}function C(z,D){return d?new Promise(R=>{c==null||c.interpolate((D==null?void 0:D.interpolate)==="linear"?ao:Hi).scaleBy($l(d,D==null?void 0:D.duration,D==null?void 0:D.ease,()=>R(!0)),z)}):Promise.resolve(!1)}function j(z){c==null||c.scaleExtent(z)}function I(z){c==null||c.translateExtent(z)}function A(z){const D=!ct(z)||z<0?0:z;c==null||c.clickDistance(D)}return{update:_,destroy:m,setViewport:h,setViewportConstrained:g,getViewport:S,scaleTo:k,scaleBy:C,setScaleExtent:j,setTranslateExtent:I,syncViewport:v,setClickDistance:A}}var An;(function(e){e.Line="line",e.Handle="handle"})(An||(An={}));const ak=["top-left","top-right","bottom-left","bottom-right"],uk=["top","right","bottom","left"];function ck({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 hf(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 wi(e,t,n){return Math.max(0,t-e,e-n)}function gf(e,t){return e?!t:t}function dk(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:_,minHeight:m,maxHeight:g}=r,{x:h,y:v,width:S,height:k,aspectRatio:C}=e;let j=Math.floor(p?x-e.pointerX:0),I=Math.floor(c?y-e.pointerY:0);const A=S+(a?-j:j),z=k+(u?-I:I),D=-i[0]*S,R=-i[1]*k;let E=wi(A,w,_),T=wi(z,m,g);if(s){let b=0,N=0;a&&j<0?b=Ut(h+j+D,s[0][0]):!a&&j>0&&(b=Yt(h+A+D,s[1][0])),u&&I<0?N=Ut(v+I+R,s[0][1]):!u&&I>0&&(N=Yt(v+z+R,s[1][1])),E=Math.max(E,b),T=Math.max(T,N)}if(l){let b=0,N=0;a&&j>0?b=Yt(h+j,l[0][0]):!a&&j<0&&(b=Ut(h+A,l[1][0])),u&&I>0?N=Yt(v+I,l[0][1]):!u&&I<0&&(N=Ut(v+z,l[1][1])),E=Math.max(E,b),T=Math.max(T,N)}if(o){if(p){const b=wi(A/C,m,g)*C;if(E=Math.max(E,b),s){let N=0;!a&&!u||a&&!u&&d?N=Yt(v+R+A/C,s[1][1])*C:N=Ut(v+R+(a?j:-j)/C,s[0][1])*C,E=Math.max(E,N)}if(l){let N=0;!a&&!u||a&&!u&&d?N=Ut(v+A/C,l[1][1])*C:N=Yt(v+(a?j:-j)/C,l[0][1])*C,E=Math.max(E,N)}}if(c){const b=wi(z*C,w,_)/C;if(T=Math.max(T,b),s){let N=0;!a&&!u||u&&!a&&d?N=Yt(h+z*C+D,s[1][0])/C:N=Ut(h+(u?I:-I)*C+D,s[0][0])/C,T=Math.max(T,N)}if(l){let N=0;!a&&!u||u&&!a&&d?N=Ut(h+z*C,l[1][0])/C:N=Yt(h+(u?I:-I)*C,l[0][0])/C,T=Math.max(T,N)}}}I=I+(I<0?T:-T),j=j+(j<0?E:-E),o&&(d?A>z*C?I=(gf(a,u)?-j:j)/C:j=(gf(a,u)?-I:I)*C:p?(I=j/C,u=a):(j=I*C,a=u));const P=a?h+j:h,L=u?v+I:v;return{width:S+(a?-j:j),height:k+(u?-I:I),x:i[0]*j*(a?-1:1)+P,y:i[1]*I*(u?-1:1)+L}}const x0={width:0,height:0,x:0,y:0},fk={...x0,pointerX:0,pointerY:0,aspectRatio:1};function pk(e){return[[0,0],[e.measured.width,e.measured.height]]}function hk(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 gk({domNode:e,nodeId:t,getStoreItems:n,onChange:r,onEnd:o}){const i=We(e);let s={controlDirection:hf("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:_}){let m={...x0},g={...fk};s={boundaries:p,resizeDirection:d,keepAspectRatio:c,controlDirection:hf(u)};let h,v=null,S=[],k,C,j,I=!1;const A=jg().on("start",z=>{const{nodeLookup:D,transform:R,snapGrid:E,snapToGrid:T,nodeOrigin:P,paneDomNode:L}=n();if(h=D.get(t),!h)return;v=(L==null?void 0:L.getBoundingClientRect())??null;const{xSnapped:b,ySnapped:N}=uo(z.sourceEvent,{transform:R,snapGrid:E,snapToGrid:T,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:b,pointerY:N,aspectRatio:m.width/m.height},k=void 0,h.parentId&&(h.extent==="parent"||h.expandParent)&&(k=D.get(h.parentId),C=k&&h.extent==="parent"?pk(k):void 0),S=[],j=void 0;for(const[$,O]of D)if(O.parentId===t&&(S.push({id:$,position:{...O.position},extent:O.extent}),O.extent==="parent"||O.expandParent)){const B=hk(O,h,O.origin??P);j?j=[[Math.min(B[0][0],j[0][0]),Math.min(B[0][1],j[0][1])],[Math.max(B[1][0],j[1][0]),Math.max(B[1][1],j[1][1])]]:j=B}x==null||x(z,{...m})}).on("drag",z=>{const{transform:D,snapGrid:R,snapToGrid:E,nodeOrigin:T}=n(),P=uo(z.sourceEvent,{transform:D,snapGrid:R,snapToGrid:E,containerBounds:v}),L=[];if(!h)return;const{x:b,y:N,width:$,height:O}=m,B={},W=h.origin??T,{width:V,height:Y,x:X,y:Q}=dk(g,s.controlDirection,P,s.boundaries,s.keepAspectRatio,W,C,j),H=V!==$,K=Y!==O,ee=X!==b&&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,S.length>0)){const le=X-b,ie=Q-N;for(const je of S)je.position={x:je.position.x-le+W[0]*(V-$),y:je.position.y-ie+W[1]*(Y-O)},L.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),k&&h.expandParent){const le=W[0]*(B.width??0);B.x&&B.x{I&&(w==null||w(z,{...m}),o==null||o({...m}),I=!1)});i.call(A)}function a(){i.on(".drag",null)}return{update:l,destroy:a}}var v0={exports:{}},w0={},S0={exports:{}},k0={};/** - * @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=M;function mk(e,t){return e===t&&(e!==0||1/e===1/t)||e!==e&&t!==t}var yk=typeof Object.is=="function"?Object.is:mk,xk=Er.useState,vk=Er.useEffect,wk=Er.useLayoutEffect,Sk=Er.useDebugValue;function kk(e,t){var n=t(),r=xk({inst:{value:n,getSnapshot:t}}),o=r[0].inst,i=r[1];return wk(function(){o.value=n,o.getSnapshot=t,Dl(o)&&i({inst:o})},[e,n,t]),vk(function(){return Dl(o)&&i({inst:o}),e(function(){Dl(o)&&i({inst:o})})},[e]),Sk(n),n}function Dl(e){var t=e.getSnapshot;e=e.value;try{var n=t();return!yk(e,n)}catch{return!0}}function _k(e,t){return t()}var Ek=typeof window>"u"||typeof window.document>"u"||typeof window.document.createElement>"u"?_k:kk;k0.useSyncExternalStore=Er.useSyncExternalStore!==void 0?Er.useSyncExternalStore:Ek;S0.exports=k0;var Ck=S0.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,bk=Ck;function Nk(e,t){return e===t&&(e!==0||1/e===1/t)||e!==e&&t!==t}var jk=typeof Object.is=="function"?Object.is:Nk,Mk=bk.useSyncExternalStore,zk=qs.useRef,Pk=qs.useEffect,Tk=qs.useMemo,Ik=qs.useDebugValue;w0.useSyncExternalStoreWithSelector=function(e,t,n,r,o){var i=zk(null);if(i.current===null){var s={hasValue:!1,value:null};i.current=s}else s=i.current;i=Tk(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,jk(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=Mk(e,i[0],i[1]);return Pk(function(){s.hasValue=!0,s.value=l},[l]),Ik(l),l};v0.exports=w0;var Rk=v0.exports;const Lk=ep(Rk),Ak={},mf=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:()=>{(Ak?"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},$k=e=>e?mf(e):mf,{useDebugValue:Dk}=dp,{useSyncExternalStoreWithSelector:Ok}=Lk,Bk=e=>e;function _0(e,t=Bk,n){const r=Ok(e.subscribe,e.getState,e.getServerState||e.getInitialState,t,n);return Dk(r),r}const yf=(e,t)=>{const n=$k(e),r=(o,i=t)=>_0(n,o,i);return Object.assign(r,n),r},Fk=(e,t)=>e?yf(e,t):yf;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 Zs=M.createContext(null),Hk=Zs.Provider,E0=bt.error001();function ne(e,t){const n=M.useContext(Zs);if(n===null)throw new Error(E0);return _0(n,e,t)}function pe(){const e=M.useContext(Zs);if(e===null)throw new Error(E0);return M.useMemo(()=>({getState:e.getState,setState:e.setState,subscribe:e.subscribe}),[e])}const xf={display:"none"},Vk={position:"absolute",width:1,height:1,margin:-1,border:0,padding:0,overflow:"hidden",clip:"rect(0px, 0px, 0px, 0px)",clipPath:"inset(100%)"},C0="react-flow__node-desc",b0="react-flow__edge-desc",Wk="react-flow__aria-live",Uk=e=>e.ariaLiveMessage,Yk=e=>e.ariaLabelConfig;function Xk({rfId:e}){const t=ne(Uk);return f.jsx("div",{id:`${Wk}-${e}`,"aria-live":"assertive","aria-atomic":"true",style:Vk,children:t})}function Qk({rfId:e,disableKeyboardA11y:t}){const n=ne(Yk);return f.jsxs(f.Fragment,{children:[f.jsx("div",{id:`${C0}-${e}`,style:xf,children:t?n["node.a11yDescription.default"]:n["node.a11yDescription.keyboardDisabled"]}),f.jsx("div",{id:`${b0}-${e}`,style:xf,children:n["edge.a11yDescription.default"]}),!t&&f.jsx(Xk,{rfId:e})]})}const Js=M.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})});Js.displayName="Panel";function Gk({proOptions:e,position:t="bottom-right"}){return e!=null&&e.hideAttribution?null:f.jsx(Js,{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 Kk=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}},Si=e=>e.id;function qk(e,t){return fe(e.selectedNodes.map(Si),t.selectedNodes.map(Si))&&fe(e.selectedEdges.map(Si),t.selectedEdges.map(Si))}function Zk({onSelectionChange:e}){const t=pe(),{selectedNodes:n,selectedEdges:r}=ne(Kk,qk);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 Jk=e=>!!e.onSelectionChangeHandlers;function e_({onSelectionChange:e}){const t=ne(Jk);return e||t?f.jsx(Zk,{onSelectionChange:e}):null}const N0=[0,0],t_={x:0,y:0,zoom:1},n_=["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"],vf=[...n_,"rfId"],r_=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}),wf={translateExtent:To,nodeOrigin:N0,minZoom:.5,maxZoom:2,elementsSelectable:!0,noPanClassName:"nopan",rfId:"1"};function o_(e){const{setNodes:t,setEdges:n,setMinZoom:r,setMaxZoom:o,setTranslateExtent:i,setNodeExtent:s,reset:l,setDefaultNodesAndEdges:a}=ne(r_,fe),u=pe();M.useEffect(()=>(a(e.defaultNodes,e.defaultEdges),()=>{p.current=wf,l()}),[]);const p=M.useRef(wf);return M.useEffect(()=>{for(const c of vf){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:CS(d)}):c==="fitView"?u.setState({fitViewQueued:d}):c==="fitViewOptions"?u.setState({fitViewOptions:d}):u.setState({[c]:d})))}p.current=e},vf.map(c=>e[c])),null}function Sf(){return typeof window>"u"||!window.matchMedia?null:window.matchMedia("(prefers-color-scheme: dark)")}function i_(e){var r;const[t,n]=M.useState(e==="system"?null:e);return M.useEffect(()=>{if(e!=="system"){n(e);return}const o=Sf(),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=Sf())!=null&&r.matches?"dark":"light"}const kf=typeof document<"u"?document:null;function Ao(e=null,t={target:kf,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,d)=>c.concat(...d),[]);return[u,p]}return[[],[]]},[e]);return M.useEffect(()=>{const a=(t==null?void 0:t.target)??kf,u=(t==null?void 0:t.actInsideInputWithModifier)??!0;if(e!==null){const p=x=>{var _,m;if(o.current=x.ctrlKey||x.metaKey||x.shiftKey||x.altKey,(!o.current||o.current&&!u)&&n0(x))return!1;const w=Ef(x.code,l);if(i.current.add(x[w]),_f(s,i.current,!1)){const g=((m=(_=x.composedPath)==null?void 0:_.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);_f(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 _f(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 s_=()=>{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=uc(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=Cs(t,n);return{x:s.x+o,y:s.y+i}}}),[])};function j0(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)l_(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 l_(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 M0(e,t){return j0(e,t)}function z0(e,t){return j0(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 Cf({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 bf(e){return{id:e.id,type:"remove"}}const Nf=e=>gS(e),a_=e=>Qg(e);function P0(e){return M.forwardRef(e)}const u_=typeof window<"u"?M.useLayoutEffect:M.useEffect;function jf(e){const[t,n]=M.useState(BigInt(0)),[r]=M.useState(()=>c_(()=>n(o=>o+BigInt(1))));return u_(()=>{const o=r.get();o.length&&(e(o),r.reset())},[t]),r}function c_(e){let t=[];return{get:()=>t,reset:()=>{t=[]},push:n=>{t.push(n),e()}}}const T0=M.createContext(null);function d_({children:e}){const t=pe(),n=M.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 _=Cf({items:w,lookup:d});for(const m of y.values())_=m(_);p&&u(w),_.length>0?c==null||c(_):x&&window.requestAnimationFrame(()=>{const{fitViewQueued:m,nodes:g,setNodes:h}=t.getState();m&&h(g)})},[]),r=jf(n),o=M.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(Cf({items:x,lookup:d}))},[]),i=jf(o),s=M.useMemo(()=>({nodeQueue:r,edgeQueue:i}),[]);return f.jsx(T0.Provider,{value:s,children:e})}function f_(){const e=M.useContext(T0);if(!e)throw new Error("useBatchContext must be used within a BatchProvider");return e}const p_=e=>!!e.panZoom;function mc(){const e=s_(),t=pe(),n=f_(),r=ne(p_),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:d,nodeOrigin:x}=t.getState(),y=Nf(c)?c:d.get(c.id),w=y.parentId?e0(y.position,y.measured,y.parentId,d,x):y.position,_={...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(_)},u=(c,d,x={replace:!1})=>{s(y=>y.map(w=>{if(w.id===c){const _=typeof d=="function"?d(w):d;return x.replace&&Nf(_)?_:{...w,..._}}return w}))},p=(c,d,x={replace:!1})=>{l(y=>y.map(w=>{if(w.id===c){const _=typeof d=="function"?d(w):d;return x.replace&&a_(_)?_:{...w,..._}}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,_]=x;return{nodes:c.map(m=>({...m})),edges:d.map(m=>({...m})),viewport:{x:y,y:w,zoom:_}}},deleteElements:async({nodes:c=[],edges:d=[]})=>{const{nodes:x,edges:y,onNodesDelete:w,onEdgesDelete:_,triggerNodeChanges:m,triggerEdgeChanges:g,onDelete:h,onBeforeDelete:v}=t.getState(),{nodes:S,edges:k}=await wS({nodesToRemove:c,edgesToRemove:d,nodes:x,edges:y,onBeforeDelete:v}),C=k.length>0,j=S.length>0;if(C){const I=k.map(bf);_==null||_(k),g(I)}if(j){const I=S.map(bf);w==null||w(S),m(I)}return(j||C)&&(h==null||h({nodes:S,edges:k})),{deletedNodes:S,deletedEdges:k}},getIntersectingNodes:(c,d=!0,x)=>{const y=nf(c),w=y?c:a(c),_=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(_?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=nf(c)?c:a(c);if(!w)return!1;const _=Ro(w,d);return x&&_>0||_>=d.width*d.height||_>=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 mS(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??ES();return t.setState({fitViewQueued:!0,fitViewOptions:c,fitViewResolver:d}),n.nodeQueue.push(x=>[...x]),d.promise}}},[]);return M.useMemo(()=>({...o,...e,viewportInitialized:r}),[r])}const Mf=e=>e.selected,h_=typeof window<"u"?window:void 0;function g_({deleteKeyCode:e,multiSelectionKeyCode:t}){const n=pe(),{deleteElements:r}=mc(),o=Ao(e,{actInsideInputWithModifier:!1}),i=Ao(t,{target:h_});M.useEffect(()=>{if(o){const{edges:s,nodes:l}=n.getState();r({nodes:l.filter(Mf),edges:s.filter(Mf)}),n.setState({nodesSelectionActive:!1})}},[o]),M.useEffect(()=>{n.setState({multiSelectionActive:i})},[i])}function m_(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=cc(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 el={position:"absolute",width:"100%",height:"100%",top:0,left:0},y_=e=>({userSelectionActive:e.userSelectionActive,lib:e.lib,connectionInProgress:e.connection.inProgress});function x_({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:_,onViewportChange:m,isControlledViewport:g,paneClickDistance:h,selectionOnDrag:v}){const S=pe(),k=M.useRef(null),{userSelectionActive:C,lib:j,connectionInProgress:I}=ne(y_,fe),A=Ao(d),z=M.useRef();m_(k);const D=M.useCallback(R=>{m==null||m({x:R[0],y:R[1],zoom:R[2]}),g||S.setState({transform:R})},[m,g]);return M.useEffect(()=>{if(k.current){z.current=lk({domNode:k.current,minZoom:p,maxZoom:c,translateExtent:u,viewport:a,onDraggingChange:P=>S.setState(L=>L.paneDragging===P?L:{paneDragging:P}),onPanZoomStart:(P,L)=>{const{onViewportChangeStart:b,onMoveStart:N}=S.getState();N==null||N(P,L),b==null||b(L)},onPanZoom:(P,L)=>{const{onViewportChange:b,onMove:N}=S.getState();N==null||N(P,L),b==null||b(L)},onPanZoomEnd:(P,L)=>{const{onViewportChangeEnd:b,onMoveEnd:N}=S.getState();N==null||N(P,L),b==null||b(L)}});const{x:R,y:E,zoom:T}=z.current.getViewport();return S.setState({panZoom:z.current,transform:[R,E,T],domNode:k.current.closest(".react-flow")}),()=>{var P;(P=z.current)==null||P.destroy()}}},[]),M.useEffect(()=>{var R;(R=z.current)==null||R.update({onPaneContextMenu:e,zoomOnScroll:t,zoomOnPinch:n,panOnScroll:r,panOnScrollSpeed:o,panOnScrollMode:i,zoomOnDoubleClick:s,panOnDrag:l,zoomActivationKeyPressed:A,preventScrolling:x,noPanClassName:_,userSelectionActive:C,noWheelClassName:w,lib:j,onTransformChange:D,connectionInProgress:I,selectionOnDrag:v,paneClickDistance:h})},[e,t,n,r,o,i,s,l,A,x,_,C,w,j,D,I,v,h]),f.jsx("div",{className:"react-flow__renderer",ref:k,style:el,children:y})}const v_=e=>({userSelectionActive:e.userSelectionActive,userSelectionRect:e.userSelectionRect});function w_(){const{userSelectionActive:e,userSelectionRect:t}=ne(v_,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 Ol=(e,t)=>n=>{n.target===t.current&&(e==null||e(n))},S_=e=>({userSelectionActive:e.userSelectionActive,elementsSelectable:e.elementsSelectable,connectionInProgress:e.connection.inProgress,dragging:e.paneDragging});function k_({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:_,elementsSelectable:m,dragging:g,connectionInProgress:h}=ne(S_,fe),v=m&&(e||_),S=M.useRef(null),k=M.useRef(),C=M.useRef(new Set),j=M.useRef(new Set),I=M.useRef(!1),A=b=>{if(I.current||h){I.current=!1;return}a==null||a(b),w.getState().resetSelectedElements(),w.setState({nodesSelectionActive:!1})},z=b=>{if(Array.isArray(r)&&(r!=null&&r.includes(2))){b.preventDefault();return}u==null||u(b)},D=p?b=>p(b):void 0,R=b=>{I.current&&(b.stopPropagation(),I.current=!1)},E=b=>{var Y,X;const{domNode:N}=w.getState();if(k.current=N==null?void 0:N.getBoundingClientRect(),!k.current)return;const $=b.target===S.current;if(!$&&!!b.target.closest(".nokey")||!e||!(i&&$||t)||b.button!==0||!b.isPrimary)return;(X=(Y=b.target)==null?void 0:Y.setPointerCapture)==null||X.call(Y,b.pointerId),I.current=!1;const{x:W,y:V}=dt(b.nativeEvent,k.current);w.setState({userSelectionRect:{width:0,height:0,startX:W,startY:V,x:W,y:V}}),$||(b.stopPropagation(),b.preventDefault())},T=b=>{const{userSelectionRect:N,transform:$,nodeLookup:O,edgeLookup:B,connectionLookup:W,triggerNodeChanges:V,triggerEdgeChanges:Y,defaultEdgeOptions:X,resetSelectedElements:Q}=w.getState();if(!k.current||!N)return;const{x:H,y:K}=dt(b.nativeEvent,k.current),{startX:ee,startY:G}=N;if(!I.current){const ie=t?0:o;if(Math.hypot(H-ee,K-G)<=ie)return;Q(),s==null||s(b)}I.current=!0;const J={startX:ee,startY:G,x:Hie.id)),j.current=new Set;const le=(X==null?void 0:X.selectable)??!0;for(const ie of C.current){const je=W.get(ie);if(je)for(const{edgeId:Vt}of je.values()){const jt=B.get(Vt);jt&&(jt.selectable??le)&&j.current.add(Vt)}}if(!rf(q,C.current)){const ie=nr(O,C.current,!0);V(ie)}if(!rf(re,j.current)){const ie=nr(B,j.current);Y(ie)}w.setState({userSelectionRect:J,userSelectionActive:!0,nodesSelectionActive:!1})},P=b=>{var N,$;b.button===0&&(($=(N=b.target)==null?void 0:N.releasePointerCapture)==null||$.call(N,b.pointerId),!_&&b.target===S.current&&w.getState().userSelectionRect&&(A==null||A(b)),w.setState({userSelectionActive:!1,userSelectionRect:null}),I.current&&(l==null||l(b),w.setState({nodesSelectionActive:C.current.size>0})))},L=r===!0||Array.isArray(r)&&r.includes(0);return f.jsxs("div",{className:we(["react-flow__pane",{draggable:L,dragging:g,selection:e}]),onClick:v?void 0:Ol(A,S),onContextMenu:Ol(z,S),onWheel:Ol(D,S),onPointerEnter:v?void 0:c,onPointerMove:v?T:d,onPointerUp:v?P:void 0,onPointerDownCapture:v?E:void 0,onClickCapture:v?R:void 0,onPointerLeave:x,ref:S,style:el,children:[y,f.jsx(w_,{})]})}function nu({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 I0({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=XS({getStoreItems:()=>l.getState(),onNodeMouseDown:c=>{nu({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=>t=>t.selected&&(t.draggable||e&&typeof t.draggable>"u");function R0(){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,d=__(s),x=o?i[0]:5,y=o?i[1]:5,w=n.direction.x*x*n.factor,_=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+_};o&&(g=Xo(g,i));const{position:h,positionAbsolute:v}=Gg({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 yc=M.createContext(null),E_=yc.Provider;yc.Consumer;const L0=()=>M.useContext(yc),C_=e=>({connectOnClick:e.connectOnClick,noPanClassName:e.noPanClassName,rfId:e.rfId}),b_=(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 N_({type:e="source",position:t=Z.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 T,P;const y=s||null,w=e==="target",_=pe(),m=L0(),{connectOnClick:g,noPanClassName:h,rfId:v}=ne(C_,fe),{connectingFrom:S,connectingTo:k,clickConnecting:C,isPossibleEndHandle:j,connectionInProcess:I,clickConnectionInProcess:A,valid:z}=ne(b_(m,y,e),fe);m||(P=(T=_.getState()).onError)==null||P.call(T,"010",bt.error010());const D=L=>{const{defaultEdgeOptions:b,onConnect:N,hasDefaultEdges:$}=_.getState(),O={...b,...L};if($){const{edges:B,setEdges:W}=_.getState();W(PS(O,B))}N==null||N(O),l==null||l(O)},R=L=>{if(!m)return;const b=r0(L.nativeEvent);if(o&&(b&&L.button===0||!b)){const N=_.getState();tu.onPointerDown(L.nativeEvent,{handleDomNode:L.currentTarget,autoPanOnConnect:N.autoPanOnConnect,connectionMode:N.connectionMode,connectionRadius:N.connectionRadius,domNode:N.domNode,nodeLookup:N.nodeLookup,lib:N.lib,isTarget:w,handleId:y,nodeId:m,flowId:N.rfId,panBy:N.panBy,cancelConnection:N.cancelConnection,onConnectStart:N.onConnectStart,onConnectEnd:(...$)=>{var O,B;return(B=(O=_.getState()).onConnectEnd)==null?void 0:B.call(O,...$)},updateConnection:N.updateConnection,onConnect:D,isValidConnection:n||((...$)=>{var O,B;return((B=(O=_.getState()).isValidConnection)==null?void 0:B.call(O,...$))??!0}),getTransform:()=>_.getState().transform,getFromHandle:()=>_.getState().connection.fromHandle,autoPanSpeed:N.autoPanSpeed,dragThreshold:N.connectionDragThreshold})}b?p==null||p(L):c==null||c(L)},E=L=>{const{onClickConnectStart:b,onClickConnectEnd:N,connectionClickStartHandle:$,connectionMode:O,isValidConnection:B,lib:W,rfId:V,nodeLookup:Y,connection:X}=_.getState();if(!m||!$&&!o)return;if(!$){b==null||b(L.nativeEvent,{nodeId:m,handleId:y,handleType:e}),_.setState({connectionClickStartHandle:{nodeId:m,type:e,id:y}});return}const Q=t0(L.target),H=n||B,{connection:K,isValid:ee}=tu.isValid(L.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&&D(K);const G=structuredClone(X);delete G.inProgress,G.toPosition=G.toHandle?G.toHandle.position:null,N==null||N(L,G),_.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:C,connectingfrom:S,connectingto:k,valid:z,connectionindicator:r&&(!I||j)&&(I||A?i:o)}]),onMouseDown:R,onTouchStart:R,onClick:g?E:void 0,ref:x,...d,children:a})}const Cr=M.memo(P0(N_));function j_({data:e,isConnectable:t,sourcePosition:n=Z.Bottom}){return f.jsxs(f.Fragment,{children:[e==null?void 0:e.label,f.jsx(Cr,{type:"source",position:n,isConnectable:t})]})}function M_({data:e,isConnectable:t,targetPosition:n=Z.Top,sourcePosition:r=Z.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 z_(){return null}function P_({data:e,isConnectable:t,targetPosition:n=Z.Top}){return f.jsxs(f.Fragment,{children:[f.jsx(Cr,{type:"target",position:n,isConnectable:t}),e==null?void 0:e.label]})}const bs={ArrowUp:{x:0,y:-1},ArrowDown:{x:0,y:1},ArrowLeft:{x:-1,y:0},ArrowRight:{x:1,y:0}},zf={input:j_,default:M_,output:P_,group:z_};function T_(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 I_=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 R_({onSelectionContextMenu:e,noPanClassName:t,disableKeyboardA11y:n}){const r=pe(),{width:o,height:i,transformString:s,userSelectionActive:l}=ne(I_,fe),a=R0(),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(I0({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(bs,x.key)&&(x.preventDefault(),a({direction:bs[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 Pf=typeof window<"u"?window:void 0,L_=e=>({nodesSelectionActive:e.nodesSelectionActive,userSelectionActive:e.userSelectionActive});function A0({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:_,elementsSelectable:m,zoomOnScroll:g,zoomOnPinch:h,panOnScroll:v,panOnScrollSpeed:S,panOnScrollMode:k,zoomOnDoubleClick:C,panOnDrag:j,defaultViewport:I,translateExtent:A,minZoom:z,maxZoom:D,preventScrolling:R,onSelectionContextMenu:E,noWheelClassName:T,noPanClassName:P,disableKeyboardA11y:L,onViewportChange:b,isControlledViewport:N}){const{nodesSelectionActive:$,userSelectionActive:O}=ne(L_,fe),B=Ao(u,{target:Pf}),W=Ao(w,{target:Pf}),V=W||j,Y=W||v,X=p&&V!==!0,Q=B||O||X;return g_({deleteKeyCode:a,multiSelectionKeyCode:y}),f.jsx(x_,{onPaneContextMenu:i,elementsSelectable:m,zoomOnScroll:g,zoomOnPinch:h,panOnScroll:Y,panOnScrollSpeed:S,panOnScrollMode:k,zoomOnDoubleClick:C,panOnDrag:!B&&V,defaultViewport:I,translateExtent:A,minZoom:z,maxZoom:D,zoomActivationKeyCode:_,preventScrolling:R,noWheelClassName:T,noPanClassName:P,onViewportChange:b,isControlledViewport:N,paneClickDistance:l,selectionOnDrag:X,children:f.jsxs(k_,{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(R_,{onSelectionContextMenu:E,noPanClassName:P,disableKeyboardA11y:L})]})})}A0.displayName="FlowRenderer";const A_=M.memo(A0),$_=e=>t=>e?ac(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 D_(e){return ne(M.useCallback($_(e),[e]),fe)}const O_=e=>e.updateNodeInternals;function B_(){const e=ne(O_),[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 F_({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,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 H_({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:_,nodeClickDistance:m,onError:g}){const{node:h,internals:v,isParent:S}=ne(H=>{const K=H.nodeLookup.get(e),ee=H.parentLookup.has(e);return{node:K,internals:K.internals,isParent:ee}},fe);let k=h.type||"default",C=(_==null?void 0:_[k])||zf[k];C===void 0&&(g==null||g("003",bt.error003(k)),k="default",C=(_==null?void 0:_.default)||zf.default);const j=!!(h.draggable||l&&typeof h.draggable>"u"),I=!!(h.selectable||a&&typeof h.selectable>"u"),A=!!(h.connectable||u&&typeof h.connectable>"u"),z=!!(h.focusable||p&&typeof h.focusable>"u"),D=pe(),R=Jg(h),E=F_({node:h,nodeType:k,hasDimensions:R,resizeObserver:c}),T=I0({nodeRef:E,disabled:h.hidden||!j,noDragClassName:d,handleSelector:h.dragHandle,nodeId:e,isSelectable:I,nodeClickDistance:m}),P=R0();if(h.hidden)return null;const L=Ht(h),b=T_(h),N=I||j||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}=D.getState();I&&(!K||!j||ee>0)&&nu({id:e,store:D,nodeRef:E}),t&&t(H,{...v.userNode})},X=H=>{if(!(n0(H.nativeEvent)||y)){if(Wg.includes(H.key)&&I){const K=H.key==="Escape";nu({id:e,store:D,unselect:K,nodeRef:E})}else if(j&&h.selected&&Object.prototype.hasOwnProperty.call(bs,H.key)){H.preventDefault();const{ariaLabelConfig:K}=D.getState();D.setState({ariaLiveMessage:K["node.a11yDescription.ariaLiveMessage"]({direction:H.key.replace("Arrow","").toLowerCase(),x:~~v.positionAbsolute.x,y:~~v.positionAbsolute.y})}),P({direction:bs[H.key],factor:H.shiftKey?4:1})}}},Q=()=>{var re;if(y||!((re=E.current)!=null&&re.matches(":focus-visible")))return;const{transform:H,width:K,height:ee,autoPanOnNodeFocus:G,setCenter:J}=D.getState();if(!G)return;ac(new Map([[e,h]]),{x:0,y:0,width:K,height:ee},H,!0).length>0||J(h.position.x+L.width/2,h.position.y+L.height/2,{zoom:H[2]})};return f.jsx("div",{className:we(["react-flow__node",`react-flow__node-${k}`,{[x]:j},h.className,{selected:h.selected,selectable:I,parent:S,draggable:j,dragging:T}]),ref:E,style:{zIndex:v.z,transform:`translate(${v.positionAbsolute.x}px,${v.positionAbsolute.y}px)`,pointerEvents:N?"all":"none",visibility:R?"visible":"hidden",...h.style,...b},"data-id":e,"data-testid":`rf__node-${e}`,onMouseEnter:$,onMouseMove:O,onMouseLeave:B,onContextMenu:W,onClick:Y,onDoubleClick:V,onKeyDown:z?X:void 0,tabIndex:z?0:void 0,onFocus:z?Q:void 0,role:h.ariaRole??(z?"group":void 0),"aria-roledescription":"node","aria-describedby":y?void 0:`${C0}-${w}`,"aria-label":h.ariaLabel,...h.domAttributes,children:f.jsx(E_,{value:e,children:f.jsx(C,{id:e,data:h.data,type:k,positionAbsoluteX:v.positionAbsolute.x,positionAbsoluteY:v.positionAbsolute.y,selected:h.selected??!1,selectable:I,draggable:j,deletable:h.deletable??!0,isConnectable:A,sourcePosition:h.sourcePosition,targetPosition:h.targetPosition,dragging:T,dragHandle:h.dragHandle,zIndex:v.z,parentId:h.parentId,...L})})})}var V_=M.memo(H_);const W_=e=>({nodesDraggable:e.nodesDraggable,nodesConnectable:e.nodesConnectable,nodesFocusable:e.nodesFocusable,elementsSelectable:e.elementsSelectable,onError:e.onError});function $0(e){const{nodesDraggable:t,nodesConnectable:n,nodesFocusable:r,elementsSelectable:o,onError:i}=ne(W_,fe),s=D_(e.onlyRenderVisibleElements),l=B_();return f.jsx("div",{className:"react-flow__nodes",style:el,children:s.map(a=>f.jsx(V_,{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))})}$0.displayName="NodeRenderer";const U_=M.memo($0);function Y_(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&&jS({sourceNode:i,targetNode:s,width:n.width,height:n.height,transform:n.transform})&&r.push(o.id)}return r},[e]),fe)}const X_=({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"})},Q_=({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"})},Tf={[_s.Arrow]:X_,[_s.ArrowClosed]:Q_};function G_(e){const t=pe();return M.useMemo(()=>{var o,i;return Object.prototype.hasOwnProperty.call(Tf,e)?Tf[e]:((i=(o=t.getState()).onError)==null||i.call(o,"009",bt.error009(e)),null)},[e])}const K_=({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=G_(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},D0=({defaultColor:e,rfId:t})=>{const n=ne(i=>i.edges),r=ne(i=>i.defaultEdgeOptions),o=M.useMemo(()=>AS(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(K_,{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};D0.displayName="MarkerDefinitions";var q_=M.memo(D0);function O0({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]=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 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}O0.displayName="EdgeText";const Z_=M.memo(O0);function tl({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(Z_,{x:t,y:n,label:r,labelStyle:o,labelShowBg:i,labelBgStyle:s,labelBgPadding:l,labelBgBorderRadius:a}):null]})}function If({pos:e,x1:t,y1:n,x2:r,y2:o}){return e===Z.Left||e===Z.Right?[.5*(t+r),n]:[t,.5*(n+o)]}function B0({sourceX:e,sourceY:t,sourcePosition:n=Z.Bottom,targetX:r,targetY:o,targetPosition:i=Z.Top}){const[s,l]=If({pos:n,x1:e,y1:t,x2:r,y2:o}),[a,u]=If({pos:i,x1:r,y1:o,x2:e,y2:t}),[p,c,d,x]=o0({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 F0(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:d,labelBgBorderRadius:x,style:y,markerEnd:w,markerStart:_,interactionWidth:m})=>{const[g,h,v]=B0({sourceX:n,sourceY:r,sourcePosition:s,targetX:o,targetY:i,targetPosition:l}),S=e.isInternal?void 0:t;return f.jsx(tl,{id:S,path:g,labelX:h,labelY:v,label:a,labelStyle:u,labelShowBg:p,labelBgStyle:c,labelBgPadding:d,labelBgBorderRadius:x,style:y,markerEnd:w,markerStart:_,interactionWidth:m})})}const J_=F0({isInternal:!1}),H0=F0({isInternal:!0});J_.displayName="SimpleBezierEdge";H0.displayName="SimpleBezierEdgeInternal";function V0(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:d,sourcePosition:x=Z.Bottom,targetPosition:y=Z.Top,markerEnd:w,markerStart:_,pathOptions:m,interactionWidth:g})=>{const[h,v,S]=Za({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}),k=e.isInternal?void 0:t;return f.jsx(tl,{id:k,path:h,labelX:v,labelY:S,label:s,labelStyle:l,labelShowBg:a,labelBgStyle:u,labelBgPadding:p,labelBgBorderRadius:c,style:d,markerEnd:w,markerStart:_,interactionWidth:g})})}const W0=V0({isInternal:!1}),U0=V0({isInternal:!0});W0.displayName="SmoothStepEdge";U0.displayName="SmoothStepEdgeInternal";function Y0(e){return M.memo(({id:t,...n})=>{var o;const r=e.isInternal?void 0:t;return f.jsx(W0,{...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 eE=Y0({isInternal:!1}),X0=Y0({isInternal:!0});eE.displayName="StepEdge";X0.displayName="StepEdgeInternal";function Q0(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:d,markerEnd:x,markerStart:y,interactionWidth:w})=>{const[_,m,g]=l0({sourceX:n,sourceY:r,targetX:o,targetY:i}),h=e.isInternal?void 0:t;return f.jsx(tl,{id:h,path:_,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 tE=Q0({isInternal:!1}),G0=Q0({isInternal:!0});tE.displayName="StraightEdge";G0.displayName="StraightEdgeInternal";function K0(e){return M.memo(({id:t,sourceX:n,sourceY:r,targetX:o,targetY:i,sourcePosition:s=Z.Bottom,targetPosition:l=Z.Top,label:a,labelStyle:u,labelShowBg:p,labelBgStyle:c,labelBgPadding:d,labelBgBorderRadius:x,style:y,markerEnd:w,markerStart:_,pathOptions:m,interactionWidth:g})=>{const[h,v,S]=i0({sourceX:n,sourceY:r,sourcePosition:s,targetX:o,targetY:i,targetPosition:l,curvature:m==null?void 0:m.curvature}),k=e.isInternal?void 0:t;return f.jsx(tl,{id:k,path:h,labelX:v,labelY:S,label:a,labelStyle:u,labelShowBg:p,labelBgStyle:c,labelBgPadding:d,labelBgBorderRadius:x,style:y,markerEnd:w,markerStart:_,interactionWidth:g})})}const nE=K0({isInternal:!1}),q0=K0({isInternal:!0});nE.displayName="BezierEdge";q0.displayName="BezierEdgeInternal";const Rf={default:q0,straight:G0,step:X0,smoothstep:U0,simplebezier:H0},Lf={sourceX:null,sourceY:null,targetX:null,targetY:null,sourcePosition:null,targetPosition:null},rE=(e,t,n)=>n===Z.Left?e-t:n===Z.Right?e+t:e,oE=(e,t,n)=>n===Z.Top?e-t:n===Z.Bottom?e+t:e,Af="react-flow__edgeupdater";function $f({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([Af,`${Af}-${l}`]),cx:rE(t,r,e),cy:oE(n,r,e),r,stroke:"transparent",fill:"transparent"})}function iE({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,S)=>{if(v.button!==0)return;const{autoPanOnConnect:k,domNode:C,connectionMode:j,connectionRadius:I,lib:A,onConnectStart:z,cancelConnection:D,nodeLookup:R,rfId:E,panBy:T,updateConnection:P}=y.getState(),L=S.type==="target",b=(O,B)=>{d(!1),c==null||c(O,n,S.type,B)},N=O=>u==null?void 0:u(n,O),$=(O,B)=>{d(!0),p==null||p(v,n,S.type),z==null||z(O,B)};tu.onPointerDown(v.nativeEvent,{autoPanOnConnect:k,connectionMode:j,connectionRadius:I,domNode:C,handleId:S.id,nodeId:S.nodeId,nodeLookup:R,isTarget:L,edgeUpdaterType:S.type,lib:A,flowId:E,cancelConnection:D,panBy:T,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:b,updateConnection:P,getTransform:()=>y.getState().transform,getFromHandle:()=>y.getState().connection.fromHandle,dragThreshold:y.getState().connectionDragThreshold,handleDomNode:v.currentTarget})},_=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($f,{position:l,centerX:r,centerY:o,radius:t,onMouseDown:_,onMouseEnter:g,onMouseOut:h,type:"source"}),(e===!0||e==="target")&&f.jsx($f,{position:a,centerX:i,centerY:s,radius:t,onMouseDown:m,onMouseEnter:g,onMouseOut:h,type:"target"})]})}function sE({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:_,onError:m,disableKeyboardA11y:g}){let h=ne(J=>J.edgeLookup.get(e));const v=ne(J=>J.defaultEdgeOptions);h=v?{...v,...h}:h;let S=h.type||"default",k=(w==null?void 0:w[S])||Rf[S];k===void 0&&(m==null||m("011",bt.error011(S)),S="default",k=(w==null?void 0:w.default)||Rf.default);const C=!!(h.focusable||t&&typeof h.focusable>"u"),j=typeof c<"u"&&(h.reconnectable||n&&typeof h.reconnectable>"u"),I=!!(h.selectable||r&&typeof h.selectable>"u"),A=M.useRef(null),[z,D]=M.useState(!1),[R,E]=M.useState(!1),T=pe(),{zIndex:P,sourceX:L,sourceY:b,targetX:N,targetY:$,sourcePosition:O,targetPosition:B}=ne(M.useCallback(J=>{const q=J.nodeLookup.get(h.source),re=J.nodeLookup.get(h.target);if(!q||!re)return{zIndex:h.zIndex,...Lf};const le=LS({id:e,sourceNode:q,targetNode:re,sourceHandle:h.sourceHandle||null,targetHandle:h.targetHandle||null,connectionMode:J.connectionMode,onError:m});return{zIndex:NS({selected:h.selected,zIndex:h.zIndex,sourceNode:q,targetNode:re,elevateOnSelect:J.elevateEdgesOnSelect,zIndexMode:J.zIndexMode}),...le||Lf}},[h.source,h.target,h.sourceHandle,h.targetHandle,h.selected,h.zIndex]),fe),W=M.useMemo(()=>h.markerStart?`url('#${Ja(h.markerStart,y)}')`:void 0,[h.markerStart,y]),V=M.useMemo(()=>h.markerEnd?`url('#${Ja(h.markerEnd,y)}')`:void 0,[h.markerEnd,y]);if(h.hidden||L===null||b===null||N===null||$===null)return null;const Y=J=>{var ie;const{addSelectedEdges:q,unselectNodesAndEdges:re,multiSelectionActive:le}=T.getState();I&&(T.setState({nodesSelectionActive:!1}),h.selected&&le?(re({nodes:[],edges:[h]}),(ie=A.current)==null||ie.blur()):q([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 q;if(!g&&Wg.includes(J.key)&&I){const{unselectNodesAndEdges:re,addSelectedEdges:le}=T.getState();J.key==="Escape"?((q=A.current)==null||q.blur(),re({edges:[h]})):le([e])}};return f.jsx("svg",{style:{zIndex:P},children:f.jsxs("g",{className:we(["react-flow__edge",`react-flow__edge-${S}`,h.className,_,{selected:h.selected,animated:h.animated,inactive:!I&&!o,updating:z,selectable:I}]),onClick:Y,onDoubleClick:X,onContextMenu:Q,onMouseEnter:H,onMouseMove:K,onMouseLeave:ee,onKeyDown:C?G:void 0,tabIndex:C?0:void 0,role:h.ariaRole??(C?"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":C?`${b0}-${y}`:void 0,ref:A,...h.domAttributes,children:[!R&&f.jsx(k,{id:e,source:h.source,target:h.target,type:h.type,selected:h.selected,animated:h.animated,selectable:I,deletable:h.deletable??!0,label:h.label,labelStyle:h.labelStyle,labelShowBg:h.labelShowBg,labelBgStyle:h.labelBgStyle,labelBgPadding:h.labelBgPadding,labelBgBorderRadius:h.labelBgBorderRadius,sourceX:L,sourceY:b,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}),j&&f.jsx(iE,{edge:h,isReconnectable:j,reconnectRadius:p,onReconnect:c,onReconnectStart:d,onReconnectEnd:x,sourceX:L,sourceY:b,targetX:N,targetY:$,sourcePosition:O,targetPosition:B,setUpdateHover:D,setReconnecting:E})]})})}var lE=M.memo(sE);const aE=e=>({edgesFocusable:e.edgesFocusable,edgesReconnectable:e.edgesReconnectable,elementsSelectable:e.elementsSelectable,connectionMode:e.connectionMode,onError:e.onError});function Z0({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:_,edgesReconnectable:m,elementsSelectable:g,onError:h}=ne(aE,fe),v=Y_(t);return f.jsxs("div",{className:"react-flow__edges",children:[f.jsx(q_,{defaultColor:e,rfId:n}),v.map(S=>f.jsx(lE,{id:S,edgesFocusable:_,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},S))]})}Z0.displayName="EdgeRenderer";const uE=M.memo(Z0),cE=e=>`translate(${e.transform[0]}px,${e.transform[1]}px) scale(${e.transform[2]})`;function dE({children:e}){const t=ne(cE);return f.jsx("div",{className:"react-flow__viewport xyflow__viewport react-flow__container",style:{transform:t},children:e})}function fE(e){const t=mc(),n=M.useRef(!1);M.useEffect(()=>{!n.current&&t.viewportInitialized&&e&&(setTimeout(()=>e(t),1),n.current=!0)},[e,t.viewportInitialized])}const pE=e=>{var t;return(t=e.panZoom)==null?void 0:t.syncViewport};function hE(e){const t=ne(pE),n=pe();return M.useEffect(()=>{e&&(t==null||t(e),n.setState({transform:[e.x,e.y,e.zoom]}))},[e,t]),null}function gE(e){return e.connection.inProgress?{...e.connection,to:Qo(e.connection.to,e.transform)}:{...e.connection}}function mE(e){return gE}function yE(e){const t=mE();return ne(t,fe)}const xE=e=>({nodesConnectable:e.nodesConnectable,isValid:e.connection.isValid,inProgress:e.connection.inProgress,width:e.width,height:e.height});function vE({containerStyle:e,style:t,type:n,component:r}){const{nodesConnectable:o,width:i,height:s,isValid:l,inProgress:a}=ne(xE,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",Xg(l)]),children:f.jsx(J0,{style:t,type:n,CustomComponent:r,isValid:l})})})}const J0=({style:e,type:t=qt.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}=yE();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:Xg(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 qt.Bezier:[y]=i0(w);break;case qt.SimpleBezier:[y]=B0(w);break;case qt.Step:[y]=Za({...w,borderRadius:0});break;case qt.SmoothStep:[y]=Za(w);break;default:[y]=l0(w)}return f.jsx("path",{d:y,fill:"none",className:"react-flow__connection-path",style:e})};J0.displayName="ConnectionLine";const wE={};function Df(e=wE){M.useRef(e),pe(),M.useEffect(()=>{},[e])}function SE(){pe(),M.useRef(!1),M.useEffect(()=>{},[])}function em({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:_,connectionLineContainerStyle:m,selectionKeyCode:g,selectionOnDrag:h,selectionMode:v,multiSelectionKeyCode:S,panActivationKeyCode:k,zoomActivationKeyCode:C,deleteKeyCode:j,onlyRenderVisibleElements:I,elementsSelectable:A,defaultViewport:z,translateExtent:D,minZoom:R,maxZoom:E,preventScrolling:T,defaultMarkerColor:P,zoomOnScroll:L,zoomOnPinch:b,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:q,onEdgeMouseMove:re,onEdgeMouseLeave:le,reconnectRadius:ie,onReconnect:je,onReconnectStart:Vt,onReconnectEnd:jt,noDragClassName:gn,noWheelClassName:Mr,noPanClassName:zr,disableKeyboardA11y:Pr,nodeExtent:nl,rfId:Go,viewport:On,onViewportChange:Tr}){return Df(e),Df(t),SE(),fE(n),hE(On),f.jsx(A_,{onPaneClick:V,onPaneMouseEnter:Y,onPaneMouseMove:X,onPaneMouseLeave:Q,onPaneContextMenu:K,onPaneScroll:H,paneClickDistance:ee,deleteKeyCode:j,selectionKeyCode:g,selectionOnDrag:h,selectionMode:v,onSelectionStart:d,onSelectionEnd:x,multiSelectionKeyCode:S,panActivationKeyCode:k,zoomActivationKeyCode:C,elementsSelectable:A,zoomOnScroll:L,zoomOnPinch:b,zoomOnDoubleClick:B,panOnScroll:N,panOnScrollSpeed:$,panOnScrollMode:O,panOnDrag:W,defaultViewport:z,translateExtent:D,minZoom:R,maxZoom:E,onSelectionContextMenu:c,preventScrolling:T,noDragClassName:gn,noWheelClassName:Mr,noPanClassName:zr,disableKeyboardA11y:Pr,onViewportChange:Tr,isControlledViewport:!!On,children:f.jsxs(dE,{children:[f.jsx(uE,{edgeTypes:t,onEdgeClick:o,onEdgeDoubleClick:s,onReconnect:je,onReconnectStart:Vt,onReconnectEnd:jt,onlyRenderVisibleElements:I,onEdgeContextMenu:J,onEdgeMouseEnter:q,onEdgeMouseMove:re,onEdgeMouseLeave:le,reconnectRadius:ie,defaultMarkerColor:P,noPanClassName:zr,disableKeyboardA11y:Pr,rfId:Go}),f.jsx(vE,{style:w,type:y,component:_,containerStyle:m}),f.jsx("div",{className:"react-flow__edgelabel-renderer"}),f.jsx(U_,{nodeTypes:e,onNodeClick:r,onNodeDoubleClick:i,onNodeMouseEnter:l,onNodeMouseMove:a,onNodeMouseLeave:u,onNodeContextMenu:p,nodeClickDistance:G,onlyRenderVisibleElements:I,noPanClassName:zr,noDragClassName:gn,disableKeyboardA11y:Pr,nodeExtent:nl,rfId:Go}),f.jsx("div",{className:"react-flow__viewport-portal"})]})})}em.displayName="GraphView";const kE=M.memo(em),Of=({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,_=new Map,m=r??t??[],g=n??e??[],h=p??[0,0],v=c??To;c0(w,_,m);const S=eu(g,x,y,{nodeOrigin:h,nodeExtent:v,zIndexMode:d});let k=[0,0,1];if(s&&o&&i){const C=Yo(x,{filter:z=>!!((z.width||z.initialWidth)&&(z.height||z.initialHeight))}),{x:j,y:I,zoom:A}=uc(C,o,i,a,u,(l==null?void 0:l.padding)??.1);k=[j,I,A]}return{rfId:"1",width:o??0,height:i??0,transform:k,nodes:g,nodesInitialized:S,nodeLookup:x,parentLookup:y,edges:m,edgeLookup:_,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:{...Yg},connectionClickStartHandle:null,connectOnClick:!0,ariaLiveMessage:"",autoPanOnConnect:!0,autoPanOnNodeDrag:!0,autoPanOnNodeFocus:!0,autoPanSpeed:15,connectionRadius:20,onError:SS,isValidConnection:void 0,onSelectionChangeHandlers:[],lib:"react",debug:!1,ariaLabelConfig:Ug,zIndexMode:d,onNodesChangeMiddlewareMap:new Map,onEdgesChangeMiddlewareMap:new Map}},_E=({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})=>Fk((x,y)=>{async function w(){const{nodeLookup:_,panZoom:m,fitViewOptions:g,fitViewResolver:h,width:v,height:S,minZoom:k,maxZoom:C}=y();m&&(await vS({nodes:_,width:v,height:S,panZoom:m,minZoom:k,maxZoom:C},g),h==null||h.resolve(!0),x({fitViewResolver:null}))}return{...Of({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:_=>{const{nodeLookup:m,parentLookup:g,nodeOrigin:h,elevateNodesOnSelect:v,fitViewQueued:S,zIndexMode:k}=y(),C=eu(_,m,g,{nodeOrigin:h,nodeExtent:c,elevateNodesOnSelect:v,checkEquality:!0,zIndexMode:k});S&&C?(w(),x({nodes:_,nodesInitialized:C,fitViewQueued:!1,fitViewOptions:void 0})):x({nodes:_,nodesInitialized:C})},setEdges:_=>{const{connectionLookup:m,edgeLookup:g}=y();c0(m,g,_),x({edges:_})},setDefaultNodesAndEdges:(_,m)=>{if(_){const{setNodes:g}=y();g(_),x({hasDefaultNodes:!0})}if(m){const{setEdges:g}=y();g(m),x({hasDefaultEdges:!0})}},updateNodeInternals:_=>{const{triggerNodeChanges:m,nodeLookup:g,parentLookup:h,domNode:v,nodeOrigin:S,nodeExtent:k,debug:C,fitViewQueued:j,zIndexMode:I}=y(),{changes:A,updatedInternals:z}=VS(_,g,h,v,S,k,I);z&&(OS(g,h,{nodeOrigin:S,nodeExtent:k,zIndexMode:I}),j?(w(),x({fitViewQueued:!1,fitViewOptions:void 0})):x({}),(A==null?void 0:A.length)>0&&(C&&console.log("React Flow: trigger node changes",A),m==null||m(A)))},updateNodePositions:(_,m=!1)=>{const g=[];let h=[];const{nodeLookup:v,triggerNodeChanges:S,connection:k,updateConnection:C,onNodesChangeMiddlewareMap:j}=y();for(const[I,A]of _){const z=v.get(I),D=!!(z!=null&&z.expandParent&&(z!=null&&z.parentId)&&(A!=null&&A.position)),R={id:I,type:"position",position:D?{x:Math.max(0,A.position.x),y:Math.max(0,A.position.y)}:A.position,dragging:m};if(z&&k.inProgress&&k.fromNode.id===z.id){const E=Ln(z,k.fromHandle,Z.Left,!0);C({...k,from:E})}D&&z.parentId&&g.push({id:I,parentId:z.parentId,rect:{...A.internals.positionAbsolute,width:A.measured.width??0,height:A.measured.height??0}}),h.push(R)}if(g.length>0){const{parentLookup:I,nodeOrigin:A}=y(),z=gc(g,v,I,A);h.push(...z)}for(const I of j.values())h=I(h);S(h)},triggerNodeChanges:_=>{const{onNodesChange:m,setNodes:g,nodes:h,hasDefaultNodes:v,debug:S}=y();if(_!=null&&_.length){if(v){const k=M0(_,h);g(k)}S&&console.log("React Flow: trigger node changes",_),m==null||m(_)}},triggerEdgeChanges:_=>{const{onEdgesChange:m,setEdges:g,edges:h,hasDefaultEdges:v,debug:S}=y();if(_!=null&&_.length){if(v){const k=z0(_,h);g(k)}S&&console.log("React Flow: trigger edge changes",_),m==null||m(_)}},addSelectedNodes:_=>{const{multiSelectionActive:m,edgeLookup:g,nodeLookup:h,triggerNodeChanges:v,triggerEdgeChanges:S}=y();if(m){const k=_.map(C=>xn(C,!0));v(k);return}v(nr(h,new Set([..._]),!0)),S(nr(g))},addSelectedEdges:_=>{const{multiSelectionActive:m,edgeLookup:g,nodeLookup:h,triggerNodeChanges:v,triggerEdgeChanges:S}=y();if(m){const k=_.map(C=>xn(C,!0));S(k);return}S(nr(g,new Set([..._]))),v(nr(h,new Set,!0))},unselectNodesAndEdges:({nodes:_,edges:m}={})=>{const{edges:g,nodes:h,nodeLookup:v,triggerNodeChanges:S,triggerEdgeChanges:k}=y(),C=_||h,j=m||g,I=[];for(const z of C){if(!z.selected)continue;const D=v.get(z.id);D&&(D.selected=!1),I.push(xn(z.id,!1))}const A=[];for(const z of j)z.selected&&A.push(xn(z.id,!1));S(I),k(A)},setMinZoom:_=>{const{panZoom:m,maxZoom:g}=y();m==null||m.setScaleExtent([_,g]),x({minZoom:_})},setMaxZoom:_=>{const{panZoom:m,minZoom:g}=y();m==null||m.setScaleExtent([g,_]),x({maxZoom:_})},setTranslateExtent:_=>{var m;(m=y().panZoom)==null||m.setTranslateExtent(_),x({translateExtent:_})},resetSelectedElements:()=>{const{edges:_,nodes:m,triggerNodeChanges:g,triggerEdgeChanges:h,elementsSelectable:v}=y();if(!v)return;const S=m.reduce((C,j)=>j.selected?[...C,xn(j.id,!1)]:C,[]),k=_.reduce((C,j)=>j.selected?[...C,xn(j.id,!1)]:C,[]);g(S),h(k)},setNodeExtent:_=>{const{nodes:m,nodeLookup:g,parentLookup:h,nodeOrigin:v,elevateNodesOnSelect:S,nodeExtent:k,zIndexMode:C}=y();_[0][0]===k[0][0]&&_[0][1]===k[0][1]&&_[1][0]===k[1][0]&&_[1][1]===k[1][1]||(eu(m,g,h,{nodeOrigin:v,nodeExtent:_,elevateNodesOnSelect:S,checkEquality:!1,zIndexMode:C}),x({nodeExtent:_}))},panBy:_=>{const{transform:m,width:g,height:h,panZoom:v,translateExtent:S}=y();return WS({delta:_,panZoom:v,transform:m,translateExtent:S,width:g,height:h})},setCenter:async(_,m,g)=>{const{width:h,height:v,maxZoom:S,panZoom:k}=y();if(!k)return Promise.resolve(!1);const C=typeof(g==null?void 0:g.zoom)<"u"?g.zoom:S;return await k.setViewport({x:h/2-_*C,y:v/2-m*C,zoom:C},{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:{...Yg}})},updateConnection:_=>{x({connection:_})},reset:()=>x({...Of()})}},Object.is);function EE({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]=M.useState(()=>_E({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(Hk,{value:y,children:f.jsx(d_,{children:x})})}function CE({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 M.useContext(Zs)?f.jsx(f.Fragment,{children:e}):f.jsx(EE,{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 bE={width:"100%",height:"100%",overflow:"hidden",position:"relative",zIndex:0};function NE({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:_,onClickConnectEnd:m,onNodeMouseEnter:g,onNodeMouseMove:h,onNodeMouseLeave:v,onNodeContextMenu:S,onNodeDoubleClick:k,onNodeDragStart:C,onNodeDrag:j,onNodeDragStop:I,onNodesDelete:A,onEdgesDelete:z,onDelete:D,onSelectionChange:R,onSelectionDragStart:E,onSelectionDrag:T,onSelectionDragStop:P,onSelectionContextMenu:L,onSelectionStart:b,onSelectionEnd:N,onBeforeDelete:$,connectionMode:O,connectionLineType:B=qt.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:q,snapGrid:re,onlyRenderVisibleElements:le=!1,selectNodesOnDrag:ie,nodesDraggable:je,autoPanOnNodeFocus:Vt,nodesConnectable:jt,nodesFocusable:gn,nodeOrigin:Mr=N0,edgesFocusable:zr,edgesReconnectable:Pr,elementsSelectable:nl=!0,defaultViewport:Go=t_,minZoom:On=.5,maxZoom:Tr=2,translateExtent:wc=To,preventScrolling:lm=!0,nodeExtent:rl,defaultMarkerColor:am="#b1b1b7",zoomOnScroll:um=!0,zoomOnPinch:cm=!0,panOnScroll:dm=!1,panOnScrollSpeed:fm=.5,panOnScrollMode:pm=bn.Free,zoomOnDoubleClick:hm=!0,panOnDrag:gm=!0,onPaneClick:mm,onPaneMouseEnter:ym,onPaneMouseMove:xm,onPaneMouseLeave:vm,onPaneScroll:wm,onPaneContextMenu:Sm,paneClickDistance:km=1,nodeClickDistance:_m=0,children:Em,onReconnect:Cm,onReconnectStart:bm,onReconnectEnd:Nm,onEdgeContextMenu:jm,onEdgeDoubleClick:Mm,onEdgeMouseEnter:zm,onEdgeMouseMove:Pm,onEdgeMouseLeave:Tm,reconnectRadius:Im=10,onNodesChange:Rm,onEdgesChange:Lm,noDragClassName:Am="nodrag",noWheelClassName:$m="nowheel",noPanClassName:Sc="nopan",fitView:kc,fitViewOptions:_c,connectOnClick:Dm,attributionPosition:Om,proOptions:Bm,defaultEdgeOptions:Fm,elevateNodesOnSelect:Hm=!0,elevateEdgesOnSelect:Vm=!1,disableKeyboardA11y:Ec=!1,autoPanOnConnect:Wm,autoPanOnNodeDrag:Um,autoPanSpeed:Ym,connectionRadius:Xm,isValidConnection:Qm,onError:Gm,style:Km,id:Cc,nodeDragThreshold:qm,connectionDragThreshold:Zm,viewport:Jm,onViewportChange:ey,width:ty,height:ny,colorMode:ry="light",debug:oy,onScroll:Ko,ariaLabelConfig:iy,zIndexMode:bc="basic",...sy},ly){const ol=Cc||"1",ay=i_(ry),uy=M.useCallback(Nc=>{Nc.currentTarget.scrollTo({top:0,left:0,behavior:"instant"}),Ko==null||Ko(Nc)},[Ko]);return f.jsx("div",{"data-testid":"rf__wrapper",...sy,onScroll:uy,style:{...Km,...bE},ref:ly,className:we(["react-flow",o,ay]),id:Cc,role:"application",children:f.jsxs(CE,{nodes:e,edges:t,width:ty,height:ny,fitView:kc,fitViewOptions:_c,minZoom:On,maxZoom:Tr,nodeOrigin:Mr,nodeExtent:rl,zIndexMode:bc,children:[f.jsx(kE,{onInit:u,onNodeClick:l,onEdgeClick:a,onNodeMouseEnter:g,onNodeMouseMove:h,onNodeMouseLeave:v,onNodeContextMenu:S,onNodeDoubleClick:k,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:Go,translateExtent:wc,minZoom:On,maxZoom:Tr,preventScrolling:lm,zoomOnScroll:um,zoomOnPinch:cm,zoomOnDoubleClick:hm,panOnScroll:dm,panOnScrollSpeed:fm,panOnScrollMode:pm,panOnDrag:gm,onPaneClick:mm,onPaneMouseEnter:ym,onPaneMouseMove:xm,onPaneMouseLeave:vm,onPaneScroll:wm,onPaneContextMenu:Sm,paneClickDistance:km,nodeClickDistance:_m,onSelectionContextMenu:L,onSelectionStart:b,onSelectionEnd:N,onReconnect:Cm,onReconnectStart:bm,onReconnectEnd:Nm,onEdgeContextMenu:jm,onEdgeDoubleClick:Mm,onEdgeMouseEnter:zm,onEdgeMouseMove:Pm,onEdgeMouseLeave:Tm,reconnectRadius:Im,defaultMarkerColor:am,noDragClassName:Am,noWheelClassName:$m,noPanClassName:Sc,rfId:ol,disableKeyboardA11y:Ec,nodeExtent:rl,viewport:Jm,onViewportChange:ey}),f.jsx(o_,{nodes:e,edges:t,defaultNodes:n,defaultEdges:r,onConnect:x,onConnectStart:y,onConnectEnd:w,onClickConnectStart:_,onClickConnectEnd:m,nodesDraggable:je,autoPanOnNodeFocus:Vt,nodesConnectable:jt,nodesFocusable:gn,edgesFocusable:zr,edgesReconnectable:Pr,elementsSelectable:nl,elevateNodesOnSelect:Hm,elevateEdgesOnSelect:Vm,minZoom:On,maxZoom:Tr,nodeExtent:rl,onNodesChange:Rm,onEdgesChange:Lm,snapToGrid:q,snapGrid:re,connectionMode:O,translateExtent:wc,connectOnClick:Dm,defaultEdgeOptions:Fm,fitView:kc,fitViewOptions:_c,onNodesDelete:A,onEdgesDelete:z,onDelete:D,onNodeDragStart:C,onNodeDrag:j,onNodeDragStop:I,onSelectionDrag:T,onSelectionDragStart:E,onSelectionDragStop:P,onMove:p,onMoveStart:c,onMoveEnd:d,noPanClassName:Sc,nodeOrigin:Mr,rfId:ol,autoPanOnConnect:Wm,autoPanOnNodeDrag:Um,autoPanSpeed:Ym,onError:Gm,connectionRadius:Xm,isValidConnection:Qm,selectNodesOnDrag:ie,nodeDragThreshold:qm,connectionDragThreshold:Zm,onBeforeDelete:$,debug:oy,ariaLabelConfig:iy,zIndexMode:bc}),f.jsx(e_,{onSelectionChange:R}),Em,f.jsx(Gk,{proOptions:Bm,position:Om}),f.jsx(Qk,{rfId:ol,disableKeyboardA11y:Ec})]})})}var jE=P0(NE);function ME(e){const[t,n]=M.useState(e),r=M.useCallback(o=>n(i=>M0(o,i)),[]);return[t,n,r]}function zE(e){const[t,n]=M.useState(e),r=M.useCallback(o=>n(i=>z0(o,i)),[]);return[t,n,r]}function PE({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 TE({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 IE={[un.Dots]:1,[un.Lines]:1,[un.Cross]:6},RE=e=>({transform:e.transform,patternId:`pattern-${e.rfId}`});function tm({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:d,patternId:x}=ne(RE,fe),y=r||IE[t],w=t===un.Dots,_=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],S=_?[h,h]:g,k=[v[0]*d[2]||1+S[0]/2,v[1]*d[2]||1+S[1]/2],C=`${x}${e||""}`;return f.jsxs("svg",{className:we(["react-flow__background",u]),style:{...a,...el,"--xy-background-color-props":l,"--xy-background-pattern-color-props":s},ref:c,"data-testid":"rf__background",children:[f.jsx("pattern",{id:C,x:d[0]%g[0],y:d[1]%g[1],width:g[0],height:g[1],patternUnits:"userSpaceOnUse",patternTransform:`translate(-${k[0]},-${k[1]})`,children:w?f.jsx(TE,{radius:h/2,className:p}):f.jsx(PE,{dimensions:S,lineWidth:o,variant:t,className:p})}),f.jsx("rect",{x:"0",y:"0",width:"100%",height:"100%",fill:`url(#${C})`})]})}tm.displayName="Background";const LE=M.memo(tm);function AE(){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 $E(){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 DE(){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 OE(){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 BE(){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 ki({children:e,className:t,...n}){return f.jsx("button",{type:"button",className:we(["react-flow__controls-button",t]),...n,children:e})}const FE=e=>({isInteractive:e.nodesDraggable||e.nodesConnectable||e.elementsSelectable,minZoomReached:e.transform[2]<=e.minZoom,maxZoomReached:e.transform[2]>=e.maxZoom,ariaLabelConfig:e.ariaLabelConfig});function nm({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:_,maxZoomReached:m,ariaLabelConfig:g}=ne(FE,fe),{zoomIn:h,zoomOut:v,fitView:S}=mc(),k=()=>{h(),i==null||i()},C=()=>{v(),s==null||s()},j=()=>{S(o),l==null||l()},I=()=>{y.setState({nodesDraggable:!w,nodesConnectable:!w,elementsSelectable:!w}),a==null||a(!w)},A=d==="horizontal"?"horizontal":"vertical";return f.jsxs(Js,{className:we(["react-flow__controls",A,u]),position:c,style:e,"data-testid":"rf__controls","aria-label":x??g["controls.ariaLabel"],children:[t&&f.jsxs(f.Fragment,{children:[f.jsx(ki,{onClick:k,className:"react-flow__controls-zoomin",title:g["controls.zoomIn.ariaLabel"],"aria-label":g["controls.zoomIn.ariaLabel"],disabled:m,children:f.jsx(AE,{})}),f.jsx(ki,{onClick:C,className:"react-flow__controls-zoomout",title:g["controls.zoomOut.ariaLabel"],"aria-label":g["controls.zoomOut.ariaLabel"],disabled:_,children:f.jsx($E,{})})]}),n&&f.jsx(ki,{className:"react-flow__controls-fitview",onClick:j,title:g["controls.fitView.ariaLabel"],"aria-label":g["controls.fitView.ariaLabel"],children:f.jsx(DE,{})}),r&&f.jsx(ki,{className:"react-flow__controls-interactive",onClick:I,title:g["controls.interactive.ariaLabel"],"aria-label":g["controls.interactive.ariaLabel"],children:w?f.jsx(BE,{}):f.jsx(OE,{})}),p]})}nm.displayName="Controls";const HE=M.memo(nm);function VE({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||{},_=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:_,stroke:l,strokeWidth:a},shapeRendering:c,onClick:x?m=>x(m,e):void 0})}const WE=M.memo(VE),UE=e=>e.nodes.map(t=>t.id),Bl=e=>e instanceof Function?e:()=>e;function YE({nodeStrokeColor:e,nodeColor:t,nodeClassName:n="",nodeBorderRadius:r=5,nodeStrokeWidth:o,nodeComponent:i=WE,onClick:s}){const l=ne(UE,fe),a=Bl(t),u=Bl(e),p=Bl(n),c=typeof window>"u"||window.chrome?"crispEdges":"geometricPrecision";return f.jsx(f.Fragment,{children:l.map(d=>f.jsx(QE,{id:d,nodeColorFunc:a,nodeStrokeColorFunc:u,nodeClassNameFunc:p,nodeBorderRadius:r,nodeStrokeWidth:o,NodeComponent:i,onClick:s,shapeRendering:c},d))})}function XE({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 _=w.internals.userNode,{x:m,y:g}=w.internals.positionAbsolute,{width:h,height:v}=Ht(_);return{node:_,x:m,y:g,width:h,height:v}},fe);return!u||u.hidden||!Jg(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 QE=M.memo(XE);var GE=M.memo(YE);const KE=200,qE=150,ZE=e=>!e.hidden,JE=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?Zg(Yo(e.nodeLookup,{filter:ZE}),t):t,rfId:e.rfId,panZoom:e.panZoom,translateExtent:e.translateExtent,flowWidth:e.width,flowHeight:e.height,ariaLabelConfig:e.ariaLabelConfig}},eC="react-flow__minimap-desc";function rm({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:_=!1,ariaLabel:m,inversePan:g,zoomStep:h=1,offsetScale:v=5}){const S=pe(),k=M.useRef(null),{boundingRect:C,viewBB:j,rfId:I,panZoom:A,translateExtent:z,flowWidth:D,flowHeight:R,ariaLabelConfig:E}=ne(JE,fe),T=(e==null?void 0:e.width)??KE,P=(e==null?void 0:e.height)??qE,L=C.width/T,b=C.height/P,N=Math.max(L,b),$=N*T,O=N*P,B=v*N,W=C.x-($-C.width)/2-B,V=C.y-(O-C.height)/2-B,Y=$+B*2,X=O+B*2,Q=`${eC}-${I}`,H=M.useRef(0),K=M.useRef();H.current=N,M.useEffect(()=>{if(k.current&&A)return K.current=JS({domNode:k.current,panZoom:A,getTransform:()=>S.getState().transform,getViewScale:()=>H.current}),()=>{var q;(q=K.current)==null||q.destroy()}},[A]),M.useEffect(()=>{var q;(q=K.current)==null||q.update({translateExtent:z,width:D,height:R,inversePan:g,pannable:w,zoomStep:h,zoomable:_})},[w,_,g,h,z,D,R]);const ee=x?q=>{var ie;const[re,le]=((ie=K.current)==null?void 0:ie.pointer(q))||[0,0];x(q,{x:re,y:le})}:void 0,G=y?M.useCallback((q,re)=>{const le=S.getState().nodeLookup.get(re).internals.userNode;y(q,le)},[]):void 0,J=m??E["minimap.ariaLabel"];return f.jsx(Js,{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*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:f.jsxs("svg",{width:T,height:P,viewBox:`${W} ${V} ${Y} ${X}`,className:"react-flow__minimap-svg",role:"img","aria-labelledby":Q,ref:k,onClick:ee,children:[J&&f.jsx("title",{id:Q,children:J}),f.jsx(GE,{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${j.x},${j.y}h${j.width}v${j.height}h${-j.width}z`,fillRule:"evenodd",pointerEvents:"none"})]})})}rm.displayName="MiniMap";M.memo(rm);const tC=e=>t=>e?`${Math.max(1/t.transform[2],1)}`:void 0,nC={[An.Line]:"right",[An.Handle]:"bottom-right"};function rC({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:_,onResizeEnd:m}){const g=L0(),h=typeof e=="string"?e:g,v=pe(),S=M.useRef(null),k=n===An.Handle,C=ne(M.useCallback(tC(k&&x),[k,x]),fe),j=M.useRef(null),I=t??nC[n];M.useEffect(()=>{if(!(!S.current||!h))return j.current||(j.current=gk({domNode:S.current,nodeId:h,getStoreItems:()=>{const{nodeLookup:z,transform:D,snapGrid:R,snapToGrid:E,nodeOrigin:T,domNode:P}=v.getState();return{nodeLookup:z,transform:D,snapGrid:R,snapToGrid:E,nodeOrigin:T,paneDomNode:P}},onChange:(z,D)=>{const{triggerNodeChanges:R,nodeLookup:E,parentLookup:T,nodeOrigin:P}=v.getState(),L=[],b={x:z.x,y:z.y},N=E.get(h);if(N&&N.expandParent&&N.parentId){const $=N.origin??P,O=z.width??N.measured.width??0,B=z.height??N.measured.height??0,W={id:N.id,parentId:N.parentId,rect:{width:O,height:B,...e0({x:z.x??N.position.x,y:z.y??N.position.y},{width:O,height:B},N.parentId,E,$)}},V=gc([W],E,T,P);L.push(...V),b.x=z.x?Math.max($[0]*O,z.x):void 0,b.y=z.y?Math.max($[1]*B,z.y):void 0}if(b.x!==void 0&&b.y!==void 0){const $={id:h,type:"position",position:{...b}};L.push($)}if(z.width!==void 0&&z.height!==void 0){const O={id:h,type:"dimensions",resizing:!0,setAttributes:d?d==="horizontal"?"width":"height":!0,dimensions:{width:z.width,height:z.height}};L.push(O)}for(const $ of D){const O={...$,type:"position"};L.push(O)}R(L)},onEnd:({width:z,height:D})=>{const R={id:h,type:"dimensions",resizing:!1,dimensions:{width:z,height:D}};v.getState().triggerNodeChanges([R])}})),j.current.update({controlPosition:I,boundaries:{minWidth:l,minHeight:a,maxWidth:u,maxHeight:p},keepAspectRatio:c,resizeDirection:d,onResizeStart:w,onResize:_,onResizeEnd:m,shouldResize:y}),()=>{var z;(z=j.current)==null||z.destroy()}},[I,l,a,u,p,c,w,_,m,y]);const A=I.split("-");return f.jsx("div",{className:we(["react-flow__resize-control","nodrag",...A,n,r]),ref:S,style:{...o,scale:C,...s&&{[k?"backgroundColor":"borderColor"]:s}},children:i})}const Bf=M.memo(rC);function oC({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:_}){return t?f.jsxs(f.Fragment,{children:[uk.map(m=>f.jsx(Bf,{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:_},m)),ak.map(m=>f.jsx(Bf,{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:_},m))]}):null}const ru={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"},iC={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"},Ff={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 xc(e){return iC[e]||"compute"}function om(e){return ru[e]||"#94a3b8"}function vc(e){return Ff[e]||Ff.compute}function sC({data:e}){const t=e,n=xc(t.service),r=om(n),o=vc(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:Z.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:Z.Bottom,style:{background:r}})]})}const lC=M.memo(sC);function aC({data:e,selected:t}){return f.jsxs(f.Fragment,{children:[f.jsx(oC,{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 uC({components:e}){const[t,n]=M.useState(!1),r=M.useMemo(()=>{if(!e||e.length===0)return Object.keys(ru).map(i=>({category:i,count:0}));const o={};for(const i of e){const s=xc(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=ru[o]||"#94a3b8",l=vc(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 cC({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 Hf={borderTop:"1px solid #e2e8f0",margin:"12px 0"},_i={fontSize:11,fontWeight:600,color:"#64748b",textTransform:"uppercase",letterSpacing:"0.05em",marginBottom:8},Fl={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"},Hl={display:"flex",justifyContent:"space-between",alignItems:"center",gap:10,color:"#475569",fontSize:13,marginBottom:7};function im(e){return typeof e=="boolean"?e?"true":"false":e==null?"":String(e)}function dC(e,t){return Object.entries(e??{}).filter(([n,r])=>r!=null&&n!=="tags").map(([n,r])=>`${n}=${im(r)}`).join(` -`)}function fC(e){const t=e==null?void 0:e.tags;return!t||typeof t!="object"||Array.isArray(t)?"":Object.entries(t).map(([n,r])=>`${n}=${im(r)}`).join(` -`)}function pC(e){const t=e.trim();return t==="true"?!0:t==="false"?!1:t!==""&&!Number.isNaN(Number(t))?Number(t):e}function Vf(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]=pC(r.slice(o+1)))}return t}function hC({component:e,cost:t,onClose:n,onApply:r,onDelete:o}){var k;const i=e!==null,[s,l]=M.useState(""),[a,u]=M.useState(""),[p,c]=M.useState("2"),[d,x]=M.useState(""),[y,w]=M.useState("");M.useEffect(()=>{e&&(l(e.label),u(e.description??""),c(String(e.tier??2)),x(dC(e.config)),w(fC(e.config)))},[e]);const _=e?xc(e.service):"compute",m=om(_),g=vc(_),h=(t==null?void 0:t.monthly)??null,v=M.useMemo(()=>{const C=Number(p);return Number.isFinite(C)?C:2},[p]),S=()=>{if(!e)return;const C=Vf(d),j=Vf(y);Object.keys(j).length>0&&(C.tags=j),r({...e,label:s.trim()||e.label,description:a,tier:v,config:C})};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:_i,children:"Overview"}),f.jsx("label",{style:Fl,htmlFor:"resource-label",children:"Label"}),f.jsx("input",{id:"resource-label","aria-label":"Label",value:s,onChange:C=>l(C.target.value),style:{...Vr,marginBottom:10}}),f.jsx("label",{style:Fl,htmlFor:"resource-description",children:"Description"}),f.jsx("textarea",{id:"resource-description","aria-label":"Description",value:a,onChange:C=>u(C.target.value),rows:3,style:{...Vr,marginBottom:10,resize:"vertical",minHeight:72}}),f.jsx("label",{style:Fl,htmlFor:"resource-tier",children:"Tier"}),f.jsx("input",{id:"resource-tier","aria-label":"Tier",type:"number",value:p,onChange:C=>c(C.target.value),style:{...Vr,marginBottom:10}}),f.jsxs("div",{style:Hl,children:[f.jsx("span",{children:"Service"}),f.jsx("strong",{style:{color:"#0f172a"},children:e==null?void 0:e.service})]}),f.jsxs("div",{style:Hl,children:[f.jsx("span",{children:"Provider"}),f.jsx("strong",{style:{color:"#0f172a"},children:(k=e==null?void 0:e.provider)==null?void 0:k.toUpperCase()})]}),f.jsx("div",{style:Hf}),f.jsx("div",{style:_i,children:"Cost"}),h!==null?f.jsxs("div",{style:Hl,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:Hf}),f.jsx("div",{style:_i,children:"Configuration"}),f.jsx("textarea",{"aria-label":"Configuration",value:d,onChange:C=>x(C.target.value),rows:7,style:{...Vr,resize:"vertical",minHeight:140,fontFamily:"ui-monospace, SFMono-Regular, Menlo, monospace"}}),f.jsx("div",{style:{..._i,marginTop:16},children:"Tags"}),f.jsx("textarea",{"aria-label":"Tags",value:y,onChange:C=>w(C.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:S,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 Wf="/api",Vl={border:"1px solid #cbd5e1",background:"#ffffff",color:"#0f172a",borderRadius:6,padding:"7px 10px",cursor:"pointer",fontSize:12,fontWeight:600};function gC({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(""),[d,x]=M.useState([]),[y,w]=M.useState([]);M.useEffect(()=>{fetch(`${Wf}/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(`${Wf}/modules`).then(g=>g.ok?g.json():null).then(g=>w((g==null?void 0:g.modules)??[])).catch(()=>w([]))},[]);const _=M.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=M.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(S=>S.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:{...Vl,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"&&_.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"&&_.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:{...Vl,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:{...Vl,position:"absolute",left:16,top:16,zIndex:15,boxShadow:"0 1px 4px rgba(0,0,0,0.08)"},children:"Add Resource"})}const Uf=200,Ei=90,Yf=300,mC=240,yt=32,yC=36,Wr=4,Wl="/api",xC={0:"Edge / CDN",1:"Network / Ingress",2:"Application",3:"Data Layer",4:"Platform Services",5:"Platform Services"},vC={0:"edge",1:"subnet",2:"subnet",3:"subnet"},Ul={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"},wC={cloudService:lC,boundaryGroup:aC};function ou(e){return JSON.parse(JSON.stringify(e))}function Ci(e){return ou(e??{})}function bi(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 Yl(e,t){let n=e,r=2;for(;t.has(n);)n=`${e}-${r}`,r+=1;return t.add(n),n}function SC(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 Xf(e){return{x:360+e%3*260,y:80+Math.floor(e/3)*150}}function kC(e,t){if(t==="vpc")return Hn;const n=e.match(/^tier-(\d+)$/);return n&&Ul[parseInt(n[1])]||Ul[2]}function _C(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:vC[i]||"subnet",label:xC[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 EC(e,t,n){var y,w,_,m;const r=[],o=e.boundaries||[],i=o.length>0?o:_C(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+=mC+(h-1)*(Ei+60)}for(const g of u){const h=a[g],v=d[g];for(let S=0;S0){const g=i.find(v=>v.kind==="vpc");let h;if(g&&g.component_ids.length>0){const v=g.component_ids.map(A=>{var z;return((z=p[A])==null?void 0:z.x)??0}),S=g.component_ids.map(A=>{var z;return((z=p[A])==null?void 0:z.y)??0}),k=Math.min(...v)-yt,C=Math.min(...S)-yt-24-yC,j=Math.max(...v)+Uf+yt,I=Math.max(...S)+Ei+yt;h=`boundary-${g.id}`,x[g.id]={x:k,y:C},r.push({id:h,type:"boundaryGroup",position:{x:k,y:C},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:j-k,height:I-C},zIndex:-2})}for(const v of i){if(v.kind==="vpc"||v.component_ids.length===0)continue;const S=v.component_ids.map(R=>{var E;return((E=p[R])==null?void 0:E.x)??0}),k=v.component_ids.map(R=>{var E;return((E=p[R])==null?void 0:E.y)??0}),C=Math.min(...S)-yt,j=Math.min(...k)-yt-24,I=Math.max(...S)+Uf+yt,A=Math.max(...k)+Ei+yt;x[v.id]={x:C,y:j};const z=kC(v.id,v.kind),D=!!(h&&g&&v.component_ids.some(R=>g.component_ids.includes(R)));r.push({id:`boundary-${v.id}`,type:"boundaryGroup",position:D?{x:C-x[g.id].x,y:j-x[g.id].y}:{x:C,y:j},data:{label:v.label||v.id,labelColor:z.labelColor,labelBg:z.labelBg,dotColor:z.dot},style:{background:z.bg,border:`1.5px solid ${z.border}`,borderRadius:10,padding:yt,width:I-C,height:A-j},zIndex:-1,parentId:D?h:void 0})}}for(const g of u){const h=a[g];for(const v of h){const S=l[v.id],k=t&&S&&x[S];let C=((_=p[v.id])==null?void 0:_.x)??0,j=((m=p[v.id])==null?void 0:m.y)??0;k&&(C-=x[S].x,j-=x[S].y),r.push({id:v.id,type:"cloudService",position:{x:C,y:j},data:{label:v.label,service:v.service,provider:v.provider,description:v.description,tier:v.tier,config:v.config||{},monthlyCost:n[v.id]},parentId:k?`boundary-${S}`:void 0,extent:k?"parent":void 0})}}return r}function sm(e,t){return`edge:${e.source}:${e.target}:${t}`}function Qf(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:sm(t,n),source:t.source,target:t.target,label:r,style:{stroke:"#94a3b8"},labelStyle:{fill:"#64748b",fontSize:11},animated:!0}})}function CC(e,t){return e&&e.map(n=>({...n,component_ids:n.component_ids.filter(r=>r!==t)}))}function bC({spec:e,onSpecChange:t}){const[n,r]=M.useState(!0),[o,i]=M.useState(null),[s,l]=M.useState(null),a=M.useCallback(R=>{l(null),t(R)},[t]),u=M.useCallback(async R=>{try{const E=await fetch(`${Wl}/export`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({spec:e,format:R})});if(!E.ok)return;const T=await E.blob(),P=URL.createObjectURL(T),L=document.createElement("a");L.href=P,L.download=`architecture.${R}`,L.click(),URL.revokeObjectURL(P)}catch{}},[e]),p=M.useMemo(()=>{var E;const R={};for(const T of((E=e.cost_estimate)==null?void 0:E.breakdown)??[])R[T.component_id]=T.monthly;return R},[e.cost_estimate]),c=M.useMemo(()=>o?e.components.find(R=>R.id===o)??null:null,[o,e.components]),d=M.useMemo(()=>{var R;return o?((R=e.cost_estimate)==null?void 0:R.breakdown.find(E=>E.component_id===o))??null:null},[o,e.cost_estimate]),[x,y,w]=ME([]),[_,m,g]=zE([]);M.useEffect(()=>{y(EC(e,n,p)),m(Qf(e))},[e,n,p,y,m]);const h=M.useCallback((R,E)=>{E.id.startsWith("boundary-")||i(E.id)},[]),v=M.useCallback(()=>{i(null)},[]),S=M.useCallback((R,E)=>{if(E.id.startsWith("boundary-"))return;const T=Ci(e.metadata),P=T.canvas??{},L={...P.nodes??{}},b=x.find($=>$.id===E.parentId),N=b?{x:b.position.x+E.position.x,y:b.position.y+E.position.y}:{x:E.position.x,y:E.position.y};L[E.id]=N,T.canvas={...P,nodes:L},a({...e,metadata:T})},[a,x,e]),k=M.useCallback(R=>{!R.source||!R.target||R.source===R.target||e.connections.some(T=>T.source===R.source&&T.target===R.target)||a({...e,connections:[...e.connections,{source:R.source,target:R.target,label:"HTTPS",protocol:"HTTPS",port:443}]})},[a,e]),C=M.useCallback(R=>{if(R.length===0)return;if(!window.confirm(`Delete ${R.length===1?"this connection":"these connections"}?`)){m(Qf(e));return}const E=new Set(R.map(T=>T.id));a({...e,connections:e.connections.filter((T,P)=>!E.has(sm(T,P)))})},[a,m,e]),j=M.useCallback(R=>{a({...e,components:e.components.map(E=>E.id===R.id?R:E)})},[a,e]),I=M.useCallback(R=>{var L,b;const E=e.components.find(N=>N.id===R);if(!E||!window.confirm(`Delete ${E.label||E.id} and its connections?`))return;const T=Ci(e.metadata);(L=T.canvas)!=null&&L.nodes&&delete T.canvas.nodes[R];const P=((b=T.modules)==null?void 0:b.instances)??{};for(const N of Object.values(P))N.component_ids.includes(R)&&(N.component_ids=N.component_ids.filter($=>$!==R),N.partial=!0,N.approved=!1,delete N.terraform);T.modules&&(T.modules.instances=P),a({...e,components:e.components.filter(N=>N.id!==R),connections:e.connections.filter(N=>N.source!==R&&N.target!==R),boundaries:CC(e.boundaries,R),metadata:T}),i(null)},[a,e]),A=M.useCallback(R=>{const E=new Set(e.components.map($=>$.id)),T=Yl(bi(R.service_key),E),P=Ci(e.metadata),L=P.canvas??{},b={...L.nodes??{}};b[T]=Xf(Object.keys(b).length+e.components.length),P.canvas={...L,nodes:b};const N={id:T,service:R.service_key,provider:R.provider.toLowerCase(),label:R.name,description:R.description??"",tier:SC(R.category),config:ou(R.default_config??{})};a({...e,components:[...e.components,N],metadata:P}),i(T)},[a,e]),z=M.useCallback(async R=>{var E;try{const T=await fetch(`${Wl}/modules/${encodeURIComponent(R)}`);if(!T.ok)return;const L=(await T.json()).module,b=new Set(e.components.map(G=>G.id)),N=Ci(e.metadata),$=N.modules??{},O={...$.instances??{}},B=new Set(Object.keys(O)),W=Yl(bi(L.id,"module"),B),V=bi(L.naming.component_id_prefix,W),Y={};for(const G of L.fragment.components)Y[G.id]=Yl(bi(`${V}_${G.id}`,V),b);const X=N.canvas??{},Q={...X.nodes??{}},H=Object.keys(Q).length+e.components.length,K=L.fragment.components.map((G,J)=>{const q=ou(G.config??{}),re={...L.default_tags??{},...typeof q.tags=="object"&&q.tags!==null?q.tags:{}};q.tags=re;const le=Y[G.id];return Q[le]=Xf(H+J),{...G,id:le,provider:G.provider.toLowerCase(),config:q}}),ee=L.fragment.connections.map(G=>({...G,source:Y[G.source],target:Y[G.target]}));O[W]={module_id:L.id,module_version:L.terraform.version,component_ids:K.map(G=>G.id),expected_component_count:K.length,required_tags:[...L.required_tags],naming_prefix:V,approved:L.approved,terraform:{...L.terraform}},N.canvas={...X,nodes:Q},N.modules={...$,instances:O},a({...e,components:[...e.components,...K],connections:[...e.connections,...ee],metadata:N}),i(((E=K[0])==null?void 0:E.id)??null)}catch{}},[a,e]),D=M.useCallback(async()=>{try{const R=await fetch(`${Wl}/canvas/validate`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({spec:e})});if(!R.ok)return;l(await R.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(gC,{provider:e.provider||"aws",standardsResult:s,onAddResource:A,onAddModule:z,onCheckStandards:D}),f.jsxs(jE,{nodes:x,edges:_,nodeTypes:wC,onNodesChange:w,onEdgesChange:g,onEdgesDelete:C,onConnect:k,onNodeDragStop:S,fitView:!0,proOptions:{hideAttribution:!0},style:{background:"#f8fafc"},onNodeClick:h,onPaneClick:v,children:[f.jsx(LE,{color:"#e2e8f0",gap:20}),f.jsx(HE,{style:{background:"#ffffff",border:"1px solid #e2e8f0",borderRadius:8}})]}),f.jsx(uC,{components:e.components}),f.jsx(cC,{showBoundaries:n,onToggleBoundaries:()=>r(R=>!R),onExportSvg:()=>u("svg"),onExportPng:()=>u("png")}),f.jsx(hC,{component:c??null,cost:d,onClose:()=>i(null),onApply:R=>j({...R,description:R.description??"",config:R.config??{}}),onDelete:I})]})}function NC({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 jC({spec:e,onDownloadTerraform:t,onDownloadYaml:n,validationSummary:r}){var o,i;return e?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:((o=e.components)==null?void 0:o.length)||0})]}),e.cost_estimate&&f.jsxs("span",{style:{color:"#64748b"},children:["Est. ",f.jsxs("strong",{style:{color:"#2563eb"},children:["$",(i=e.cost_estimate.monthly_total)==null?void 0:i.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]}),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"})]})]}):null}const MC=[{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},$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"}},zC={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 PC({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 TC({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 Gf({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(TC,{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 IC({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),[d,x]=M.useState(!1),y=M.useCallback(async S=>{i(S),l(!0),u(null),c(new Set),x(!1);try{const k=S==="well-architected",C=await fetch(`${t}/validate`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({spec:e,compliance:k?[]:[S],well_architected:k})}),j=await C.json();if(!C.ok)throw new Error(j.detail||"Validation failed");r(j.results)}catch(k){u(k instanceof Error?k.message:"Validation failed"),r(null)}finally{l(!1)}},[e,t]),w=M.useCallback(S=>{c(k=>{const C=new Set(k);return C.has(S)?C.delete(S):C.add(S),C})},[]),_=(n==null?void 0:n[0])??null,m=_?_.checks.filter(S=>!S.passed).sort((S,k)=>(Ni[S.severity]??9)-(Ni[k.severity]??9)):[],g=_?_.checks.filter(S=>S.passed).sort((S,k)=>(Ni[S.severity]??9)-(Ni[k.severity]??9)):[],h={};for(const S of m){const k=S.category;h[k]||(h[k]=[]),h[k].push(S)}const v=_?_.checks.reduce((S,k)=>(k.passed||(S[k.severity]=(S[k.severity]||0)+1),S),{}):{};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:MC.map(S=>{const k=o===S.key;return f.jsx("button",{onClick:()=>y(S.key),disabled:s,style:{padding:"8px 18px",borderRadius:6,border:k?"1.5px solid #2563eb":"1px solid #e2e8f0",background:k?"#eff6ff":"#ffffff",color:k?"#1d4ed8":"#475569",cursor:s?"wait":"pointer",fontSize:13,fontWeight:k?600:500,transition:"all 0.15s ease",opacity:s&&!k?.6:1},children:S.label},S.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}),_&&!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(PC,{score:_.score,passed:_.passed}),f.jsxs("div",{style:{flex:1},children:[f.jsx("div",{style:{fontSize:16,fontWeight:700,color:"#0f172a",marginBottom:4},children:_.framework}),f.jsxs("div",{style:{fontSize:13,color:"#64748b",marginBottom:14},children:[_.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(S=>{const k=v[S]||0,C=$o[S];return f.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,padding:"6px 12px",borderRadius:6,background:k>0?C.bg:"#f8fafc",border:`1px solid ${k>0?C.border:"#e2e8f0"}`,minWidth:100},children:[f.jsx("span",{style:{fontSize:18,fontWeight:700,color:k>0?C.text:"#cbd5e1",lineHeight:1},children:k}),f.jsx("span",{style:{fontSize:11,fontWeight:600,color:k>0?C.text:"#94a3b8",textTransform:"uppercase",letterSpacing:"0.03em"},children:S})]},S)})})]})]}),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,k])=>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:zC[S]||S.replace(/_/g," ")}),k.map(C=>{const j=`${S}-${C.name}`;return f.jsx(Gf,{check:C,expanded:p.has(j),onToggle:()=>w(j)},j)})]},S))]}),g.length>0&&f.jsxs("div",{children:[f.jsxs("button",{onClick:()=>x(S=>!S),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(S=>{const k=`passed-${S.category}-${S.name}`;return f.jsx(Gf,{check:S,expanded:p.has(k),onToggle:()=>w(k)},k)})})]}),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 ",_.framework," control requirements."]})]}),!_&&!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 RC=[{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"}],Kf={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 LC({spec:e,apiBase:t}){const[n,r]=M.useState(["hipaa","soc2","fedramp"]),[o,i]=M.useState(null),[s,l]=M.useState(!1),[a,u]=M.useState(null),p=d=>r(x=>x.includes(d)?x.filter(y=>y!==d):[...x,d]),c=M.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){const x=await d.json().catch(()=>({}));throw new Error(x.detail||`Request failed (${d.status})`)}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:RC.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=Kf[d.severity]||Kf.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,_)=>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]},_))}),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"},AC=[{key:"terraform",label:"Terraform"},{key:"pulumi-python",label:"Pulumi (Python)"},{key:"pulumi-ts",label:"Pulumi (TS)"}];function $C({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){const d=await c.json().catch(()=>({}));throw new Error(d.detail||`Request failed (${c.status})`)}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:AC.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 Xl=[{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 qf({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 DC({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),d=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})}),v=await h.json();if(!h.ok)throw new Error(v.detail||"Export failed");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=M.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 S=document.createRange();S.selectNodeContents(v),(g=window.getSelection())==null||g.removeAllRanges(),(h=window.getSelection())==null||h.addRange(S)}}},[o]),w=M.useCallback(()=>{if(!o||!n)return;const g=Xl.find(k=>k.key===n),h=new Blob([o],{type:"text/plain"}),v=URL.createObjectURL(h),S=document.createElement("a");S.href=v,S.download=`architecture.${(g==null?void 0:g.ext)||"txt"}`,S.click(),URL.revokeObjectURL(v)},[o,n]),_=o?o.split(` -`).length:0,m=Xl.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:Xl.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(qf,{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(qf,{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:[_," 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 OC={0:"Edge / CDN",1:"Load Balancing",2:"Compute",3:"Data",4:"Supporting"};function Ql(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 iu(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=iu(r,t+2);return`${n}- ${o.trimStart()}`}return`${n}- ${Ql(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=iu(i,t+2);return`${n}${o}: -${s}`}return`${n}${o}: ${Ql(i)}`}).join(` -`)}return Ql(e)}function ji({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 BC({spec:e,yaml:t}){var x;const[n,r]=M.useState("overview"),[o,i]=M.useState(!1),s=M.useRef(null),l=M.useMemo(()=>iu(e)||t||"",[e,t]),a=M.useMemo(()=>{const y=new Set(e.components.map(w=>w.provider));return Array.from(y)},[e.components]),u=M.useMemo(()=>{const y=new Set(e.components.map(w=>w.service));return Array.from(y)},[e.components]),p=M.useMemo(()=>{const y={};for(const w of e.components){const _=w.tier??2;y[_]||(y[_]=[]),y[_].push(w)}return y},[e.components]),c=M.useCallback(async()=>{var y,w;try{await navigator.clipboard.writeText(l),i(!0),setTimeout(()=>i(!1),2e3)}catch{const _=s.current;if(_){const m=document.createRange();m.selectNodeContents(_),(y=window.getSelection())==null||y.removeAllRanges(),(w=window.getSelection())==null||w.addRange(m)}}},[l]),d=M.useCallback(()=>{var m;const y=new Blob([l],{type:"text/yaml"}),w=URL.createObjectURL(y),_=document.createElement("a");_.href=w,_.download=`${((m=e.name)==null?void 0:m.replace(/\s+/g,"-").toLowerCase())||"architecture"}.yaml`,_.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(ji,{label:"Components",value:e.components.length}),f.jsx(ji,{label:"Connections",value:e.connections.length}),f.jsx(ji,{label:"Services",value:u.length,sub:a.join(", ")}),e.cost_estimate&&f.jsx(ji,{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:OC[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 _=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:(_==null?void 0:_.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"},qe="/api",FC=["Add caching layer","Reduce cost","Increase redundancy","Add monitoring","Add security"];function Zf(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 FC.filter(l=>!(l==="Add caching layer"&&r||l==="Add monitoring"&&o||l==="Add security"&&i)).slice(0,3)}function HC(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 Gl(e,t){var i;let n=e;const[r,o]=await Promise.all([fetch(`${qe}/cost`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({spec:n})}).then(s=>s.ok?s.json():null).catch(()=>null),fetch(`${qe}/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 Jf(e,t,n){var a;const r=e?`${qe}/modify/stream`:`${qe}/design/stream`,o=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)});if(!o.ok){const u=await o.json();n.onError(u.detail||"Request failed");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);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);break;case"error":n.onError(x.message);break}}catch{}}}function VC(){var h;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(""),[d,x]=M.useState(null),y=M.useRef(null),w=M.useRef(null);M.useEffect(()=>{var v;(v=w.current)==null||v.scrollIntoView({behavior:"smooth"})},[e]);const _=async()=>{var I;if(!n.trim()||o!=="idle")return;const v={role:"user",content:n};t(A=>[...A,v]),r("");const S=s!==null;i(S?"modifying":"generating");let k=null,C="",j=!1;try{const A=S?{spec:s,instruction:n}:{description:n};try{await Jf(S,A,{onStage:E=>{E==="generating"?i("generating"):(E==="costing"||E==="validating")&&i("costing")},onSpec:E=>{l(E),k=E,i("costing")},onCost:E=>{E&&k&&(k={...k,cost_estimate:E},l(k))},onValidation:(E,T)=>{E!==null&&x({passed:E,total:T})},onDone:(E,T)=>{k=E,C=T,l(E),i("done")},onError:E=>{throw new Error(E)}}),j=k!==null}catch{i(S?"modifying":"generating")}if(!j){const E=S?await fetch(`${qe}/modify`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({spec:s,instruction:n})}):await fetch(`${qe}/design`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({description:n})}),T=await E.json();if(!E.ok)throw new Error(T.detail||"Request failed");k=T.spec,C=T.yaml,i("costing"),k=await Gl(k,x),l(k),i("done")}const z=k,R={role:"assistant",content:`${S?"Modified":"Designed"} **${z.name}** with ${z.components.length} components on ${z.provider.toUpperCase()}.${z.cost_estimate?` Estimated cost: $${z.cost_estimate.monthly_total.toFixed(2)}/mo.`:""}`,spec:z,yaml:C,suggestions:Zf(z)};t(E=>[...E,R]),u("diagram")}catch(A){const z=A instanceof Error?A.message:"Unknown error";t(D=>[...D,{role:"assistant",content:`Error: ${z}`}])}finally{i("idle"),(I=y.current)==null||I.focus()}},m=async v=>{if(s)try{const S=await fetch(`${qe}/download`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({spec:s,format:v})});if(!S.ok)return;const k=await S.blob(),j=(S.headers.get("Content-Disposition")||"").match(/filename=([^\s;]+)/),I=j?j[1]:`architecture.${v==="terraform"?"tf":"yaml"}`,A=URL.createObjectURL(k),z=document.createElement("a");z.href=A,z.download=I,z.click(),URL.revokeObjectURL(A)}catch{}},g=async v=>{l(v),x(null);try{const S=await Gl(v,x);l(S)}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((v,S)=>f.jsxs("div",{style:{marginBottom:12},children:[f.jsx("div",{style:{padding:"10px 14px",borderRadius:8,background:v.role==="user"?"#2563eb":"#f1f5f9",color:v.role==="user"?"#ffffff":"#1e293b",fontSize:14,lineHeight:1.5},children:HC(v.content)}),v.role==="assistant"&&v.spec&&v.suggestions&&v.suggestions.length>0&&f.jsx("div",{style:{display:"flex",gap:6,marginTop:6,flexWrap:"wrap"},children:v.suggestions.map(k=>f.jsx("button",{onClick:()=>{var C;r(k),(C=y.current)==null||C.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:k},k))})]},S)),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:w})]}),f.jsx("div",{style:{padding:16,borderTop:"1px solid #e2e8f0"},children:f.jsxs("div",{style:{display:"flex",gap:8},children:[f.jsx("input",{ref:y,value:n,onChange:v=>r(v.target.value),onKeyDown:v=>v.key==="Enter"&&_(),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:_,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(v=>f.jsx("button",{onClick:()=>u(v),style:{padding:"12px 24px",border:"none",borderBottom:a===v?"2px solid #2563eb":"2px solid transparent",background:"transparent",color:a===v?"#2563eb":"#64748b",cursor:"pointer",fontSize:14,fontWeight:500,textTransform:"capitalize"},children:v},v))}),f.jsxs("div",{style:{flex:1,overflow:"auto",display:"flex",flexDirection:"column"},children:[f.jsx("div",{style:{padding:"0.5rem 1rem"},children:f.jsx(jC,{spec:s,onDownloadTerraform:s?()=>m("terraform"):void 0,onDownloadYaml:s?()=>m("yaml"):void 0,validationSummary:d})}),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(bC,{spec:s,onSpecChange:g}),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(NC,{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(BC,{spec:s,yaml:((h=e.findLast(v=>v.yaml))==null?void 0:h.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(IC,{spec:s,apiBase:qe}),a==="validate"&&!s&&f.jsx("div",{style:{padding:32,color:"#64748b"},children:"Design an architecture first."}),a==="compliance"&&s&&f.jsx(LC,{spec:s,apiBase:qe}),a==="compliance"&&!s&&f.jsx("div",{style:{padding:32,color:"#64748b"},children:"Design an architecture first."}),a==="plan"&&s&&f.jsx($C,{spec:s,apiBase:qe}),a==="plan"&&!s&&f.jsx("div",{style:{padding:32,color:"#64748b"},children:"Design an architecture first."}),a==="export"&&s&&f.jsx(DC,{spec:s,apiBase:qe}),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:v=>c(v.target.value),onKeyDown:async v=>{if(v.key==="Enter"&&p.trim()&&o==="idle"){const S=p;c(""),i("modifying");let k=null,C="",j=!1;try{try{await Jf(!0,{spec:s,instruction:S},{onStage:A=>{A==="generating"?i("modifying"):(A==="costing"||A==="validating")&&i("costing")},onSpec:A=>{l(A),k=A,i("costing")},onCost:A=>{A&&k&&(k={...k,cost_estimate:A},l(k))},onValidation:(A,z)=>{A!==null&&x({passed:A,total:z})},onDone:(A,z)=>{k=A,C=z,l(A),i("done")},onError:A=>{throw new Error(A)}}),j=k!==null}catch{i("modifying")}if(!j){const A=await fetch(`${qe}/modify`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({spec:s,instruction:S})}),z=await A.json();if(!A.ok)throw new Error(z.detail||"Modification failed");const D=z.spec;C=z.yaml,i("costing"),k=await Gl(D,x),l(k),i("done")}const I=k;t(A=>[...A,{role:"user",content:S},{role:"assistant",content:`Modified **${I.name}** with ${I.components.length} components on ${I.provider.toUpperCase()}.${I.cost_estimate?` Estimated cost: $${I.cost_estimate.monthly_total.toFixed(2)}/mo.`:""}`,spec:I,yaml:C,suggestions:Zf(I)}])}catch(I){t(A=>[...A,{role:"user",content:S},{role:"assistant",content:`Error: ${I instanceof Error?I.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."})]})]})]})]})}Kl.createRoot(document.getElementById("root")).render(f.jsx(dp.StrictMode,{children:f.jsx(VC,{})})); diff --git a/packages/web/cloudwright_web/static/assets/index-DU-cIjQd.js b/packages/web/cloudwright_web/static/assets/index-DU-cIjQd.js new file mode 100644 index 0000000..f3fab83 --- /dev/null +++ b/packages/web/cloudwright_web/static/assets/index-DU-cIjQd.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 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 fe8dac6..ac78efa 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 ffbe563..b760fa1 100644 --- a/packages/web/frontend/src/App.tsx +++ b/packages/web/frontend/src/App.tsx @@ -7,6 +7,7 @@ import CompliancePanel from "./components/CompliancePanel"; import PlanPanel from "./components/PlanPanel"; import ExportPanel from "./components/ExportPanel"; import SpecPanel from "./components/SpecPanel"; +import { parseApiError, formatApiError } from "./lib/apiError"; interface ArchSpec { name: string; @@ -55,6 +56,14 @@ interface CostEstimate { currency: string; } +interface UsageInfo { + model?: string; + input_tokens?: number; + output_tokens?: number; + cost_usd?: number; + latency_ms?: number; +} + interface Message { role: "user" | "assistant"; content: string; @@ -146,6 +155,7 @@ async function streamDesignOrModify( onCost: (estimate: CostEstimate | null) => void; onValidation: (passed: number | null, total: number | null) => void; onDone: (spec: ArchSpec, yaml: string) => void; + onUsage?: (usage: UsageInfo) => void; onError: (message: string) => void; } ) { @@ -157,8 +167,7 @@ async function streamDesignOrModify( }); if (!response.ok) { - const data = await response.json(); - callbacks.onError(data.detail || "Request failed"); + callbacks.onError(await parseApiError(response)); return; } @@ -188,6 +197,7 @@ async function streamDesignOrModify( break; case "generated": callbacks.onSpec(event.spec, event.yaml); + if (event.usage && callbacks.onUsage) callbacks.onUsage(event.usage); break; case "costed": callbacks.onCost(event.cost_estimate); @@ -197,6 +207,7 @@ async function streamDesignOrModify( break; case "done": callbacks.onDone(event.spec, event.yaml); + if (event.usage && callbacks.onUsage) callbacks.onUsage(event.usage); break; case "error": callbacks.onError(event.message); @@ -218,6 +229,7 @@ function App() { const [modifyInput, setModifyInput] = useState(""); const [validationSummary, setValidationSummary] = useState<{ passed: number; total: number } | null>(null); + const [lastUsage, setLastUsage] = useState(null); const inputRef = useRef(null); const chatEndRef = useRef(null); @@ -272,6 +284,7 @@ function App() { setCurrentSpec(spec); setLoadingStage("done"); }, + onUsage: (usage) => setLastUsage(usage), onError: (msg) => { throw new Error(msg); }, }); streamSucceeded = finalSpec !== null; @@ -294,9 +307,10 @@ function App() { body: JSON.stringify({ description: input }), }); const data = await res.json(); - if (!res.ok) throw new Error(data.detail || "Request failed"); + if (!res.ok) throw new Error(formatApiError(data)); finalSpec = data.spec as ArchSpec; finalYaml = data.yaml; + if (data.usage) setLastUsage(data.usage as UsageInfo); setLoadingStage("costing"); finalSpec = await enrichSpec(finalSpec, setValidationSummary); @@ -529,6 +543,7 @@ function App() { onDownloadTerraform={currentSpec ? () => handleDownload("terraform") : undefined} onDownloadYaml={currentSpec ? () => handleDownload("yaml") : undefined} validationSummary={validationSummary} + usage={lastUsage} />
@@ -654,6 +669,7 @@ function App() { setCurrentSpec(spec); setLoadingStage("done"); }, + onUsage: (usage) => setLastUsage(usage), onError: (msg) => { throw new Error(msg); }, }); streamSucceeded = finalSpec !== null; @@ -668,7 +684,8 @@ function App() { body: JSON.stringify({ spec: currentSpec, instruction }), }); const data = await res.json(); - if (!res.ok) throw new Error(data.detail || "Modification failed"); + if (!res.ok) throw new Error(formatApiError(data, "Modification failed")); + if (data.usage) setLastUsage(data.usage as UsageInfo); const rawSpec = data.spec as ArchSpec; finalYaml = data.yaml; setLoadingStage("costing"); diff --git a/packages/web/frontend/src/components/CompliancePanel.tsx b/packages/web/frontend/src/components/CompliancePanel.tsx index 2e34b1a..b0134f0 100644 --- a/packages/web/frontend/src/components/CompliancePanel.tsx +++ b/packages/web/frontend/src/components/CompliancePanel.tsx @@ -1,4 +1,5 @@ import React, { useState, useCallback } from "react"; +import { parseApiError } from "../lib/apiError"; interface ControlRef { framework: string; @@ -74,10 +75,7 @@ export default function CompliancePanel({ spec, apiBase }: CompliancePanelProps) headers: { "Content-Type": "application/json" }, body: JSON.stringify({ spec, frameworks: selected }), }); - if (!res.ok) { - const j = await res.json().catch(() => ({})); - throw new Error(j.detail || `Request failed (${res.status})`); - } + if (!res.ok) throw new Error(await parseApiError(res)); setReport((await res.json()) as ComplianceReport); } catch (e) { setError(e instanceof Error ? e.message : "Compliance scan failed"); diff --git a/packages/web/frontend/src/components/ExportPanel.tsx b/packages/web/frontend/src/components/ExportPanel.tsx index 9194f36..a4b68b0 100644 --- a/packages/web/frontend/src/components/ExportPanel.tsx +++ b/packages/web/frontend/src/components/ExportPanel.tsx @@ -1,4 +1,5 @@ import React, { useState, useCallback, useRef } from "react"; +import { parseApiError } from "../lib/apiError"; interface ExportPanelProps { spec: Record; @@ -74,8 +75,8 @@ export default function ExportPanel({ spec, apiBase }: ExportPanelProps) { headers: { "Content-Type": "application/json" }, body: JSON.stringify({ spec, format: fmt }), }); + if (!res.ok) throw new Error(await parseApiError(res)); const data = await res.json(); - if (!res.ok) throw new Error(data.detail || "Export failed"); setContent(data.content || JSON.stringify(data, null, 2)); } catch (err) { setError(err instanceof Error ? err.message : "Export failed"); diff --git a/packages/web/frontend/src/components/PlanPanel.tsx b/packages/web/frontend/src/components/PlanPanel.tsx index a42f3cc..b1c53e6 100644 --- a/packages/web/frontend/src/components/PlanPanel.tsx +++ b/packages/web/frontend/src/components/PlanPanel.tsx @@ -1,4 +1,5 @@ import React, { useState, useCallback } from "react"; +import { parseApiError } from "../lib/apiError"; interface PlanResult { tool: string; @@ -38,10 +39,7 @@ export default function PlanPanel({ spec, apiBase }: PlanPanelProps) { headers: { "Content-Type": "application/json" }, body: JSON.stringify({ spec, target, run_plan: true }), }); - if (!res.ok) { - const j = await res.json().catch(() => ({})); - throw new Error(j.detail || `Request failed (${res.status})`); - } + if (!res.ok) throw new Error(await parseApiError(res)); setResult((await res.json()) as PlanResult); } catch (e) { setError(e instanceof Error ? e.message : "Plan failed"); diff --git a/packages/web/frontend/src/components/SummaryBar.tsx b/packages/web/frontend/src/components/SummaryBar.tsx index e53e1a1..c1c3e17 100644 --- a/packages/web/frontend/src/components/SummaryBar.tsx +++ b/packages/web/frontend/src/components/SummaryBar.tsx @@ -1,15 +1,31 @@ import React from 'react'; +interface UsageInfo { + model?: string; + input_tokens?: number; + output_tokens?: number; + cost_usd?: number; + latency_ms?: number; +} + interface SummaryBarProps { spec: any | null; onDownloadTerraform?: () => void; onDownloadYaml?: () => void; validationSummary?: { passed: number; total: number } | null; + usage?: UsageInfo | null; } -export default function SummaryBar({ spec, onDownloadTerraform, onDownloadYaml, validationSummary }: SummaryBarProps) { +export default function SummaryBar({ spec, onDownloadTerraform, onDownloadYaml, validationSummary, usage }: SummaryBarProps) { if (!spec) return null; + const usageParts: string[] = []; + if (usage?.model) usageParts.push(usage.model.replace("claude-", "").replace("anthropic.", "")); + if (usage?.input_tokens != null && usage?.output_tokens != null) + usageParts.push(`${((usage.input_tokens + usage.output_tokens) / 1000).toFixed(1)}k tokens`); + if (usage?.cost_usd != null) usageParts.push(`$${usage.cost_usd.toFixed(4)}`); + if (usage?.latency_ms != null) usageParts.push(`${(usage.latency_ms / 1000).toFixed(1)}s`); + return (
)} + {usageParts.length > 0 && ( + {usageParts.join(' · ')} + )}
{onDownloadTerraform && (