From 8656e78dbbde4de8334c9a4e6538cdd987aa63f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Han?= Date: Tue, 2 Jun 2026 15:59:24 +0200 Subject: [PATCH 001/646] fix(ci): fix bash syntax error and regex bug in conventions workflow (#456) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sébastien Han --- .github/workflows/conventions.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/conventions.yaml b/.github/workflows/conventions.yaml index 70f39bcb75..30102b8be4 100644 --- a/.github/workflows/conventions.yaml +++ b/.github/workflows/conventions.yaml @@ -219,7 +219,7 @@ jobs: missing=$(gh api \ "repos/${{ github.repository }}/pulls/${PR_NUMBER}/commits" \ --paginate \ - --jq '[.[] | select(.commit.message | test("^Signed-off-by: "; "m") | not) | .sha[:7]] | join(", ")') + --jq '[.[] | select(.commit.message | test("(?m)^Signed-off-by: ") | not) | .sha[:7]] | join(", ")') if [ -n "$missing" ]; then marker="" @@ -316,7 +316,7 @@ jobs: ${violations} Sorry, this project does not accept commits authored by tools as valid. - Commits need to be authored by and signed-off by the human(s) responsible for the PR, with their name and contact. + Commits need to be authored by and signed-off by the human(s) responsible for the PR, with their name and contact." fi echo "::error::AI tool authorship found in PR commits" exit 1 From 689ce1c879c18a598a06c823d1bb299ff84d8b6e Mon Sep 17 00:00:00 2001 From: Shane Utt Date: Mon, 1 Jun 2026 20:12:07 -0400 Subject: [PATCH 002/646] fix(ci): dedup and exit 1 instead of pr close for conventions Signed-off-by: Shane Utt --- .github/workflows/conventions.yaml | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/.github/workflows/conventions.yaml b/.github/workflows/conventions.yaml index 30102b8be4..045479119c 100644 --- a/.github/workflows/conventions.yaml +++ b/.github/workflows/conventions.yaml @@ -57,7 +57,8 @@ jobs: --body "${marker} **PR too large**: ${added} lines added (limit: ${MAX_ADDITIONS}). Please split into smaller PRs. Add \`skip/pr-hygiene\` label to override." fi - gh pr close "$PR_NUMBER" --repo "${{ github.repository }}" + echo "::error::PR has ${added} lines added (limit: ${MAX_ADDITIONS})" + exit 1 fi # ---------------------------------------------------------------------------- @@ -81,9 +82,15 @@ jobs: fi word_count=$(echo "$PR_BODY" | wc -w) - if [ "$word_count" -lt 2 ]; then # minimum "fixes " - gh pr comment "$PR_NUMBER" --repo "${{ github.repository }}" \ - --body "Please add a description to this PR explaining what it does and why. See our [coding conventions](docs/developing/conventions.md)." + if [ "$word_count" -lt 2 ]; then + marker="" + already=$(gh api "repos/${{ github.repository }}/issues/${PR_NUMBER}/comments" \ + --jq "[.[] | select(.body | contains(\"${marker}\"))] | length") + if [ "$already" -eq 0 ]; then + gh pr comment "$PR_NUMBER" --repo "${{ github.repository }}" \ + --body "${marker} + Please add a description to this PR explaining what it does and why. See our [coding conventions](docs/developing/conventions.md)." + fi fi # ---------------------------------------------------------------------------- @@ -392,7 +399,8 @@ jobs: --body "${marker} **Proposal validation failed**: $(echo -e "$errors") - See [proposal process](docs/proposals.md) for requirements. Fix and re-open." + See [proposal process](docs/proposals.md) for requirements." fi - gh pr close "$PR_NUMBER" --repo "${{ github.repository }}" + echo "::error::Proposal validation failed" + exit 1 fi From 9b4578b7919d6a6431afb33284084714b37c6b3b Mon Sep 17 00:00:00 2001 From: Shane Utt Date: Mon, 1 Jun 2026 20:13:21 -0400 Subject: [PATCH 003/646] style: reorder struct fields Reorder fields in 18 structs to follow convention: `name` first (if present), then remaining fields alphabetically. Update all construction sites to match. Signed-off-by: Shane Utt --- filter/ext-proc/src/lib.rs | 88 +++++++++---------- .../builtins/http/ai/agentic/a2a/config.rs | 32 +++---- .../builtins/http/ai/agentic/a2a/envelope.rs | 6 +- .../src/builtins/http/ai/agentic/a2a/mod.rs | 11 +-- .../http/ai/agentic/json_rpc/config.rs | 22 ++--- .../http/ai/agentic/json_rpc/envelope.rs | 24 ++--- .../builtins/http/ai/agentic/json_rpc/mod.rs | 6 +- .../http/ai/agentic/mcp/broker/config.rs | 42 ++++----- .../http/ai/agentic/mcp/broker/mod.rs | 12 +-- .../builtins/http/ai/agentic/mcp/config.rs | 24 ++--- .../builtins/http/ai/agentic/mcp/envelope.rs | 6 +- .../src/builtins/http/ai/agentic/mcp/mod.rs | 11 +-- .../ai/openai/responses/classifier/mod.rs | 32 +++---- protocol/src/http/pingora/metrics.rs | 8 +- server/src/dump.rs | 20 ++--- tests/utils/src/agentic/mcp.rs | 8 +- 16 files changed, 177 insertions(+), 175 deletions(-) diff --git a/filter/ext-proc/src/lib.rs b/filter/ext-proc/src/lib.rs index 2ffd802b7d..3b7aba898b 100644 --- a/filter/ext-proc/src/lib.rs +++ b/filter/ext-proc/src/lib.rs @@ -103,80 +103,80 @@ const DEFAULT_DEFERRED_CLOSE_TIMEOUT_MS: u64 = 5000; reason = "mirrors Envoy ExternalProcessor proto fields" )] struct ExtProcConfig { - /// gRPC endpoint URI of the external processing server. - target: String, - - /// Per-message timeout in milliseconds. - /// Maps to Envoy's `message_timeout`. - #[serde(default = "default_message_timeout_ms")] - message_timeout_ms: u64, - - /// Controls which parts of the request/response are sent to the - /// external processor. Maps to Envoy's `processing_mode`. + /// When `true`, the content-length header is preserved after + /// external processing body mutation. Only relevant for body + /// send modes that enable mutation. #[serde(default)] - processing_mode: ProcessingModeConfig, + allow_content_length_header: bool, /// Whether the external processor may override the processing /// mode via `mode_override` in its responses. #[serde(default)] allow_mode_override: bool, - /// Upper bound in milliseconds for `override_message_timeout` - /// values sent by the external processor. When set, the server - /// may extend the per-message timeout up to this limit. + /// Allowlist of processing modes the processor may override to. + /// Only evaluated when `allow_mode_override` is `true`. #[allow(dead_code, reason = "parsed for config compatibility; used in subsequent PRs")] - max_message_timeout_ms: Option, - - /// Observation-only mode. When enabled, request/response data is - /// sent to the processor but the pipeline does not wait for a - /// response before continuing. #[serde(default)] - observability_mode: bool, + allowed_override_modes: Vec, + + /// Timeout in milliseconds for deferred gRPC stream closure in + /// observability mode. Default: 5000. + #[allow(dead_code, reason = "parsed for config compatibility; used in subsequent PRs")] + #[serde(default = "default_deferred_close_timeout_ms")] + deferred_close_timeout_ms: u64, /// When `true`, `ImmediateResponse` messages from the processor /// are ignored. #[serde(default)] disable_immediate_response: bool, + /// Controls which request/response headers are forwarded to the + /// external processor. When unset, all headers are forwarded. + #[allow(dead_code, reason = "parsed for config compatibility; used in subsequent PRs")] + forward_rules: Option, + + /// Upper bound in milliseconds for `override_message_timeout` + /// values sent by the external processor. When set, the server + /// may extend the per-message timeout up to this limit. + #[allow(dead_code, reason = "parsed for config compatibility; used in subsequent PRs")] + max_message_timeout_ms: Option, + + /// Per-message timeout in milliseconds. + /// Maps to Envoy's `message_timeout`. + #[serde(default = "default_message_timeout_ms")] + message_timeout_ms: u64, + /// Restricts which headers the external processor is allowed to /// mutate. When unset, all headers may be modified except /// pseudo-headers and `host`. #[allow(dead_code, reason = "parsed for config compatibility; used in subsequent PRs")] mutation_rules: Option, - /// Controls which request/response headers are forwarded to the - /// external processor. When unset, all headers are forwarded. - #[allow(dead_code, reason = "parsed for config compatibility; used in subsequent PRs")] - forward_rules: Option, - - /// HTTP status code returned to the downstream client when the - /// external processor returns an error, fails to respond, or - /// cannot be reached. Default: 500. - #[serde(default = "default_status_on_error")] - status_on_error: u16, + /// Observation-only mode. When enabled, request/response data is + /// sent to the processor but the pipeline does not wait for a + /// response before continuing. + #[serde(default)] + observability_mode: bool, - /// When `true`, the content-length header is preserved after - /// external processing body mutation. Only relevant for body - /// send modes that enable mutation. + /// Controls which parts of the request/response are sent to the + /// external processor. Maps to Envoy's `processing_mode`. #[serde(default)] - allow_content_length_header: bool, + processing_mode: ProcessingModeConfig, /// Send body to the processor as it arrives without waiting for /// the header response. Only applies to `streamed` body mode. #[serde(default)] send_body_without_waiting_for_header_response: bool, - /// Allowlist of processing modes the processor may override to. - /// Only evaluated when `allow_mode_override` is `true`. - #[allow(dead_code, reason = "parsed for config compatibility; used in subsequent PRs")] - #[serde(default)] - allowed_override_modes: Vec, + /// HTTP status code returned to the downstream client when the + /// external processor returns an error, fails to respond, or + /// cannot be reached. Default: 500. + #[serde(default = "default_status_on_error")] + status_on_error: u16, - /// Timeout in milliseconds for deferred gRPC stream closure in - /// observability mode. Default: 5000. - #[allow(dead_code, reason = "parsed for config compatibility; used in subsequent PRs")] - #[serde(default = "default_deferred_close_timeout_ms")] - deferred_close_timeout_ms: u64, + /// gRPC endpoint URI of the external processing server. + target: String, } /// Returns the default message timeout in milliseconds. diff --git a/filter/src/builtins/http/ai/agentic/a2a/config.rs b/filter/src/builtins/http/ai/agentic/a2a/config.rs index b1c9212437..27ad9511ad 100644 --- a/filter/src/builtins/http/ai/agentic/a2a/config.rs +++ b/filter/src/builtins/http/ai/agentic/a2a/config.rs @@ -40,26 +40,26 @@ pub(crate) enum InvalidA2aBehavior { #[derive(Debug, Clone, Deserialize)] #[serde(deny_unknown_fields)] pub(crate) struct A2aHeaders { - /// Header name for the canonical A2A method (e.g. `x-praxis-a2a-method`). - #[serde(default = "default_method_header")] - pub method: Option, - /// Header name for the A2A family (e.g. `x-praxis-a2a-family`). #[serde(default = "default_family_header")] pub family: Option, - /// Header name for the extracted task ID (e.g. `x-praxis-a2a-task-id`). - #[serde(default = "default_task_id_header")] - pub task_id: Option, - /// Header name for the JSON-RPC kind (e.g. `x-praxis-a2a-kind`). #[serde(default = "default_kind_header")] pub kind: Option, + /// Header name for the canonical A2A method (e.g. `x-praxis-a2a-method`). + #[serde(default = "default_method_header")] + pub method: Option, + /// Header name for streaming detection (e.g. `x-praxis-a2a-streaming`). #[serde(default = "default_streaming_header")] pub streaming: Option, + /// Header name for the extracted task ID (e.g. `x-praxis-a2a-task-id`). + #[serde(default = "default_task_id_header")] + pub task_id: Option, + /// Header name for A2A version (e.g. `x-praxis-a2a-version`). #[serde(default = "default_version_header")] pub version: Option, @@ -68,11 +68,11 @@ pub(crate) struct A2aHeaders { impl Default for A2aHeaders { fn default() -> Self { Self { - method: default_method_header(), family: default_family_header(), - task_id: default_task_id_header(), kind: default_kind_header(), + method: default_method_header(), streaming: default_streaming_header(), + task_id: default_task_id_header(), version: default_version_header(), } } @@ -140,21 +140,21 @@ fn default_version_header() -> Option { #[derive(Debug, Deserialize)] #[serde(deny_unknown_fields)] pub(crate) struct A2aConfig { + /// Header names for A2A metadata promotion. + #[serde(default)] + pub headers: A2aHeaders, + /// Maximum body size in bytes for `StreamBuffer`. #[serde(default = "default_max_body_bytes")] pub max_body_bytes: usize, - /// Invalid input handling behavior. - #[serde(default)] - pub on_invalid: InvalidA2aBehavior, - /// Method aliases for compatibility (slash-delimited → `PascalCase`). #[serde(default)] pub method_aliases: BTreeMap, - /// Header names for A2A metadata promotion. + /// Invalid input handling behavior. #[serde(default)] - pub headers: A2aHeaders, + pub on_invalid: InvalidA2aBehavior, } /// Default max body bytes. diff --git a/filter/src/builtins/http/ai/agentic/a2a/envelope.rs b/filter/src/builtins/http/ai/agentic/a2a/envelope.rs index 853a8797df..5063219aad 100644 --- a/filter/src/builtins/http/ai/agentic/a2a/envelope.rs +++ b/filter/src/builtins/http/ai/agentic/a2a/envelope.rs @@ -170,12 +170,12 @@ impl A2aFamily { /// Extracted A2A envelope metadata. #[derive(Debug, Clone)] pub(crate) struct A2aEnvelope { + /// Method family classification. + pub family: A2aFamily, /// Classified A2A method (canonical after alias resolution). pub method: A2aMethod, /// Original method string before alias resolution (if different). pub original_method: Option, - /// Method family classification. - pub family: A2aFamily, /// Whether the method supports streaming. pub streaming: bool, /// Task ID extracted from params, when present. @@ -206,9 +206,9 @@ pub(crate) fn extract_a2a_envelope( let version = extract_version(request_headers); A2aEnvelope { + family, method, original_method, - family, streaming, task_id, version, diff --git a/filter/src/builtins/http/ai/agentic/a2a/mod.rs b/filter/src/builtins/http/ai/agentic/a2a/mod.rs index 64452f7f5f..77e216de13 100644 --- a/filter/src/builtins/http/ai/agentic/a2a/mod.rs +++ b/filter/src/builtins/http/ai/agentic/a2a/mod.rs @@ -102,12 +102,13 @@ impl A2aFilter { pub fn from_config(config: &serde_yaml::Value) -> Result, FilterError> { let cfg: A2aConfig = parse_filter_config("a2a", config)?; let validated_config = build_config(cfg)?; - let json_rpc_config = build_json_rpc_config(validated_config.max_body_bytes); + let max_body_bytes = validated_config.max_body_bytes; + let json_rpc_config = build_json_rpc_config(max_body_bytes); Ok(Box::new(Self { - max_body_bytes: validated_config.max_body_bytes, config: validated_config, json_rpc_config, + max_body_bytes, })) } } @@ -193,17 +194,17 @@ fn build_json_rpc_config(max_body_bytes: usize) -> JsonRpcConfig { use crate::builtins::http::ai::agentic::json_rpc::config::{BatchPolicy, InvalidJsonRpcBehavior, JsonRpcHeaders}; JsonRpcConfig { - max_body_bytes, // A2A classification produces one static routing decision per request. // JSON-RPC batches can mix methods, task IDs, and streaming semantics, // so reject them instead of routing by an arbitrary batch element. batch_policy: BatchPolicy::Reject, - on_invalid: InvalidJsonRpcBehavior::Continue, headers: JsonRpcHeaders { - method: None, id: None, kind: None, + method: None, }, + max_body_bytes, + on_invalid: InvalidJsonRpcBehavior::Continue, } } diff --git a/filter/src/builtins/http/ai/agentic/json_rpc/config.rs b/filter/src/builtins/http/ai/agentic/json_rpc/config.rs index 7bf8340a7d..c9f30d37f2 100644 --- a/filter/src/builtins/http/ai/agentic/json_rpc/config.rs +++ b/filter/src/builtins/http/ai/agentic/json_rpc/config.rs @@ -54,20 +54,20 @@ pub(crate) enum InvalidJsonRpcBehavior { #[derive(Debug, Clone, Deserialize)] #[serde(deny_unknown_fields)] pub(crate) struct JsonRpcHeaders { - /// Header name for JSON-RPC method (e.g., `X-Json-Rpc-Method`). - pub method: Option, /// Header name for JSON-RPC id (e.g., `X-Json-Rpc-Id`). pub id: Option, /// Header name for JSON-RPC kind (e.g., `X-Json-Rpc-Kind`). pub kind: Option, + /// Header name for JSON-RPC method (e.g., `X-Json-Rpc-Method`). + pub method: Option, } impl Default for JsonRpcHeaders { fn default() -> Self { Self { - method: Some("X-Json-Rpc-Method".to_owned()), id: Some("X-Json-Rpc-Id".to_owned()), kind: Some("X-Json-Rpc-Kind".to_owned()), + method: Some("X-Json-Rpc-Method".to_owned()), } } } @@ -82,21 +82,21 @@ impl Default for JsonRpcHeaders { #[derive(Debug, Deserialize)] #[serde(deny_unknown_fields)] pub(crate) struct JsonRpcConfig { - /// Maximum body size in bytes for `StreamBuffer`. - #[serde(default = "default_max_body_bytes")] - pub max_body_bytes: usize, - /// Batch handling policy. #[serde(default)] pub batch_policy: BatchPolicy, - /// Invalid input handling behavior. - #[serde(default)] - pub on_invalid: InvalidJsonRpcBehavior, - /// Header names for metadata promotion. #[serde(default)] pub headers: JsonRpcHeaders, + + /// Maximum body size in bytes for `StreamBuffer`. + #[serde(default = "default_max_body_bytes")] + pub max_body_bytes: usize, + + /// Invalid input handling behavior. + #[serde(default)] + pub on_invalid: InvalidJsonRpcBehavior, } /// Default max body bytes. diff --git a/filter/src/builtins/http/ai/agentic/json_rpc/envelope.rs b/filter/src/builtins/http/ai/agentic/json_rpc/envelope.rs index 4a49ddb640..449956d0f0 100644 --- a/filter/src/builtins/http/ai/agentic/json_rpc/envelope.rs +++ b/filter/src/builtins/http/ai/agentic/json_rpc/envelope.rs @@ -74,16 +74,16 @@ impl JsonRpcIdKind { /// Parsed JSON-RPC envelope metadata. #[derive(Debug, Clone, PartialEq, Eq)] pub(crate) struct JsonRpcEnvelope { - /// Message kind (request/notification/response/batch). - pub kind: JsonRpcKind, - /// Method name (for requests and notifications). - pub method: Option, + /// Batch length (for batches only). + pub batch_len: Option, /// ID as string (for requests and responses). pub id: Option, /// ID type classification. pub id_kind: JsonRpcIdKind, - /// Batch length (for batches only). - pub batch_len: Option, + /// Message kind (request/notification/response/batch). + pub kind: JsonRpcKind, + /// Method name (for requests and notifications). + pub method: Option, } // ----------------------------------------------------------------------------- @@ -204,11 +204,11 @@ fn parse_single_message(value: &Value) -> Result, @@ -101,22 +101,22 @@ pub(super) struct McpBrokerConfig { #[derive(Debug, Clone)] #[allow(dead_code, reason = "fields used by follow-up tools/call routing")] pub(super) struct CatalogTool { - /// Exposed (prefixed) tool name visible to clients. - pub exposed_name: String, - /// Original tool name on the backend. - pub original_name: String, - /// Backend server name from config. - pub server_name: String, - /// Backend cluster name. - pub cluster: String, + /// Optional tool annotations. + pub annotations: Option, /// Backend MCP endpoint path. pub backend_path: String, + /// Backend cluster name. + pub cluster: String, /// Optional description. pub description: Option, + /// Exposed (prefixed) tool name visible to clients. + pub exposed_name: String, /// MCP input schema. pub input_schema: serde_json::Value, - /// Optional tool annotations. - pub annotations: Option, + /// Original tool name on the backend. + pub original_name: String, + /// Backend server name from config. + pub server_name: String, } // ----------------------------------------------------------------------------- @@ -317,13 +317,13 @@ fn build_catalog_entry(server: &McpServerConfig, tool: &ToolConfig) -> CatalogTo }; CatalogTool { - exposed_name, - original_name: tool.name.clone(), - server_name: server.name.clone(), - cluster: server.cluster.clone(), + annotations: tool.annotations.clone(), backend_path: server.path.clone(), + cluster: server.cluster.clone(), description: tool.description.clone(), + exposed_name, input_schema: tool.input_schema.clone().unwrap_or_else(default_input_schema), - annotations: tool.annotations.clone(), + original_name: tool.name.clone(), + server_name: server.name.clone(), } } diff --git a/filter/src/builtins/http/ai/agentic/mcp/broker/mod.rs b/filter/src/builtins/http/ai/agentic/mcp/broker/mod.rs index bb49eed806..396a4c9c6f 100644 --- a/filter/src/builtins/http/ai/agentic/mcp/broker/mod.rs +++ b/filter/src/builtins/http/ai/agentic/mcp/broker/mod.rs @@ -84,14 +84,14 @@ const SERVER_NAME: &str = "praxis"; /// description: Create a calendar event /// ``` pub(crate) struct McpBrokerFilter { + /// Static tool catalog built from config. + catalog: Vec, /// Shared JSON-RPC parser configuration. json_rpc_config: JsonRpcConfig, /// Maximum body bytes for `StreamBuffer`. max_body_bytes: usize, /// Public path this MCP broker handles (e.g. `/mcp`). public_path: String, - /// Static tool catalog built from config. - catalog: Vec, } impl McpBrokerFilter { @@ -113,10 +113,10 @@ impl McpBrokerFilter { let json_rpc_config = build_json_rpc_config(validated.max_body_bytes); Ok(Box::new(Self { + catalog, json_rpc_config, max_body_bytes: validated.max_body_bytes, public_path: validated.path.clone(), - catalog, })) } } @@ -461,13 +461,13 @@ fn build_json_rpc_config(max_body_bytes: usize) -> JsonRpcConfig { use crate::builtins::http::ai::agentic::json_rpc::config::{BatchPolicy, InvalidJsonRpcBehavior, JsonRpcHeaders}; JsonRpcConfig { - max_body_bytes, batch_policy: BatchPolicy::Reject, - on_invalid: InvalidJsonRpcBehavior::Continue, headers: JsonRpcHeaders { - method: None, id: None, kind: None, + method: None, }, + max_body_bytes, + on_invalid: InvalidJsonRpcBehavior::Continue, } } diff --git a/filter/src/builtins/http/ai/agentic/mcp/config.rs b/filter/src/builtins/http/ai/agentic/mcp/config.rs index c074369763..b735ba8f11 100644 --- a/filter/src/builtins/http/ai/agentic/mcp/config.rs +++ b/filter/src/builtins/http/ai/agentic/mcp/config.rs @@ -77,15 +77,15 @@ pub(crate) struct HeaderValidation { #[derive(Debug, Clone, Deserialize)] #[serde(deny_unknown_fields)] pub(crate) struct McpHeaders { + /// Header name for the JSON-RPC kind (e.g. `x-praxis-mcp-kind`). + #[serde(default = "default_kind_header")] + pub kind: Option, /// Header name for the MCP method (e.g. `x-praxis-mcp-method`). #[serde(default = "default_method_header")] pub method: Option, /// Header name for the tool/resource/prompt name (e.g. `x-praxis-mcp-name`). #[serde(default = "default_name_header")] pub name: Option, - /// Header name for the JSON-RPC kind (e.g. `x-praxis-mcp-kind`). - #[serde(default = "default_kind_header")] - pub kind: Option, /// Header name for MCP session presence (e.g. `x-praxis-mcp-session-present`). #[serde(default = "default_session_present_header")] pub session_present: Option, @@ -94,9 +94,9 @@ pub(crate) struct McpHeaders { impl Default for McpHeaders { fn default() -> Self { Self { + kind: default_kind_header(), method: default_method_header(), name: default_name_header(), - kind: default_kind_header(), session_present: default_session_present_header(), } } @@ -146,14 +146,6 @@ fn default_session_present_header() -> Option { #[derive(Debug, Deserialize)] #[serde(deny_unknown_fields)] pub(crate) struct McpConfig { - /// Maximum body size in bytes for `StreamBuffer`. - #[serde(default = "default_max_body_bytes")] - pub max_body_bytes: usize, - - /// Invalid input handling behavior. - #[serde(default)] - pub on_invalid: InvalidMcpBehavior, - /// Header validation settings. #[serde(default)] pub header_validation: HeaderValidation, @@ -161,6 +153,14 @@ pub(crate) struct McpConfig { /// Header names for MCP metadata promotion. #[serde(default)] pub headers: McpHeaders, + + /// Maximum body size in bytes for `StreamBuffer`. + #[serde(default = "default_max_body_bytes")] + pub max_body_bytes: usize, + + /// Invalid input handling behavior. + #[serde(default)] + pub on_invalid: InvalidMcpBehavior, } /// Default max body bytes. diff --git a/filter/src/builtins/http/ai/agentic/mcp/envelope.rs b/filter/src/builtins/http/ai/agentic/mcp/envelope.rs index f4d960a654..9e4fd8d061 100644 --- a/filter/src/builtins/http/ai/agentic/mcp/envelope.rs +++ b/filter/src/builtins/http/ai/agentic/mcp/envelope.rs @@ -109,10 +109,10 @@ pub(crate) struct McpEnvelope { pub method: McpMethod, /// Tool/resource/prompt name extracted from params. pub name: Option, - /// `Mcp-Session-Id` value from the request header. - pub session_id: Option, /// Protocol version from initialize params or `Mcp-Protocol-Version` header. pub protocol_version: Option, + /// `Mcp-Session-Id` value from the request header. + pub session_id: Option, } // ----------------------------------------------------------------------------- @@ -132,8 +132,8 @@ pub(crate) fn extract_mcp_envelope(value: &Value, method_str: &str, request_head McpEnvelope { method, name, - session_id, protocol_version, + session_id, } } diff --git a/filter/src/builtins/http/ai/agentic/mcp/mod.rs b/filter/src/builtins/http/ai/agentic/mcp/mod.rs index 4d3347bd53..2f1d9e1ff2 100644 --- a/filter/src/builtins/http/ai/agentic/mcp/mod.rs +++ b/filter/src/builtins/http/ai/agentic/mcp/mod.rs @@ -92,12 +92,13 @@ impl McpFilter { let cfg: McpConfig = parse_filter_config("mcp", config)?; let validated_config = build_config(cfg)?; - let json_rpc_config = build_json_rpc_config(validated_config.max_body_bytes); + let max_body_bytes = validated_config.max_body_bytes; + let json_rpc_config = build_json_rpc_config(max_body_bytes); Ok(Box::new(Self { - max_body_bytes: validated_config.max_body_bytes, config: validated_config, json_rpc_config, + max_body_bytes, })) } } @@ -189,14 +190,14 @@ fn build_json_rpc_config(max_body_bytes: usize) -> JsonRpcConfig { use super::json_rpc::config::{BatchPolicy, InvalidJsonRpcBehavior, JsonRpcHeaders}; JsonRpcConfig { - max_body_bytes, batch_policy: BatchPolicy::Reject, - on_invalid: InvalidJsonRpcBehavior::Continue, headers: JsonRpcHeaders { - method: None, id: None, kind: None, + method: None, }, + max_body_bytes, + on_invalid: InvalidJsonRpcBehavior::Continue, } } diff --git a/filter/src/builtins/http/ai/openai/responses/classifier/mod.rs b/filter/src/builtins/http/ai/openai/responses/classifier/mod.rs index 3f50063d26..7b61ea7394 100644 --- a/filter/src/builtins/http/ai/openai/responses/classifier/mod.rs +++ b/filter/src/builtins/http/ai/openai/responses/classifier/mod.rs @@ -42,20 +42,20 @@ impl AiRequestFormat { /// Extracted facts from a classified request body. #[derive(Debug)] pub(crate) struct ClassifiedRequest { + /// Extracted `background` field value, if present. + pub background: Option, /// Detected body format. pub format: AiRequestFormat, + /// Whether `conversation` is present and non-null. + pub has_conversation: bool, + /// Whether `previous_response_id` is present and non-null. + pub has_previous_response_id: bool, /// Extracted `model` field value, if present. pub model: Option, - /// Extracted `stream` field value, if present. - pub stream: Option, /// Extracted `store` field value, if present. pub store: Option, - /// Extracted `background` field value, if present. - pub background: Option, - /// Whether `previous_response_id` is present and non-null. - pub has_previous_response_id: bool, - /// Whether `conversation` is present and non-null. - pub has_conversation: bool, + /// Extracted `stream` field value, if present. + pub stream: Option, } // ----------------------------------------------------------------------------- @@ -82,13 +82,13 @@ pub(crate) fn classify_request_body(body: &[u8]) -> ClassifiedRequest { let format = classify_format(obj); ClassifiedRequest { + background: obj.get("background").and_then(serde_json::Value::as_bool), format, + has_conversation: obj.get("conversation").is_some_and(|v| !v.is_null()), + has_previous_response_id: obj.get("previous_response_id").is_some_and(|v| !v.is_null()), model: extract_string(obj, "model"), - stream: obj.get("stream").and_then(serde_json::Value::as_bool), store: obj.get("store").and_then(serde_json::Value::as_bool), - background: obj.get("background").and_then(serde_json::Value::as_bool), - has_previous_response_id: obj.get("previous_response_id").is_some_and(|v| !v.is_null()), - has_conversation: obj.get("conversation").is_some_and(|v| !v.is_null()), + stream: obj.get("stream").and_then(serde_json::Value::as_bool), } } @@ -111,13 +111,13 @@ fn classify_format(obj: &serde_json::Map) -> AiReques /// Build a result with no extracted facts. fn empty_result(format: AiRequestFormat) -> ClassifiedRequest { ClassifiedRequest { + background: None, format, + has_conversation: false, + has_previous_response_id: false, model: None, - stream: None, store: None, - background: None, - has_previous_response_id: false, - has_conversation: false, + stream: None, } } diff --git a/protocol/src/http/pingora/metrics.rs b/protocol/src/http/pingora/metrics.rs index 539ad490d8..0e9ba2e477 100644 --- a/protocol/src/http/pingora/metrics.rs +++ b/protocol/src/http/pingora/metrics.rs @@ -124,14 +124,14 @@ pub fn method_label(method: &str) -> &'static str { /// so the metrics facade can intern them without per-request allocation. /// Only `cluster` is dynamic. pub(crate) struct RequestMetricLabels { + /// Cluster name or `"none"`. + pub cluster: ::metrics::SharedString, /// HTTP method (e.g. `"GET"`). pub method: &'static str, - /// Status class (e.g. `"2xx"`). - pub status_class: &'static str, /// Route name or `"unknown"`. pub route: &'static str, - /// Cluster name or `"none"`. - pub cluster: ::metrics::SharedString, + /// Status class (e.g. `"2xx"`). + pub status_class: &'static str, } /// Record HTTP request metrics for a completed request. diff --git a/server/src/dump.rs b/server/src/dump.rs index c950fd2686..ba8b1fe086 100644 --- a/server/src/dump.rs +++ b/server/src/dump.rs @@ -42,23 +42,23 @@ pub(crate) struct ResolvedListenerDump { /// A single resolved filter entry with its position metadata. #[derive(Serialize)] pub(crate) struct ResolvedFilterDump { + /// Optional user-assigned name for this filter entry. + pub name: Option, + /// Name of the chain this filter belongs to. pub chain: String, /// Zero-based index of this filter within its chain. pub chain_index: usize, - /// Zero-based index of this filter in the overall pipeline. - pub pipeline_index: usize, + /// Per-filter failure behaviour. + pub failure_mode: FailureMode, /// Filter type name (e.g. `"router"`, `"load_balancer"`). pub filter: String, - /// Optional user-assigned name for this filter entry. - pub name: Option, - - /// Per-filter failure behaviour. - pub failure_mode: FailureMode, + /// Zero-based index of this filter in the overall pipeline. + pub pipeline_index: usize, } // ----------------------------------------------------------------------------- @@ -167,12 +167,12 @@ fn build_resolved_filters( .ok_or_else(|| format!("unknown chain '{chain_name}' in validated config"))?; for (chain_index, entry) in chain_filters.iter().enumerate() { filters.push(ResolvedFilterDump { + name: entry.name.clone(), chain: chain_name.clone(), chain_index, - pipeline_index, - filter: entry.filter_type.clone(), - name: entry.name.clone(), failure_mode: entry.failure_mode, + filter: entry.filter_type.clone(), + pipeline_index, }); pipeline_index += 1; } diff --git a/tests/utils/src/agentic/mcp.rs b/tests/utils/src/agentic/mcp.rs index ebecc68306..38f21c08ee 100644 --- a/tests/utils/src/agentic/mcp.rs +++ b/tests/utils/src/agentic/mcp.rs @@ -79,14 +79,14 @@ impl Default for McpMockConfig { /// A tool fixture advertised by the mock MCP server. pub struct McpToolFixture { + /// Tool name used for matching in `tools/call`. + pub name: String, + /// Tool description shown in `tools/list`. pub description: Option, /// JSON Schema for the tool's input parameters. pub input_schema: Value, - - /// Tool name used for matching in `tools/call`. - pub name: String, } impl McpToolFixture { @@ -94,9 +94,9 @@ impl McpToolFixture { /// object schema, and no description. pub fn new(name: impl Into) -> Self { Self { + name: name.into(), description: None, input_schema: json!({"type": "object", "additionalProperties": false}), - name: name.into(), } } From 8f4b3923a536b5058785ec57c84f59aef2179876 Mon Sep 17 00:00:00 2001 From: Shane Utt Date: Mon, 1 Jun 2026 20:13:54 -0400 Subject: [PATCH 004/646] style: add assertion messages to all bare asserts Add descriptive message strings to every assert!/assert_eq! call in MCP, JSON-RPC, and A2A test files. Extract assert_promoted_header/assert_no_promoted_header helpers. Signed-off-by: Shane Utt --- .../src/builtins/http/ai/agentic/a2a/tests.rs | 176 +++++++-- .../http/ai/agentic/json_rpc/tests.rs | 336 ++++++++++++------ .../http/ai/agentic/mcp/broker/tests.rs | 2 +- .../src/builtins/http/ai/agentic/mcp/tests.rs | 232 +++++++++--- 4 files changed, 548 insertions(+), 198 deletions(-) diff --git a/filter/src/builtins/http/ai/agentic/a2a/tests.rs b/filter/src/builtins/http/ai/agentic/a2a/tests.rs index 805de65d51..097210b815 100644 --- a/filter/src/builtins/http/ai/agentic/a2a/tests.rs +++ b/filter/src/builtins/http/ai/agentic/a2a/tests.rs @@ -23,7 +23,7 @@ use crate::{FilterAction, filter::HttpFilter}; fn parse_minimal_config() { let yaml: serde_yaml::Value = serde_yaml::from_str("{}").unwrap(); let filter = A2aFilter::from_config(&yaml).unwrap(); - assert_eq!(filter.name(), "a2a"); + assert_eq!(filter.name(), "a2a", "minimal config should produce a2a filter"); } #[test] @@ -48,7 +48,7 @@ fn parse_full_config() { ) .unwrap(); let filter = A2aFilter::from_config(&yaml).unwrap(); - assert_eq!(filter.name(), "a2a"); + assert_eq!(filter.name(), "a2a", "full config should produce a2a filter"); } #[test] @@ -177,12 +177,36 @@ fn method_classification_is_case_sensitive() { #[test] fn family_classification_message_and_task() { - assert_eq!(A2aMethod::SendMessage.family(), A2aFamily::Message); - assert_eq!(A2aMethod::SendStreamingMessage.family(), A2aFamily::Message); - assert_eq!(A2aMethod::GetTask.family(), A2aFamily::Task); - assert_eq!(A2aMethod::ListTasks.family(), A2aFamily::Task); - assert_eq!(A2aMethod::CancelTask.family(), A2aFamily::Task); - assert_eq!(A2aMethod::SubscribeToTask.family(), A2aFamily::Task); + assert_eq!( + A2aMethod::SendMessage.family(), + A2aFamily::Message, + "SendMessage should be Message family" + ); + assert_eq!( + A2aMethod::SendStreamingMessage.family(), + A2aFamily::Message, + "SendStreamingMessage should be Message family" + ); + assert_eq!( + A2aMethod::GetTask.family(), + A2aFamily::Task, + "GetTask should be Task family" + ); + assert_eq!( + A2aMethod::ListTasks.family(), + A2aFamily::Task, + "ListTasks should be Task family" + ); + assert_eq!( + A2aMethod::CancelTask.family(), + A2aFamily::Task, + "CancelTask should be Task family" + ); + assert_eq!( + A2aMethod::SubscribeToTask.family(), + A2aFamily::Task, + "SubscribeToTask should be Task family" + ); } #[test] @@ -393,7 +417,11 @@ fn no_original_method_for_canonical() { let json = serde_json::json!({"jsonrpc": "2.0", "method": "SendMessage"}); let envelope = extract_a2a_envelope(&json, "SendMessage", &BTreeMap::new(), &HeaderMap::new()); - assert_eq!(envelope.method, A2aMethod::SendMessage); + assert_eq!( + envelope.method, + A2aMethod::SendMessage, + "canonical method should resolve directly" + ); assert_eq!( envelope.original_method, None, "canonical method should not set original_method" @@ -458,9 +486,20 @@ async fn streaming_message_sets_streaming_true() { let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); - assert!(matches!(action, FilterAction::Release)); - assert_eq!(ctx.get_metadata("a2a.streaming"), Some("true")); - assert_eq!(ctx.get_metadata("a2a.family"), Some("message")); + assert!( + matches!(action, FilterAction::Release), + "streaming message should release" + ); + assert_eq!( + ctx.get_metadata("a2a.streaming"), + Some("true"), + "streaming should be true" + ); + assert_eq!( + ctx.get_metadata("a2a.family"), + Some("message"), + "family should be message" + ); } #[tokio::test] @@ -473,10 +512,18 @@ async fn get_task_extracts_task_id() { let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); - assert!(matches!(action, FilterAction::Release)); - assert_eq!(ctx.get_metadata("a2a.method"), Some("GetTask")); - assert_eq!(ctx.get_metadata("a2a.family"), Some("task")); - assert_eq!(ctx.get_metadata("a2a.task_id"), Some("task-999")); + assert!(matches!(action, FilterAction::Release), "GetTask should release"); + assert_eq!( + ctx.get_metadata("a2a.method"), + Some("GetTask"), + "method should be GetTask" + ); + assert_eq!(ctx.get_metadata("a2a.family"), Some("task"), "family should be task"); + assert_eq!( + ctx.get_metadata("a2a.task_id"), + Some("task-999"), + "task_id should be extracted" + ); } #[tokio::test] @@ -490,9 +537,20 @@ async fn push_notification_config_extracts_task_id_from_params() { let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); - assert!(matches!(action, FilterAction::Release)); - assert_eq!(ctx.get_metadata("a2a.family"), Some("push_notification")); - assert_eq!(ctx.get_metadata("a2a.task_id"), Some("task-abc")); + assert!( + matches!(action, FilterAction::Release), + "push notification config should release" + ); + assert_eq!( + ctx.get_metadata("a2a.family"), + Some("push_notification"), + "family should be push_notification" + ); + assert_eq!( + ctx.get_metadata("a2a.task_id"), + Some("task-abc"), + "task_id should be extracted from params" + ); } #[tokio::test] @@ -532,8 +590,16 @@ async fn unknown_method_classifies_as_family_unknown() { matches!(action, FilterAction::Release), "unknown methods should still be classified, not rejected" ); - assert_eq!(ctx.get_metadata("a2a.method"), Some("CustomUnknown")); - assert_eq!(ctx.get_metadata("a2a.family"), Some("unknown")); + assert_eq!( + ctx.get_metadata("a2a.method"), + Some("CustomUnknown"), + "unknown method should be promoted" + ); + assert_eq!( + ctx.get_metadata("a2a.family"), + Some("unknown"), + "unknown method family should be unknown" + ); } #[tokio::test] @@ -547,7 +613,7 @@ async fn version_header_extracted_to_metadata() { let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); - assert!(matches!(action, FilterAction::Release)); + assert!(matches!(action, FilterAction::Release), "should release with version"); assert_eq!( ctx.get_metadata("a2a.version"), Some("1.0"), @@ -613,7 +679,7 @@ async fn on_request_is_noop() { let action = filter.on_request(&mut ctx).await.unwrap(); - assert!(matches!(action, FilterAction::Continue)); + assert!(matches!(action, FilterAction::Continue), "on_request should be a no-op"); } #[tokio::test] @@ -700,7 +766,7 @@ async fn promotes_filter_results() { let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); - assert!(matches!(action, FilterAction::Release)); + assert!(matches!(action, FilterAction::Release), "should release on valid A2A"); let results = ctx.filter_results.get("a2a").unwrap(); assert_eq!( @@ -736,7 +802,7 @@ async fn promotes_method_and_family_headers() { let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); - assert!(matches!(action, FilterAction::Release)); + assert!(matches!(action, FilterAction::Release), "should release on valid A2A"); let headers: std::collections::HashMap<_, _> = ctx .extra_request_headers @@ -744,8 +810,16 @@ async fn promotes_method_and_family_headers() { .map(|(k, v)| (k.as_ref(), v.as_str())) .collect(); - assert_eq!(headers.get("x-praxis-a2a-method"), Some(&"SendStreamingMessage")); - assert_eq!(headers.get("x-praxis-a2a-family"), Some(&"message")); + assert_eq!( + headers.get("x-praxis-a2a-method"), + Some(&"SendStreamingMessage"), + "method header should be promoted" + ); + assert_eq!( + headers.get("x-praxis-a2a-family"), + Some(&"message"), + "family header should be promoted" + ); } #[tokio::test] @@ -758,7 +832,7 @@ async fn promotes_kind_and_streaming_headers() { let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); - assert!(matches!(action, FilterAction::Release)); + assert!(matches!(action, FilterAction::Release), "should release on valid A2A"); let headers: std::collections::HashMap<_, _> = ctx .extra_request_headers @@ -766,8 +840,16 @@ async fn promotes_kind_and_streaming_headers() { .map(|(k, v)| (k.as_ref(), v.as_str())) .collect(); - assert_eq!(headers.get("x-praxis-a2a-kind"), Some(&"request")); - assert_eq!(headers.get("x-praxis-a2a-streaming"), Some(&"true")); + assert_eq!( + headers.get("x-praxis-a2a-kind"), + Some(&"request"), + "kind header should be promoted" + ); + assert_eq!( + headers.get("x-praxis-a2a-streaming"), + Some(&"true"), + "streaming header should be true" + ); } #[tokio::test] @@ -780,7 +862,7 @@ async fn notification_sets_kind() { let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); - assert!(matches!(action, FilterAction::Release)); + assert!(matches!(action, FilterAction::Release), "notification should release"); assert_eq!( ctx.get_metadata("json_rpc.kind"), Some("notification"), @@ -799,7 +881,7 @@ async fn version_promoted_to_headers_and_results() { let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); - assert!(matches!(action, FilterAction::Release)); + assert!(matches!(action, FilterAction::Release), "should release with version"); let headers: std::collections::HashMap<_, _> = ctx .extra_request_headers @@ -834,7 +916,10 @@ async fn control_char_method_skips_all_promotions() { let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); - assert!(matches!(action, FilterAction::Release)); + assert!( + matches!(action, FilterAction::Release), + "control char method should still release" + ); let headers: std::collections::HashMap<_, _> = ctx .extra_request_headers @@ -870,7 +955,10 @@ async fn control_char_task_id_skips_promotion() { let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); - assert!(matches!(action, FilterAction::Release)); + assert!( + matches!(action, FilterAction::Release), + "control char task ID should still release" + ); assert_eq!( ctx.get_metadata("a2a.task_id"), None, @@ -889,7 +977,10 @@ async fn too_long_task_id_not_promoted() { let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); - assert!(matches!(action, FilterAction::Release)); + assert!( + matches!(action, FilterAction::Release), + "too-long task ID should still release" + ); assert_eq!( ctx.get_metadata("a2a.task_id"), None, @@ -919,7 +1010,10 @@ async fn too_long_version_not_promoted() { let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); - assert!(matches!(action, FilterAction::Release)); + assert!( + matches!(action, FilterAction::Release), + "too-long version should still release" + ); assert_eq!( ctx.get_metadata("a2a.version"), None, @@ -997,7 +1091,10 @@ async fn canonical_method_stores_same_in_json_rpc_method() { let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); - assert!(matches!(action, FilterAction::Release)); + assert!( + matches!(action, FilterAction::Release), + "canonical method should release" + ); assert_eq!( ctx.get_metadata("json_rpc.method"), Some("SendMessage"), @@ -1026,11 +1123,12 @@ fn make_default_filter() -> A2aFilter { fn make_filter(yaml: &str) -> A2aFilter { let cfg: A2aConfig = serde_yaml::from_str(yaml).unwrap(); let validated_config = build_config(cfg).unwrap(); - let json_rpc_config = super::build_json_rpc_config(validated_config.max_body_bytes); + let max_body_bytes = validated_config.max_body_bytes; + let json_rpc_config = super::build_json_rpc_config(max_body_bytes); A2aFilter { - max_body_bytes: validated_config.max_body_bytes, config: validated_config, json_rpc_config, + max_body_bytes, } } diff --git a/filter/src/builtins/http/ai/agentic/json_rpc/tests.rs b/filter/src/builtins/http/ai/agentic/json_rpc/tests.rs index ad327feb6e..fcc570748f 100644 --- a/filter/src/builtins/http/ai/agentic/json_rpc/tests.rs +++ b/filter/src/builtins/http/ai/agentic/json_rpc/tests.rs @@ -20,7 +20,11 @@ use crate::{FilterAction, filter::HttpFilter}; fn parse_minimal_config() { let yaml: serde_yaml::Value = serde_yaml::from_str("{}").unwrap(); let filter = JsonRpcFilter::from_config(&yaml).unwrap(); - assert_eq!(filter.name(), "json_rpc"); + assert_eq!( + filter.name(), + "json_rpc", + "minimal config should produce json_rpc filter" + ); } #[test] @@ -38,14 +42,17 @@ fn parse_full_config() { ) .unwrap(); let filter = JsonRpcFilter::from_config(&yaml).unwrap(); - assert_eq!(filter.name(), "json_rpc"); + assert_eq!(filter.name(), "json_rpc", "full config should produce json_rpc filter"); } #[test] fn reject_zero_max_body_bytes() { let yaml: serde_yaml::Value = serde_yaml::from_str("max_body_bytes: 0").unwrap(); let err = JsonRpcFilter::from_config(&yaml).err().expect("should fail"); - assert!(err.to_string().contains("must be greater than 0")); + assert!( + err.to_string().contains("must be greater than 0"), + "error should mention max_body_bytes constraint" + ); } #[test] @@ -58,7 +65,10 @@ fn reject_empty_header_names() { ) .unwrap(); let err = JsonRpcFilter::from_config(&yaml).err().expect("should fail"); - assert!(err.to_string().contains("must not be empty")); + assert!( + err.to_string().contains("must not be empty"), + "error should mention empty header name" + ); } #[test] @@ -71,14 +81,17 @@ fn reject_invalid_header_names() { ) .unwrap(); let err = JsonRpcFilter::from_config(&yaml).err().expect("should fail"); - assert!(err.to_string().contains("not a valid HTTP header name")); + assert!( + err.to_string().contains("not a valid HTTP header name"), + "error should mention invalid header name" + ); } #[test] fn default_headers_config_parses() { let yaml: serde_yaml::Value = serde_yaml::from_str("{}").unwrap(); let filter = JsonRpcFilter::from_config(&yaml).unwrap(); - assert_eq!(filter.name(), "json_rpc"); + assert_eq!(filter.name(), "json_rpc", "default headers config should parse"); } // ----------------------------------------------------------------------------- @@ -91,11 +104,15 @@ fn parses_request_with_string_id() { let json = br#"{"jsonrpc":"2.0","method":"tools/call","id":"req-123"}"#; let envelope = parse_json_rpc_envelope(json, &config).unwrap().unwrap(); - assert_eq!(envelope.kind, JsonRpcKind::Request); - assert_eq!(envelope.method, Some("tools/call".to_owned())); - assert_eq!(envelope.id, Some("req-123".to_owned())); - assert_eq!(envelope.id_kind, JsonRpcIdKind::String); - assert_eq!(envelope.batch_len, None); + assert_eq!(envelope.kind, JsonRpcKind::Request, "kind should be request"); + assert_eq!( + envelope.method, + Some("tools/call".to_owned()), + "method should be tools/call" + ); + assert_eq!(envelope.id, Some("req-123".to_owned()), "id should be req-123"); + assert_eq!(envelope.id_kind, JsonRpcIdKind::String, "id_kind should be string"); + assert_eq!(envelope.batch_len, None, "batch_len should be None"); } #[test] @@ -104,10 +121,14 @@ fn parses_request_with_integer_id() { let json = br#"{"jsonrpc":"2.0","method":"SendMessage","id":42}"#; let envelope = parse_json_rpc_envelope(json, &config).unwrap().unwrap(); - assert_eq!(envelope.kind, JsonRpcKind::Request); - assert_eq!(envelope.method, Some("SendMessage".to_owned())); - assert_eq!(envelope.id, Some("42".to_owned())); - assert_eq!(envelope.id_kind, JsonRpcIdKind::Integer); + assert_eq!(envelope.kind, JsonRpcKind::Request, "kind should be request"); + assert_eq!( + envelope.method, + Some("SendMessage".to_owned()), + "method should be SendMessage" + ); + assert_eq!(envelope.id, Some("42".to_owned()), "id should be 42"); + assert_eq!(envelope.id_kind, JsonRpcIdKind::Integer, "id_kind should be integer"); } #[test] @@ -116,8 +137,12 @@ fn parses_request_with_float_id() { let json = br#"{"jsonrpc":"2.0","method":"test","id":3.14}"#; let envelope = parse_json_rpc_envelope(json, &config).unwrap().unwrap(); - assert_eq!(envelope.kind, JsonRpcKind::Request); - assert_eq!(envelope.id_kind, JsonRpcIdKind::Number); + assert_eq!(envelope.kind, JsonRpcKind::Request, "kind should be request"); + assert_eq!( + envelope.id_kind, + JsonRpcIdKind::Number, + "float id should be Number kind" + ); } #[test] @@ -126,9 +151,13 @@ fn parses_request_with_null_id() { let json = br#"{"jsonrpc":"2.0","method":"test","id":null}"#; let envelope = parse_json_rpc_envelope(json, &config).unwrap().unwrap(); - assert_eq!(envelope.kind, JsonRpcKind::Request); - assert_eq!(envelope.id, Some("null".to_owned())); - assert_eq!(envelope.id_kind, JsonRpcIdKind::Null); + assert_eq!(envelope.kind, JsonRpcKind::Request, "kind should be request"); + assert_eq!( + envelope.id, + Some("null".to_owned()), + "null id should be stored as string" + ); + assert_eq!(envelope.id_kind, JsonRpcIdKind::Null, "id_kind should be Null"); } #[test] @@ -137,10 +166,14 @@ fn parses_notification() { let json = br#"{"jsonrpc":"2.0","method":"notifications/tools/list_changed"}"#; let envelope = parse_json_rpc_envelope(json, &config).unwrap().unwrap(); - assert_eq!(envelope.kind, JsonRpcKind::Notification); - assert_eq!(envelope.method, Some("notifications/tools/list_changed".to_owned())); - assert_eq!(envelope.id, None); - assert_eq!(envelope.id_kind, JsonRpcIdKind::Missing); + assert_eq!(envelope.kind, JsonRpcKind::Notification, "kind should be notification"); + assert_eq!( + envelope.method, + Some("notifications/tools/list_changed".to_owned()), + "method should be extracted" + ); + assert_eq!(envelope.id, None, "notification should have no id"); + assert_eq!(envelope.id_kind, JsonRpcIdKind::Missing, "id_kind should be Missing"); } #[test] @@ -149,10 +182,10 @@ fn parses_response_with_result() { let json = br#"{"jsonrpc":"2.0","id":"req-123","result":{"tools":[]}}"#; let envelope = parse_json_rpc_envelope(json, &config).unwrap().unwrap(); - assert_eq!(envelope.kind, JsonRpcKind::Response); - assert_eq!(envelope.method, None); - assert_eq!(envelope.id, Some("req-123".to_owned())); - assert_eq!(envelope.id_kind, JsonRpcIdKind::String); + assert_eq!(envelope.kind, JsonRpcKind::Response, "kind should be response"); + assert_eq!(envelope.method, None, "response should have no method"); + assert_eq!(envelope.id, Some("req-123".to_owned()), "id should be req-123"); + assert_eq!(envelope.id_kind, JsonRpcIdKind::String, "id_kind should be String"); } #[test] @@ -161,9 +194,9 @@ fn parses_response_with_error() { let json = br#"{"jsonrpc":"2.0","id":1,"error":{"code":-32601,"message":"Method not found"}}"#; let envelope = parse_json_rpc_envelope(json, &config).unwrap().unwrap(); - assert_eq!(envelope.kind, JsonRpcKind::Response); - assert_eq!(envelope.method, None); - assert_eq!(envelope.id, Some("1".to_owned())); + assert_eq!(envelope.kind, JsonRpcKind::Response, "kind should be response"); + assert_eq!(envelope.method, None, "error response should have no method"); + assert_eq!(envelope.id, Some("1".to_owned()), "id should be 1"); } #[test] @@ -171,7 +204,10 @@ fn rejects_missing_jsonrpc_field() { let config = make_config(BatchPolicy::Reject, InvalidJsonRpcBehavior::Reject); let json = br#"{"method":"test","id":1}"#; let err = parse_json_rpc_envelope(json, &config).expect_err("should fail"); - assert!(err.to_string().contains("missing 'jsonrpc'")); + assert!( + err.to_string().contains("missing 'jsonrpc'"), + "error should mention missing jsonrpc" + ); } #[test] @@ -179,7 +215,10 @@ fn continues_on_missing_jsonrpc_when_configured() { let config = make_config(BatchPolicy::Reject, InvalidJsonRpcBehavior::Continue); let json = br#"{"method":"test","id":1}"#; let result = parse_json_rpc_envelope(json, &config).unwrap(); - assert!(result.is_none()); + assert!( + result.is_none(), + "missing jsonrpc should return None when on_invalid: continue" + ); } #[test] @@ -187,7 +226,10 @@ fn rejects_wrong_jsonrpc_version() { let config = make_config(BatchPolicy::Reject, InvalidJsonRpcBehavior::Reject); let json = br#"{"jsonrpc":"1.0","method":"test","id":1}"#; let err = parse_json_rpc_envelope(json, &config).expect_err("should fail"); - assert!(err.to_string().contains("wrong jsonrpc version")); + assert!( + err.to_string().contains("wrong jsonrpc version"), + "error should mention wrong version" + ); } #[test] @@ -195,7 +237,10 @@ fn rejects_missing_method_for_request() { let config = make_config(BatchPolicy::Reject, InvalidJsonRpcBehavior::Reject); let json = br#"{"jsonrpc":"2.0","id":1}"#; let err = parse_json_rpc_envelope(json, &config).expect_err("should fail"); - assert!(err.to_string().contains("missing 'method'")); + assert!( + err.to_string().contains("missing 'method'"), + "error should mention missing method" + ); } #[test] @@ -203,7 +248,10 @@ fn rejects_non_string_method() { let config = make_config(BatchPolicy::Reject, InvalidJsonRpcBehavior::Reject); let json = br#"{"jsonrpc":"2.0","method":123,"id":1}"#; let err = parse_json_rpc_envelope(json, &config).expect_err("should fail"); - assert!(err.to_string().contains("must be a string")); + assert!( + err.to_string().contains("must be a string"), + "error should mention string requirement" + ); } #[test] @@ -211,7 +259,10 @@ fn rejects_boolean_id() { let config = make_config(BatchPolicy::Reject, InvalidJsonRpcBehavior::Reject); let json = br#"{"jsonrpc":"2.0","method":"test","id":true}"#; let err = parse_json_rpc_envelope(json, &config).expect_err("should fail"); - assert!(err.to_string().contains("must be string, number, or null")); + assert!( + err.to_string().contains("must be string, number, or null"), + "error should mention valid id types" + ); } #[test] @@ -219,7 +270,10 @@ fn rejects_object_id() { let config = make_config(BatchPolicy::Reject, InvalidJsonRpcBehavior::Reject); let json = br#"{"jsonrpc":"2.0","method":"test","id":{"key":"value"}}"#; let err = parse_json_rpc_envelope(json, &config).expect_err("should fail"); - assert!(err.to_string().contains("must be string, number, or null")); + assert!( + err.to_string().contains("must be string, number, or null"), + "error should mention valid id types" + ); } #[test] @@ -227,7 +281,10 @@ fn rejects_array_id() { let config = make_config(BatchPolicy::Reject, InvalidJsonRpcBehavior::Reject); let json = br#"{"jsonrpc":"2.0","method":"test","id":[1,2,3]}"#; let err = parse_json_rpc_envelope(json, &config).expect_err("should fail"); - assert!(err.to_string().contains("must be string, number, or null")); + assert!( + err.to_string().contains("must be string, number, or null"), + "error should mention valid id types" + ); } #[test] @@ -235,7 +292,11 @@ fn handles_params_object() { let config = make_config(BatchPolicy::Reject, InvalidJsonRpcBehavior::Continue); let json = br#"{"jsonrpc":"2.0","method":"test","params":{"arg1":"val1"},"id":1}"#; let envelope = parse_json_rpc_envelope(json, &config).unwrap().unwrap(); - assert_eq!(envelope.method, Some("test".to_owned())); + assert_eq!( + envelope.method, + Some("test".to_owned()), + "method should be extracted with params object" + ); } #[test] @@ -243,7 +304,11 @@ fn handles_params_array() { let config = make_config(BatchPolicy::Reject, InvalidJsonRpcBehavior::Continue); let json = br#"{"jsonrpc":"2.0","method":"test","params":["arg1","arg2"],"id":1}"#; let envelope = parse_json_rpc_envelope(json, &config).unwrap().unwrap(); - assert_eq!(envelope.method, Some("test".to_owned())); + assert_eq!( + envelope.method, + Some("test".to_owned()), + "method should be extracted with params array" + ); } #[test] @@ -251,7 +316,11 @@ fn handles_reserved_rpc_method() { let config = make_config(BatchPolicy::Reject, InvalidJsonRpcBehavior::Continue); let json = br#"{"jsonrpc":"2.0","method":"rpc.discovery","id":1}"#; let envelope = parse_json_rpc_envelope(json, &config).unwrap().unwrap(); - assert_eq!(envelope.method, Some("rpc.discovery".to_owned())); + assert_eq!( + envelope.method, + Some("rpc.discovery".to_owned()), + "reserved rpc. method should be accepted" + ); } #[test] @@ -259,7 +328,10 @@ fn batch_reject_policy_rejects_array() { let config = make_config(BatchPolicy::Reject, InvalidJsonRpcBehavior::Reject); let json = br#"[{"jsonrpc":"2.0","method":"test1","id":1},{"jsonrpc":"2.0","method":"test2","id":2}]"#; let err = parse_json_rpc_envelope(json, &config).expect_err("should fail"); - assert!(err.to_string().contains("not supported")); + assert!( + err.to_string().contains("not supported"), + "error should mention batch not supported" + ); } #[test] @@ -268,10 +340,14 @@ fn batch_first_policy_uses_first_item() { let json = br#"[{"jsonrpc":"2.0","method":"first","id":1},{"jsonrpc":"2.0","method":"second","id":2}]"#; let envelope = parse_json_rpc_envelope(json, &config).unwrap().unwrap(); - assert_eq!(envelope.kind, JsonRpcKind::Batch); - assert_eq!(envelope.method, Some("first".to_owned())); - assert_eq!(envelope.id, Some("1".to_owned())); - assert_eq!(envelope.batch_len, Some(2)); + assert_eq!(envelope.kind, JsonRpcKind::Batch, "kind should be batch"); + assert_eq!( + envelope.method, + Some("first".to_owned()), + "should use first item method" + ); + assert_eq!(envelope.id, Some("1".to_owned()), "should use first item id"); + assert_eq!(envelope.batch_len, Some(2), "batch_len should be 2"); } #[test] @@ -280,8 +356,12 @@ fn batch_first_policy_skips_invalid_items() { let json = br#"[{"not":"jsonrpc"},{"jsonrpc":"2.0","method":"valid","id":2}]"#; let envelope = parse_json_rpc_envelope(json, &config).unwrap().unwrap(); - assert_eq!(envelope.method, Some("valid".to_owned())); - assert_eq!(envelope.batch_len, Some(2)); + assert_eq!( + envelope.method, + Some("valid".to_owned()), + "should skip invalid and use valid item" + ); + assert_eq!(envelope.batch_len, Some(2), "batch_len should be 2"); } #[test] @@ -289,7 +369,7 @@ fn empty_batch_array_fails() { let config = make_config(BatchPolicy::First, InvalidJsonRpcBehavior::Continue); let json = br#"[]"#; let err = parse_json_rpc_envelope(json, &config).expect_err("should fail"); - assert!(err.to_string().contains("empty")); + assert!(err.to_string().contains("empty"), "error should mention empty batch"); } #[test] @@ -297,7 +377,10 @@ fn invalid_json_fails() { let config = make_config(BatchPolicy::Reject, InvalidJsonRpcBehavior::Reject); let json = b"not json at all"; let err = parse_json_rpc_envelope(json, &config).expect_err("should fail"); - assert!(err.to_string().contains("invalid JSON")); + assert!( + err.to_string().contains("invalid JSON"), + "error should mention invalid JSON" + ); } #[test] @@ -305,7 +388,7 @@ fn non_object_json_continues_when_configured() { let config = make_config(BatchPolicy::Reject, InvalidJsonRpcBehavior::Continue); let json = br#""just a string""#; let result = parse_json_rpc_envelope(json, &config).unwrap(); - assert!(result.is_none()); + assert!(result.is_none(), "non-object JSON should return None when continuing"); } // ----------------------------------------------------------------------------- @@ -317,26 +400,22 @@ async fn extracts_method_from_request() { let filter = make_filter(); let req = crate::test_utils::make_request(http::Method::POST, "/mcp"); let mut ctx = crate::test_utils::make_filter_context(&req); - let json = br#"{"jsonrpc":"2.0","method":"tools/call","id":"req-123"}"#; let mut body = Some(Bytes::from_static(json)); - let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); - - assert!(matches!(action, FilterAction::Release)); - - assert_eq!(ctx.extra_request_headers.len(), 3); - let headers: std::collections::HashMap<_, _> = - ctx.extra_request_headers.iter().map(|(k, v)| (k.as_ref(), v)).collect(); - assert_eq!(headers.get("X-Json-Rpc-Method").map(|s| s.as_str()), Some("tools/call")); - assert_eq!(headers.get("X-Json-Rpc-Id").map(|s| s.as_str()), Some("req-123")); - assert_eq!(headers.get("X-Json-Rpc-Kind").map(|s| s.as_str()), Some("request")); - + assert!( + matches!(action, FilterAction::Release), + "should release on valid JSON-RPC" + ); + assert_eq!(ctx.extra_request_headers.len(), 3, "should promote 3 headers"); + assert_promoted_header(&ctx, "X-Json-Rpc-Method", "tools/call"); + assert_promoted_header(&ctx, "X-Json-Rpc-Id", "req-123"); + assert_promoted_header(&ctx, "X-Json-Rpc-Kind", "request"); let results = ctx.filter_results.get("json_rpc").unwrap(); - assert_eq!(results.get("method"), Some("tools/call")); - assert_eq!(results.get("id"), Some("req-123")); - assert_eq!(results.get("kind"), Some("request")); - assert_eq!(results.get("id_kind"), Some("string")); + assert_eq!(results.get("method"), Some("tools/call"), "method result"); + assert_eq!(results.get("id"), Some("req-123"), "id result"); + assert_eq!(results.get("kind"), Some("request"), "kind result"); + assert_eq!(results.get("id_kind"), Some("string"), "id_kind result"); } #[tokio::test] @@ -344,26 +423,24 @@ async fn extracts_notification() { let filter = make_filter(); let req = crate::test_utils::make_request(http::Method::POST, "/mcp"); let mut ctx = crate::test_utils::make_filter_context(&req); - let json = br#"{"jsonrpc":"2.0","method":"notifications/tools/list_changed"}"#; let mut body = Some(Bytes::from_static(json)); - let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); - - assert!(matches!(action, FilterAction::Release)); - - let headers: std::collections::HashMap<_, _> = - ctx.extra_request_headers.iter().map(|(k, v)| (k.as_ref(), v)).collect(); + assert!(matches!(action, FilterAction::Release), "notification should release"); + assert_promoted_header(&ctx, "X-Json-Rpc-Method", "notifications/tools/list_changed"); + assert_promoted_header(&ctx, "X-Json-Rpc-Kind", "notification"); + assert_no_promoted_header(&ctx, "X-Json-Rpc-Id"); + let results = ctx.filter_results.get("json_rpc").unwrap(); assert_eq!( - headers.get("X-Json-Rpc-Method").map(|s| s.as_str()), - Some("notifications/tools/list_changed") + results.get("kind"), + Some("notification"), + "kind result should be notification" + ); + assert_eq!( + results.get("id_kind"), + Some("missing"), + "id_kind result should be missing" ); - assert_eq!(headers.get("X-Json-Rpc-Kind").map(|s| s.as_str()), Some("notification")); - assert!(!headers.contains_key("X-Json-Rpc-Id")); - - let results = ctx.filter_results.get("json_rpc").unwrap(); - assert_eq!(results.get("kind"), Some("notification")); - assert_eq!(results.get("id_kind"), Some("missing")); } #[tokio::test] @@ -377,8 +454,14 @@ async fn continues_on_incomplete_json() { let action = filter.on_request_body(&mut ctx, &mut body, false).await.unwrap(); - assert!(matches!(action, FilterAction::Continue)); - assert!(ctx.extra_request_headers.is_empty()); + assert!( + matches!(action, FilterAction::Continue), + "incomplete JSON should continue" + ); + assert!( + ctx.extra_request_headers.is_empty(), + "no headers should be promoted for incomplete JSON" + ); } #[tokio::test] @@ -391,8 +474,14 @@ async fn continues_on_non_json_body_by_default() { let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); - assert!(matches!(action, FilterAction::Continue)); - assert!(ctx.extra_request_headers.is_empty()); + assert!( + matches!(action, FilterAction::Continue), + "non-JSON should continue by default" + ); + assert!( + ctx.extra_request_headers.is_empty(), + "no headers should be promoted for non-JSON" + ); } #[tokio::test] @@ -446,7 +535,7 @@ async fn on_request_is_noop() { let action = filter.on_request(&mut ctx).await.unwrap(); - assert!(matches!(action, FilterAction::Continue)); + assert!(matches!(action, FilterAction::Continue), "on_request should continue"); } #[tokio::test] @@ -458,7 +547,7 @@ async fn returns_continue_on_none_body() { let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); - assert!(matches!(action, FilterAction::Continue)); + assert!(matches!(action, FilterAction::Continue), "None body should continue"); } #[tokio::test] @@ -472,12 +561,21 @@ async fn skips_header_with_control_chars() { let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); - assert!(matches!(action, FilterAction::Release)); + assert!( + matches!(action, FilterAction::Release), + "should release even with control chars" + ); let headers: std::collections::HashMap<_, _> = ctx.extra_request_headers.iter().map(|(k, v)| (k.as_ref(), v)).collect(); - assert!(!headers.contains_key("X-Json-Rpc-Method")); - assert!(headers.contains_key("X-Json-Rpc-Kind")); + assert!( + !headers.contains_key("X-Json-Rpc-Method"), + "control char method should not be promoted to header" + ); + assert!( + headers.contains_key("X-Json-Rpc-Kind"), + "kind header should still be promoted" + ); } #[tokio::test] @@ -491,17 +589,28 @@ async fn allows_tab_character() { let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); - assert!(matches!(action, FilterAction::Release)); + assert!( + matches!(action, FilterAction::Release), + "tab character should be allowed" + ); let headers: std::collections::HashMap<_, _> = ctx.extra_request_headers.iter().map(|(k, v)| (k.as_ref(), v)).collect(); - assert_eq!(headers.get("X-Json-Rpc-Method").map(|s| s.as_str()), Some("with\ttab")); + assert_eq!( + headers.get("X-Json-Rpc-Method").map(|s| s.as_str()), + Some("with\ttab"), + "tab in method should be promoted" + ); } #[test] fn body_access_is_read_only() { let filter = make_filter(); - assert_eq!(filter.request_body_access(), crate::body::BodyAccess::ReadOnly); + assert_eq!( + filter.request_body_access(), + crate::body::BodyAccess::ReadOnly, + "JSON-RPC filter should use ReadOnly body access" + ); } #[test] @@ -513,7 +622,8 @@ fn body_mode_is_stream_buffer() { filter.request_body_mode(), crate::body::BodyMode::StreamBuffer { max_bytes: Some(DEFAULT_MAX_BODY_BYTES) - } + }, + "JSON-RPC filter should use StreamBuffer with default max bytes" ); } @@ -523,30 +633,54 @@ fn body_mode_is_stream_buffer() { fn make_config(batch_policy: BatchPolicy, on_invalid: InvalidJsonRpcBehavior) -> super::config::JsonRpcConfig { super::config::JsonRpcConfig { - max_body_bytes: 1_048_576, batch_policy, - on_invalid, headers: JsonRpcHeaders::default(), + max_body_bytes: 1_048_576, + on_invalid, } } fn make_filter() -> JsonRpcFilter { JsonRpcFilter { - max_body_bytes: 1_048_576, config: make_config(BatchPolicy::Reject, InvalidJsonRpcBehavior::Continue), + max_body_bytes: 1_048_576, } } fn make_reject_filter() -> JsonRpcFilter { JsonRpcFilter { - max_body_bytes: 1_048_576, config: make_config(BatchPolicy::Reject, InvalidJsonRpcBehavior::Reject), + max_body_bytes: 1_048_576, } } fn make_error_filter() -> JsonRpcFilter { JsonRpcFilter { - max_body_bytes: 1_048_576, config: make_config(BatchPolicy::Reject, InvalidJsonRpcBehavior::Error), + max_body_bytes: 1_048_576, } } + +/// Assert that a specific promoted header has the expected value. +fn assert_promoted_header(ctx: &crate::filter::HttpFilterContext<'_>, name: &str, expected: &str) { + let headers: std::collections::HashMap<_, _> = ctx + .extra_request_headers + .iter() + .map(|(k, v)| (k.as_ref(), v.as_str())) + .collect(); + assert_eq!( + headers.get(name).copied(), + Some(expected), + "promoted header '{name}' should be '{expected}'" + ); +} + +/// Assert that a promoted header is absent. +fn assert_no_promoted_header(ctx: &crate::filter::HttpFilterContext<'_>, name: &str) { + let headers: std::collections::HashMap<_, _> = ctx + .extra_request_headers + .iter() + .map(|(k, v)| (k.as_ref(), v.as_str())) + .collect(); + assert!(!headers.contains_key(name), "promoted header '{name}' should be absent"); +} diff --git a/filter/src/builtins/http/ai/agentic/mcp/broker/tests.rs b/filter/src/builtins/http/ai/agentic/mcp/broker/tests.rs index a54d1e0842..6eaf18cc2e 100644 --- a/filter/src/builtins/http/ai/agentic/mcp/broker/tests.rs +++ b/filter/src/builtins/http/ai/agentic/mcp/broker/tests.rs @@ -1164,10 +1164,10 @@ servers: let (validated, catalog) = build_config(cfg).unwrap(); let json_rpc_config = build_json_rpc_config(validated.max_body_bytes); McpBrokerFilter { + catalog, json_rpc_config, max_body_bytes: validated.max_body_bytes, public_path: validated.path.clone(), - catalog, } } diff --git a/filter/src/builtins/http/ai/agentic/mcp/tests.rs b/filter/src/builtins/http/ai/agentic/mcp/tests.rs index 0e8fee82f8..6271a55057 100644 --- a/filter/src/builtins/http/ai/agentic/mcp/tests.rs +++ b/filter/src/builtins/http/ai/agentic/mcp/tests.rs @@ -19,7 +19,7 @@ use crate::{FilterAction, filter::HttpFilter}; fn parse_minimal_config() { let yaml: serde_yaml::Value = serde_yaml::from_str("{}").unwrap(); let filter = McpFilter::from_config(&yaml).unwrap(); - assert_eq!(filter.name(), "mcp"); + assert_eq!(filter.name(), "mcp", "minimal config should produce mcp filter"); } #[test] @@ -40,14 +40,17 @@ fn parse_full_config() { ) .unwrap(); let filter = McpFilter::from_config(&yaml).unwrap(); - assert_eq!(filter.name(), "mcp"); + assert_eq!(filter.name(), "mcp", "full config should produce mcp filter"); } #[test] fn reject_zero_max_body_bytes() { let yaml: serde_yaml::Value = serde_yaml::from_str("max_body_bytes: 0").unwrap(); let err = McpFilter::from_config(&yaml).err().expect("should fail"); - assert!(err.to_string().contains("must be greater than 0")); + assert!( + err.to_string().contains("must be greater than 0"), + "error should mention max_body_bytes constraint" + ); } #[test] @@ -60,7 +63,10 @@ fn reject_empty_header_names() { ) .unwrap(); let err = McpFilter::from_config(&yaml).err().expect("should fail"); - assert!(err.to_string().contains("must not be empty")); + assert!( + err.to_string().contains("must not be empty"), + "error should mention empty header name" + ); } #[test] @@ -73,7 +79,10 @@ fn reject_invalid_header_names() { ) .unwrap(); let err = McpFilter::from_config(&yaml).err().expect("should fail"); - assert!(err.to_string().contains("not a valid HTTP header name")); + assert!( + err.to_string().contains("not a valid HTTP header name"), + "error should mention invalid header name" + ); } // ----------------------------------------------------------------------------- @@ -90,9 +99,17 @@ async fn tools_call_extracts_method_and_name() { let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); - assert!(matches!(action, FilterAction::Release)); - assert_eq!(ctx.get_metadata("mcp.method"), Some("tools/call")); - assert_eq!(ctx.get_metadata("mcp.name"), Some("get_weather")); + assert!(matches!(action, FilterAction::Release), "tools/call should release"); + assert_eq!( + ctx.get_metadata("mcp.method"), + Some("tools/call"), + "method should be tools/call" + ); + assert_eq!( + ctx.get_metadata("mcp.name"), + Some("get_weather"), + "name should be get_weather" + ); } #[tokio::test] @@ -105,9 +122,17 @@ async fn initialize_extracts_protocol_version() { let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); - assert!(matches!(action, FilterAction::Release)); - assert_eq!(ctx.get_metadata("mcp.method"), Some("initialize")); - assert_eq!(ctx.get_metadata("mcp.protocol_version"), Some("2025-03-26")); + assert!(matches!(action, FilterAction::Release), "initialize should release"); + assert_eq!( + ctx.get_metadata("mcp.method"), + Some("initialize"), + "method should be initialize" + ); + assert_eq!( + ctx.get_metadata("mcp.protocol_version"), + Some("2025-03-26"), + "protocol version should be extracted" + ); } #[tokio::test] @@ -121,8 +146,15 @@ async fn session_id_detected() { let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); - assert!(matches!(action, FilterAction::Release)); - assert_eq!(ctx.get_metadata("mcp.session_id"), Some("gw-123")); + assert!( + matches!(action, FilterAction::Release), + "should release with session id" + ); + assert_eq!( + ctx.get_metadata("mcp.session_id"), + Some("gw-123"), + "session id should be detected" + ); } #[tokio::test] @@ -135,9 +167,17 @@ async fn resources_read_extracts_uri() { let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); - assert!(matches!(action, FilterAction::Release)); - assert_eq!(ctx.get_metadata("mcp.method"), Some("resources/read")); - assert_eq!(ctx.get_metadata("mcp.name"), Some("file:///data.csv")); + assert!(matches!(action, FilterAction::Release), "resources/read should release"); + assert_eq!( + ctx.get_metadata("mcp.method"), + Some("resources/read"), + "method should be resources/read" + ); + assert_eq!( + ctx.get_metadata("mcp.name"), + Some("file:///data.csv"), + "URI should be extracted as name" + ); } #[tokio::test] @@ -150,7 +190,7 @@ async fn non_json_rpc_continues_when_configured() { let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); - assert!(matches!(action, FilterAction::Continue)); + assert!(matches!(action, FilterAction::Continue), "non-JSON-RPC should continue"); } #[tokio::test] @@ -163,7 +203,10 @@ async fn non_json_rpc_rejected_by_default() { let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); - assert!(matches!(action, FilterAction::Reject(_))); + assert!( + matches!(action, FilterAction::Reject(_)), + "non-JSON-RPC should be rejected by default" + ); } #[tokio::test] @@ -174,7 +217,7 @@ async fn on_request_is_noop() { let action = filter.on_request(&mut ctx).await.unwrap(); - assert!(matches!(action, FilterAction::Continue)); + assert!(matches!(action, FilterAction::Continue), "on_request should be a no-op"); } #[tokio::test] @@ -186,13 +229,17 @@ async fn returns_continue_on_none_body() { let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); - assert!(matches!(action, FilterAction::Continue)); + assert!(matches!(action, FilterAction::Continue), "None body should continue"); } #[test] fn body_access_is_read_only() { let filter = make_default_filter(); - assert_eq!(filter.request_body_access(), crate::body::BodyAccess::ReadOnly); + assert_eq!( + filter.request_body_access(), + crate::body::BodyAccess::ReadOnly, + "MCP filter should use ReadOnly body access" + ); } #[test] @@ -202,7 +249,8 @@ fn body_mode_is_stream_buffer() { filter.request_body_mode(), crate::body::BodyMode::StreamBuffer { max_bytes: Some(super::config::DEFAULT_MAX_BODY_BYTES) - } + }, + "MCP filter should use StreamBuffer with default max bytes" ); } @@ -216,13 +264,25 @@ async fn promotes_filter_results() { let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); - assert!(matches!(action, FilterAction::Release)); + assert!(matches!(action, FilterAction::Release), "should release on valid MCP"); let results = ctx.filter_results.get("mcp").unwrap(); - assert_eq!(results.get("method"), Some("tools/call")); - assert_eq!(results.get("name"), Some("get_weather")); - assert_eq!(results.get("kind"), Some("request")); - assert_eq!(results.get("session_present"), Some("false")); + assert_eq!( + results.get("method"), + Some("tools/call"), + "method result should be tools/call" + ); + assert_eq!( + results.get("name"), + Some("get_weather"), + "name result should be get_weather" + ); + assert_eq!(results.get("kind"), Some("request"), "kind result should be request"); + assert_eq!( + results.get("session_present"), + Some("false"), + "session_present should be false without session header" + ); } #[tokio::test] @@ -232,21 +292,21 @@ async fn promotes_internal_headers() { let req = make_mcp_request(&[]); let mut ctx = crate::test_utils::make_filter_context(&req); let mut body = Some(Bytes::from(body_str)); - let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); - - assert!(matches!(action, FilterAction::Release)); - + assert!(matches!(action, FilterAction::Release), "should release on valid MCP"); let headers: std::collections::HashMap<_, _> = ctx .extra_request_headers .iter() .map(|(k, v)| (k.as_ref(), v.as_str())) .collect(); - - assert_eq!(headers.get("x-praxis-mcp-method"), Some(&"tools/call")); - assert_eq!(headers.get("x-praxis-mcp-name"), Some(&"get_weather")); - assert_eq!(headers.get("x-praxis-mcp-kind"), Some(&"request")); - assert_eq!(headers.get("x-praxis-mcp-session-present"), Some(&"false")); + assert_eq!(headers.get("x-praxis-mcp-method"), Some(&"tools/call"), "method header"); + assert_eq!(headers.get("x-praxis-mcp-name"), Some(&"get_weather"), "name header"); + assert_eq!(headers.get("x-praxis-mcp-kind"), Some(&"request"), "kind header"); + assert_eq!( + headers.get("x-praxis-mcp-session-present"), + Some(&"false"), + "session-present header" + ); } #[tokio::test] @@ -260,10 +320,17 @@ async fn session_present_true_in_results() { let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); - assert!(matches!(action, FilterAction::Release)); + assert!( + matches!(action, FilterAction::Release), + "should release with session id" + ); let results = ctx.filter_results.get("mcp").unwrap(); - assert_eq!(results.get("session_present"), Some("true")); + assert_eq!( + results.get("session_present"), + Some("true"), + "session_present should be true when session header is present" + ); } #[tokio::test] @@ -276,9 +343,17 @@ async fn notification_sets_kind() { let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); - assert!(matches!(action, FilterAction::Release)); - assert_eq!(ctx.get_metadata("json_rpc.kind"), Some("notification")); - assert_eq!(ctx.get_metadata("mcp.method"), Some("notifications/initialized")); + assert!(matches!(action, FilterAction::Release), "notification should release"); + assert_eq!( + ctx.get_metadata("json_rpc.kind"), + Some("notification"), + "kind should be notification" + ); + assert_eq!( + ctx.get_metadata("mcp.method"), + Some("notifications/initialized"), + "method should be notifications/initialized" + ); } // ----------------------------------------------------------------------------- @@ -320,21 +395,30 @@ fn mcp_method_round_trips() { #[test] fn tools_call_requires_name() { use super::envelope::McpMethod; - assert!(McpMethod::ToolsCall.requires_name()); - assert!(!McpMethod::ToolsCall.requires_uri()); + assert!(McpMethod::ToolsCall.requires_name(), "tools/call should require name"); + assert!( + !McpMethod::ToolsCall.requires_uri(), + "tools/call should not require URI" + ); } #[test] fn resources_read_requires_uri() { use super::envelope::McpMethod; - assert!(McpMethod::ResourcesRead.requires_uri()); - assert!(!McpMethod::ResourcesRead.requires_name()); + assert!( + McpMethod::ResourcesRead.requires_uri(), + "resources/read should require URI" + ); + assert!( + !McpMethod::ResourcesRead.requires_name(), + "resources/read should not require name" + ); } #[test] fn prompts_get_requires_name() { use super::envelope::McpMethod; - assert!(McpMethod::PromptsGet.requires_name()); + assert!(McpMethod::PromptsGet.requires_name(), "prompts/get should require name"); } // ----------------------------------------------------------------------------- @@ -367,7 +451,10 @@ async fn complete_json_at_eos_releases() { let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); - assert!(matches!(action, FilterAction::Release)); + assert!( + matches!(action, FilterAction::Release), + "complete JSON at EOS should release" + ); } // ----------------------------------------------------------------------------- @@ -384,7 +471,10 @@ async fn control_char_method_skips_all_promotions() { let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); - assert!(matches!(action, FilterAction::Release)); + assert!( + matches!(action, FilterAction::Release), + "control char method should still release" + ); let headers: std::collections::HashMap<_, _> = ctx .extra_request_headers @@ -424,9 +514,20 @@ async fn matching_headers_succeed() { let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); - assert!(matches!(action, FilterAction::Release)); - assert_eq!(ctx.get_metadata("mcp.method"), Some("tools/call")); - assert_eq!(ctx.get_metadata("mcp.name"), Some("get_weather")); + assert!( + matches!(action, FilterAction::Release), + "matching headers should release" + ); + assert_eq!( + ctx.get_metadata("mcp.method"), + Some("tools/call"), + "method should be extracted" + ); + assert_eq!( + ctx.get_metadata("mcp.name"), + Some("get_weather"), + "name should be extracted" + ); } #[tokio::test] @@ -439,7 +540,10 @@ async fn header_body_mismatch_rejected() { let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); - assert!(matches!(action, FilterAction::Reject(_))); + assert!( + matches!(action, FilterAction::Reject(_)), + "header/body mismatch should be rejected" + ); } #[tokio::test] @@ -452,8 +556,15 @@ async fn missing_headers_ignored_by_default() { let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); - assert!(matches!(action, FilterAction::Release)); - assert_eq!(ctx.get_metadata("mcp.method"), Some("tools/call")); + assert!( + matches!(action, FilterAction::Release), + "missing headers should be ignored by default" + ); + assert_eq!( + ctx.get_metadata("mcp.method"), + Some("tools/call"), + "method should still be extracted" + ); } #[tokio::test] @@ -466,7 +577,10 @@ async fn missing_headers_rejected_when_configured() { let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); - assert!(matches!(action, FilterAction::Reject(_))); + assert!( + matches!(action, FilterAction::Reject(_)), + "missing headers should be rejected when configured" + ); } #[tokio::test] @@ -503,7 +617,10 @@ async fn invalid_utf8_header_ignored_when_mismatch_ignore() { let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); - assert!(matches!(action, FilterAction::Release)); + assert!( + matches!(action, FilterAction::Release), + "invalid UTF-8 header should be ignored when mismatch: ignore" + ); } // ----------------------------------------------------------------------------- @@ -771,10 +888,11 @@ fn make_filter(yaml: &str) -> McpFilter { let cfg: McpConfig = serde_yaml::from_str(yaml).unwrap(); let validated_config = build_config(cfg).unwrap(); let json_rpc_config = super::build_json_rpc_config(validated_config.max_body_bytes); + let max_body_bytes = validated_config.max_body_bytes; McpFilter { - max_body_bytes: validated_config.max_body_bytes, config: validated_config, json_rpc_config, + max_body_bytes, } } From 45e72d1380b1b08298c131afafb23af6fde20804 Mon Sep 17 00:00:00 2001 From: Shane Utt Date: Mon, 1 Jun 2026 20:14:41 -0400 Subject: [PATCH 005/646] perf: cache metrics SharedString in request ctx Pre-build the metrics SharedString when the cluster is selected during request_filter, avoiding an Arc::clone + SharedString construction per request in the logging hook. Signed-off-by: Shane Utt --- protocol/src/http/pingora/context.rs | 9 +++++++++ protocol/src/http/pingora/handler/mod.rs | 12 ++++++------ .../src/http/pingora/handler/request_filter/mod.rs | 3 ++- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/protocol/src/http/pingora/context.rs b/protocol/src/http/pingora/context.rs index c08af5c2cd..f39773cf36 100644 --- a/protocol/src/http/pingora/context.rs +++ b/protocol/src/http/pingora/context.rs @@ -87,6 +87,14 @@ pub struct PingoraRequestCtx { /// context construction. pub metrics_cluster: Option>, + /// Pre-built [`SharedString`] for the metrics cluster label. + /// + /// Cached when `metrics_cluster` is set so that + /// `emit_request_metrics` avoids an `Arc` clone per request. + /// + /// [`SharedString`]: ::metrics::SharedString + pub metrics_cluster_shared: Option<::metrics::SharedString>, + /// Pre-read body chunks (`StreamBuffer` mode). When `StreamBuffer` is /// active, the body is read during `request_filter` (before upstream /// selection) so that body-based routing can influence `upstream_peer`. @@ -296,6 +304,7 @@ impl Default for PingoraRequestCtx { mutated_request_body_len: None, filter_results: std::collections::HashMap::new(), metrics_cluster: None, + metrics_cluster_shared: None, pre_read_body: None, request_body_buffer: None, request_body_bytes: 0, diff --git a/protocol/src/http/pingora/handler/mod.rs b/protocol/src/http/pingora/handler/mod.rs index f6c706ecdc..4e407316b7 100644 --- a/protocol/src/http/pingora/handler/mod.rs +++ b/protocol/src/http/pingora/handler/mod.rs @@ -256,16 +256,16 @@ fn emit_request_metrics(session: &Session, ctx: &PingoraRequestCtx) { }; let method = metrics::method_label(raw_method); - let cluster = ctx.metrics_cluster.as_ref().map_or_else( - || ::metrics::SharedString::const_str("none"), - |cluster| ::metrics::SharedString::from(Arc::clone(cluster)), - ); + let cluster = ctx + .metrics_cluster_shared + .clone() + .unwrap_or_else(|| ::metrics::SharedString::const_str("none")); let labels = metrics::RequestMetricLabels { + cluster, method, - status_class, route: "unknown", - cluster, + status_class, }; let duration_secs = ctx.request_start.elapsed().as_secs_f64(); diff --git a/protocol/src/http/pingora/handler/request_filter/mod.rs b/protocol/src/http/pingora/handler/request_filter/mod.rs index 66b62b0f54..211c0ff659 100644 --- a/protocol/src/http/pingora/handler/request_filter/mod.rs +++ b/protocol/src/http/pingora/handler/request_filter/mod.rs @@ -3,7 +3,7 @@ //! Request-phase filter execution. -use std::borrow::Cow; +use std::{borrow::Cow, sync::Arc}; use pingora_core::Result; use pingora_proxy::Session; @@ -205,6 +205,7 @@ async fn run_pipeline( ctx.request_snapshot = Some(request); ctx.filter_metadata = filter_metadata; + ctx.metrics_cluster_shared = cluster.as_ref().map(|c| ::metrics::SharedString::from(Arc::clone(c))); ctx.metrics_cluster = cluster.clone(); match action { From 5a68f54dc5af27d20c39f204c60b523a178f5a53 Mon Sep 17 00:00:00 2001 From: Shane Utt Date: Mon, 1 Jun 2026 20:15:34 -0400 Subject: [PATCH 006/646] perf: inline ready_response in PingoraAdminService Call aggregate_health directly instead of constructing a PingoraHealthService per /ready request. Avoids an Arc clone of the health registry on every readiness probe. Signed-off-by: Shane Utt --- protocol/src/http/pingora/health/service.rs | 22 ++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/protocol/src/http/pingora/health/service.rs b/protocol/src/http/pingora/health/service.rs index bd246eefa3..1503e8155f 100644 --- a/protocol/src/http/pingora/health/service.rs +++ b/protocol/src/http/pingora/health/service.rs @@ -169,10 +169,26 @@ impl PingoraAdminService { /// Build the `/ready` response status and body. /// - /// Delegates to the same aggregation logic as [`PingoraHealthService`]. + /// Uses the same aggregation logic as [`PingoraHealthService`] + /// without constructing an intermediate struct. fn ready_response(&self) -> (u16, String) { - let health = PingoraHealthService::new(self.health_registry.clone(), self.verbose); - health.ready_response() + let Some(ref registry) = self.health_registry else { + return (200, r#"{"status":"ok"}"#.to_owned()); + }; + + if registry.is_empty() { + return ( + 200, + r#"{"status":"ok","clusters":{"total":0,"healthy":0,"degraded":0}}"#.to_owned(), + ); + } + + let agg = aggregate_health(registry, self.verbose); + let status_str = if agg.any_down { "degraded" } else { "ok" }; + let status_code: u16 = if agg.any_down { 503 } else { 200 }; + + let body = format_ready_body(status_str, &agg); + (status_code, body) } } From 2a17c62b6cfc9975acb1f699e95c538d72db74a6 Mon Sep 17 00:00:00 2001 From: Shane Utt Date: Mon, 1 Jun 2026 20:16:04 -0400 Subject: [PATCH 007/646] test: replace hardcoded sleeps with poll loop Replace thread::sleep(*ms) synchronization with a poll_until utility that checks the pipeline pointer with a 5-second timeout. May help reduce flakiness under CI load. Signed-off-by: Shane Utt --- server/src/watcher.rs | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/server/src/watcher.rs b/server/src/watcher.rs index ea2f6ccf78..43444457ac 100644 --- a/server/src/watcher.rs +++ b/server/src/watcher.rs @@ -326,7 +326,9 @@ mod tests { std::fs::write(&config_path, VALID_YAML_CHANGED).unwrap(); - std::thread::sleep(Duration::from_millis(2000)); + poll_until(Duration::from_secs(5), || { + Arc::as_ptr(&pipelines.get("web").unwrap().load()) != old_ptr + }); let new_ptr = Arc::as_ptr(&pipelines.get("web").unwrap().load()); assert_ne!(old_ptr, new_ptr, "pipeline should be swapped after config file change"); @@ -363,7 +365,8 @@ mod tests { std::thread::sleep(Duration::from_millis(200)); std::fs::write(&config_path, "invalid: [[[yaml").unwrap(); - std::thread::sleep(Duration::from_millis(1500)); + + std::thread::sleep(Duration::from_millis(DEBOUNCE_MS + 200)); let current_ptr = Arc::as_ptr(&pipelines.get("web").unwrap().load()); assert_eq!( @@ -372,7 +375,10 @@ mod tests { ); std::fs::write(&config_path, VALID_YAML_CHANGED).unwrap(); - std::thread::sleep(Duration::from_millis(1500)); + + poll_until(Duration::from_secs(5), || { + Arc::as_ptr(&pipelines.get("web").unwrap().load()) != old_ptr + }); let new_ptr = Arc::as_ptr(&pipelines.get("web").unwrap().load()); assert_ne!(old_ptr, new_ptr, "pipeline should recover after valid config"); @@ -441,6 +447,17 @@ mod tests { // Test Utilities // ------------------------------------------------------------------------- + /// Poll `predicate` every 20ms until it returns `true` or `timeout` elapses. + fn poll_until(timeout: Duration, predicate: impl Fn() -> bool) { + let deadline = std::time::Instant::now() + timeout; + while std::time::Instant::now() < deadline { + if predicate() { + return; + } + std::thread::sleep(Duration::from_millis(20)); + } + } + /// Serializes tests that mutate the process working directory. static CWD_MUTEX: std::sync::OnceLock> = std::sync::OnceLock::new(); From 6178ed2a3fec1e04adab207cb097089284bcd85b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Han?= Date: Tue, 2 Jun 2026 17:16:19 +0200 Subject: [PATCH 008/646] fix(ci): skip merge commits in conventions workflow checks (#464) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Merge commits are auto-generated by git and lack Signed-off-by trailers, may not be GPG-signed by the PR author, and have auto-generated commit metadata. Filter them out by selecting only commits with a single parent in the signed-commits-check, signoff-check, and ai-authorship-check jobs. Signed-off-by: Sébastien Han --- .github/workflows/conventions.yaml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/workflows/conventions.yaml b/.github/workflows/conventions.yaml index 045479119c..2db9bfa01c 100644 --- a/.github/workflows/conventions.yaml +++ b/.github/workflows/conventions.yaml @@ -187,7 +187,7 @@ jobs: fi unsigned=$(gh api "repos/${{ github.repository }}/pulls/${PR_NUMBER}/commits" \ - --paginate --jq '[.[] | select(.commit.verification.verified == false) | .sha[:7]] | join(", ")') + --paginate --jq '[.[] | select(.parents | length == 1) | select(.commit.verification.verified == false) | .sha[:7]] | join(", ")') if [ -n "$unsigned" ]; then marker="" @@ -226,7 +226,7 @@ jobs: missing=$(gh api \ "repos/${{ github.repository }}/pulls/${PR_NUMBER}/commits" \ --paginate \ - --jq '[.[] | select(.commit.message | test("(?m)^Signed-off-by: ") | not) | .sha[:7]] | join(", ")') + --jq '[.[] | select(.parents | length == 1) | select(.commit.message | test("(?m)^Signed-off-by: ") | not) | .sha[:7]] | join(", ")') if [ -n "$missing" ]; then marker="" @@ -281,7 +281,8 @@ jobs: --arg credit "$CREDIT" \ --arg any_trailer "$ANY_TRAILER" ' [ - (.[] | .sha[:7] as $sha | + (.[] | select(.parents | length == 1) | + .sha[:7] as $sha | select( (.commit.author.email | test($ai_email; "i")) or @@ -289,7 +290,8 @@ jobs: test($ai_email; "i")) ) | "- `\($sha)`: AI tool email in author/committer"), - (.[] | .sha[:7] as $sha | + (.[] | select(.parents | length == 1) | + .sha[:7] as $sha | select( (.commit.author.name | test($ai_author; "i")) or @@ -297,7 +299,8 @@ jobs: test($ai_author; "i")) ) | "- `\($sha)`: AI tool in author/committer name"), - (.[] | .sha[:7] as $sha | + (.[] | select(.parents | length == 1) | + .sha[:7] as $sha | .commit.message | split("\n")[] | select( (test($any_trailer; "i") and From e510c5e65cefb0bdf752c804f77b8c5731a92791 Mon Sep 17 00:00:00 2001 From: Shane Utt Date: Mon, 1 Jun 2026 21:22:07 -0400 Subject: [PATCH 009/646] fix(ext-proc): validate deferred_close_timeout Reject configs where deferred_close_timeout_ms is nonzero but less than message_timeout_ms. Deferred close must outlast individual message processing to avoid premature stream teardown. Signed-off-by: Shane Utt --- filter/ext-proc/src/lib.rs | 7 +++++++ filter/ext-proc/src/tests.rs | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/filter/ext-proc/src/lib.rs b/filter/ext-proc/src/lib.rs index 3b7aba898b..125f08e1bf 100644 --- a/filter/ext-proc/src/lib.rs +++ b/filter/ext-proc/src/lib.rs @@ -398,6 +398,13 @@ fn validate_core_fields(cfg: &ExtProcConfig) -> Result<(), FilterError> { if cfg.message_timeout_ms == 0 { return Err("ext_proc: message_timeout_ms must be greater than 0".into()); } + if cfg.deferred_close_timeout_ms > 0 && cfg.deferred_close_timeout_ms < cfg.message_timeout_ms { + let close = cfg.deferred_close_timeout_ms; + let msg = cfg.message_timeout_ms; + return Err( + format!("ext_proc: deferred_close_timeout_ms ({close}) must be >= message_timeout_ms ({msg})").into(), + ); + } if let Some(max) = cfg.max_message_timeout_ms { if max == 0 { return Err("ext_proc: max_message_timeout_ms must be greater than 0".into()); diff --git a/filter/ext-proc/src/tests.rs b/filter/ext-proc/src/tests.rs index d1054bd4dd..b683e10998 100644 --- a/filter/ext-proc/src/tests.rs +++ b/filter/ext-proc/src/tests.rs @@ -541,6 +541,24 @@ max_message_timeout_ms: 100 ); } +#[tokio::test] +async fn rejects_deferred_close_timeout_less_than_message_timeout() { + let yaml: serde_yaml::Value = serde_yaml::from_str( + r#" +target: "http://127.0.0.1:50051" +message_timeout_ms: 500 +deferred_close_timeout_ms: 100 +"#, + ) + .unwrap(); + + let err = ExtProcFilter::from_config(&yaml).err().expect("should error"); + assert!( + err.to_string().contains("deferred_close_timeout_ms"), + "error should reject deferred_close_timeout_ms < message_timeout_ms: {err}" + ); +} + #[tokio::test] async fn rejects_allowed_override_modes_with_entries() { let yaml: serde_yaml::Value = serde_yaml::from_str( From 02c4bfa5706de3b41d8d4f0e4d09864ed09504e7 Mon Sep 17 00:00:00 2001 From: Shane Utt Date: Mon, 1 Jun 2026 22:28:28 -0400 Subject: [PATCH 010/646] docs: document why RouterRouteConfig omits deny_unknown_fields The #[serde(flatten)] on the route field is incompatible with deny_unknown_fields. Add a doc comment explaining this and noting that Route's own deny_unknown_fields covers its fields. Signed-off-by: Shane Utt --- .../src/builtins/http/traffic_management/router/config.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/filter/src/builtins/http/traffic_management/router/config.rs b/filter/src/builtins/http/traffic_management/router/config.rs index e860ac269e..e15383a4ae 100644 --- a/filter/src/builtins/http/traffic_management/router/config.rs +++ b/filter/src/builtins/http/traffic_management/router/config.rs @@ -53,6 +53,13 @@ pub(super) struct RouterConfig { /// Router-owned route config so JSON body aliasing stays out of /// [`praxis_core::config::Route`]. +/// +/// `deny_unknown_fields` is intentionally omitted because +/// `#[serde(flatten)]` on `route` is incompatible with it. +/// Unknown fields within the `Route` portion are validated by +/// `Route`'s own `deny_unknown_fields`. +/// +/// [`praxis_core::config::Route`]: praxis_core::config::Route #[derive(Debug, Clone, Deserialize)] pub(super) struct RouterRouteConfig { /// Generic path, host, header, and cluster routing fields. From e47dd1802d4eb264ea7c0e54a61788c5ce1fb979 Mon Sep 17 00:00:00 2001 From: Shane Utt Date: Mon, 1 Jun 2026 22:30:06 -0400 Subject: [PATCH 011/646] security: zeroize credential values Credential values now use Zeroizing for automatic memory clearing on drop, matching the treatment private keys receive in the TLS crate. Signed-off-by: Shane Utt --- Cargo.lock | 1 + filter/Cargo.toml | 1 + .../http/security/credential_injection/filter.rs | 9 +++++---- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 77f0726df3..2e6b95e5c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2318,6 +2318,7 @@ dependencies = [ "tonic", "tracing", "yaml_serde", + "zeroize", ] [[package]] diff --git a/filter/Cargo.toml b/filter/Cargo.toml index 5cff914510..771162ff6f 100644 --- a/filter/Cargo.toml +++ b/filter/Cargo.toml @@ -38,6 +38,7 @@ serde_yaml = { workspace = true } thiserror = { workspace = true } tonic = { workspace = true, optional = true } tracing = { workspace = true } +zeroize = { workspace = true } [dev-dependencies] tokio = { workspace = true } diff --git a/filter/src/builtins/http/security/credential_injection/filter.rs b/filter/src/builtins/http/security/credential_injection/filter.rs index f2b0b173ed..b1f936b63a 100644 --- a/filter/src/builtins/http/security/credential_injection/filter.rs +++ b/filter/src/builtins/http/security/credential_injection/filter.rs @@ -6,6 +6,7 @@ use std::{borrow::Cow, collections::HashMap, sync::Arc}; use async_trait::async_trait; +use zeroize::Zeroizing; use super::config::{ClusterCredentialConfig, CredentialInjectionConfig}; use crate::{ @@ -23,8 +24,8 @@ struct ClusterCredential { /// Header name to inject. header: String, - /// Full header value (prefix + credential). - header_value: String, + /// Full header value (prefix + credential), zeroized on drop. + header_value: Zeroizing, } // ----------------------------------------------------------------------------- @@ -154,7 +155,7 @@ impl HttpFilter for CredentialInjectionFilter { "injecting credential header (replaces any client-provided value)" ); ctx.extra_request_headers - .push((Cow::Owned(cred.header.clone()), cred.header_value.clone())); + .push((Cow::Owned(cred.header.clone()), cred.header_value.as_str().to_owned())); Ok(FilterAction::Continue) } @@ -175,7 +176,7 @@ fn resolve_credential(cfg: &ClusterCredentialConfig) -> Result Date: Mon, 1 Jun 2026 22:30:30 -0400 Subject: [PATCH 012/646] fix: cap max_body_bytes at 64 MiB in AI protos Add MAX_JSON_BODY_BYTES (64 MiB) ceiling and reject configs that exceed it, preventing unbounded memory buffering via StreamBuffer. Same pattern as the router's MAX_JSON_ALIAS_BODY_BYTES cap. Signed-off-by: Shane Utt --- filter/src/body/limits.rs | 3 +++ filter/src/body/mod.rs | 2 +- filter/src/builtins/http/ai/agentic/a2a/config.rs | 10 +++++++++- filter/src/builtins/http/ai/agentic/a2a/tests.rs | 10 ++++++++++ filter/src/builtins/http/ai/agentic/json_rpc/config.rs | 10 +++++++++- filter/src/builtins/http/ai/agentic/json_rpc/tests.rs | 10 ++++++++++ filter/src/builtins/http/ai/openai/responses/config.rs | 10 +++++++++- filter/src/builtins/http/ai/openai/responses/tests.rs | 10 ++++++++++ 8 files changed, 61 insertions(+), 4 deletions(-) diff --git a/filter/src/body/limits.rs b/filter/src/body/limits.rs index 15858ecd01..6b02fafe6e 100644 --- a/filter/src/body/limits.rs +++ b/filter/src/body/limits.rs @@ -9,3 +9,6 @@ /// Default maximum body size for generic JSON request-body inspection (10 MiB). pub(crate) const DEFAULT_JSON_BODY_MAX_BYTES: usize = 10_485_760; // 10 MiB + +/// Hard ceiling for JSON body inspection buffers (64 MiB). +pub(crate) const MAX_JSON_BODY_BYTES: usize = 67_108_864; // 64 MiB diff --git a/filter/src/body/mod.rs b/filter/src/body/mod.rs index a0ee70bc8f..749f52a750 100644 --- a/filter/src/body/mod.rs +++ b/filter/src/body/mod.rs @@ -6,7 +6,7 @@ mod access; mod buffer; mod builder; -mod limits; +pub(crate) mod limits; mod mode; pub use access::BodyAccess; diff --git a/filter/src/builtins/http/ai/agentic/a2a/config.rs b/filter/src/builtins/http/ai/agentic/a2a/config.rs index 27ad9511ad..53204d2530 100644 --- a/filter/src/builtins/http/ai/agentic/a2a/config.rs +++ b/filter/src/builtins/http/ai/agentic/a2a/config.rs @@ -7,7 +7,7 @@ use std::collections::BTreeMap; use serde::Deserialize; -use crate::FilterError; +use crate::{FilterError, body::limits::MAX_JSON_BODY_BYTES}; // ----------------------------------------------------------------------------- // Constants @@ -172,6 +172,14 @@ pub(crate) fn build_config(cfg: A2aConfig) -> Result { return Err("a2a: 'max_body_bytes' must be greater than 0".into()); } + if cfg.max_body_bytes > MAX_JSON_BODY_BYTES { + return Err(format!( + "a2a: max_body_bytes ({}) exceeds maximum ({MAX_JSON_BODY_BYTES})", + cfg.max_body_bytes + ) + .into()); + } + // Validate header names validate_header_name("method", cfg.headers.method.as_deref())?; validate_header_name("family", cfg.headers.family.as_deref())?; diff --git a/filter/src/builtins/http/ai/agentic/a2a/tests.rs b/filter/src/builtins/http/ai/agentic/a2a/tests.rs index 097210b815..a6a0c57e52 100644 --- a/filter/src/builtins/http/ai/agentic/a2a/tests.rs +++ b/filter/src/builtins/http/ai/agentic/a2a/tests.rs @@ -61,6 +61,16 @@ fn reject_zero_max_body_bytes() { ); } +#[test] +fn rejects_max_body_bytes_above_ceiling() { + let yaml: serde_yaml::Value = serde_yaml::from_str("max_body_bytes: 67108865").unwrap(); + let err = A2aFilter::from_config(&yaml).err().expect("should fail"); + assert!( + err.to_string().contains("exceeds maximum"), + "error should mention exceeds maximum" + ); +} + #[test] fn reject_invalid_alias_target() { let yaml: serde_yaml::Value = serde_yaml::from_str( diff --git a/filter/src/builtins/http/ai/agentic/json_rpc/config.rs b/filter/src/builtins/http/ai/agentic/json_rpc/config.rs index c9f30d37f2..546e4d8fd2 100644 --- a/filter/src/builtins/http/ai/agentic/json_rpc/config.rs +++ b/filter/src/builtins/http/ai/agentic/json_rpc/config.rs @@ -5,7 +5,7 @@ use serde::Deserialize; -use crate::FilterError; +use crate::{FilterError, body::limits::MAX_JSON_BODY_BYTES}; // ----------------------------------------------------------------------------- // Body Constants @@ -114,6 +114,14 @@ pub(crate) fn build_config(cfg: JsonRpcConfig) -> Result<(usize, JsonRpcConfig), return Err("json_rpc: 'max_body_bytes' must be greater than 0".into()); } + if cfg.max_body_bytes > MAX_JSON_BODY_BYTES { + return Err(format!( + "json_rpc: max_body_bytes ({}) exceeds maximum ({MAX_JSON_BODY_BYTES})", + cfg.max_body_bytes + ) + .into()); + } + validate_header_name("method", cfg.headers.method.as_deref())?; validate_header_name("id", cfg.headers.id.as_deref())?; validate_header_name("kind", cfg.headers.kind.as_deref())?; diff --git a/filter/src/builtins/http/ai/agentic/json_rpc/tests.rs b/filter/src/builtins/http/ai/agentic/json_rpc/tests.rs index fcc570748f..a98d57b793 100644 --- a/filter/src/builtins/http/ai/agentic/json_rpc/tests.rs +++ b/filter/src/builtins/http/ai/agentic/json_rpc/tests.rs @@ -55,6 +55,16 @@ fn reject_zero_max_body_bytes() { ); } +#[test] +fn rejects_max_body_bytes_above_ceiling() { + let yaml: serde_yaml::Value = serde_yaml::from_str("max_body_bytes: 67108865").unwrap(); + let err = JsonRpcFilter::from_config(&yaml).err().expect("should fail"); + assert!( + err.to_string().contains("exceeds maximum"), + "error should mention exceeds maximum" + ); +} + #[test] fn reject_empty_header_names() { let yaml: serde_yaml::Value = serde_yaml::from_str( diff --git a/filter/src/builtins/http/ai/openai/responses/config.rs b/filter/src/builtins/http/ai/openai/responses/config.rs index 84f9bb431a..5cc4beef2e 100644 --- a/filter/src/builtins/http/ai/openai/responses/config.rs +++ b/filter/src/builtins/http/ai/openai/responses/config.rs @@ -5,7 +5,7 @@ use serde::Deserialize; -use crate::FilterError; +use crate::{FilterError, body::limits::MAX_JSON_BODY_BYTES}; // ----------------------------------------------------------------------------- // Constants @@ -135,6 +135,14 @@ pub(crate) fn build_config(cfg: ResponsesFormatConfig) -> Result MAX_JSON_BODY_BYTES { + return Err(format!( + "responses_format: max_body_bytes ({}) exceeds maximum ({MAX_JSON_BODY_BYTES})", + cfg.max_body_bytes + ) + .into()); + } + validate_header_name("format", cfg.headers.format.as_deref())?; validate_header_name("model", cfg.headers.model.as_deref())?; validate_header_name("stream", cfg.headers.stream.as_deref())?; diff --git a/filter/src/builtins/http/ai/openai/responses/tests.rs b/filter/src/builtins/http/ai/openai/responses/tests.rs index 715633b2a8..d8df7878c8 100644 --- a/filter/src/builtins/http/ai/openai/responses/tests.rs +++ b/filter/src/builtins/http/ai/openai/responses/tests.rs @@ -72,6 +72,16 @@ fn zero_max_body_bytes_rejected() { assert!(result.is_err(), "zero max_body_bytes should be rejected"); } +#[test] +fn rejects_max_body_bytes_above_ceiling() { + let yaml: serde_yaml::Value = serde_yaml::from_str("max_body_bytes: 67108865").unwrap(); + let result = ResponsesFormatFilter::from_config(&yaml); + assert!( + result.is_err(), + "max_body_bytes above 64 MiB ceiling should be rejected" + ); +} + #[test] fn invalid_header_name_rejected() { let yaml: serde_yaml::Value = serde_yaml::from_str( From d9cb4af858b70bf46ded1da2eecf751bab006159 Mon Sep 17 00:00:00 2001 From: Shane Utt Date: Mon, 1 Jun 2026 22:33:30 -0400 Subject: [PATCH 013/646] test: add fuzz targets for CIDR parsing, header names, body buffer Three new fuzz targets expanding coverage to previously unfuzzed attack surfaces: - fuzz_cidr_parse: CidrRange::parse with arbitrary strings - fuzz_header_name: http::HeaderName::from_bytes with arbitrary bytes - fuzz_body_buffer: BodyBuffer accumulation with random chunks, asserting frozen size never exceeds max_bytes Signed-off-by: Shane Utt --- tests/fuzz/Cargo.lock | 1 + tests/fuzz/Cargo.toml | 15 ++++++++++++++ tests/fuzz/fuzz_targets/fuzz_body_buffer.rs | 22 +++++++++++++++++++++ tests/fuzz/fuzz_targets/fuzz_cidr_parse.rs | 8 ++++++++ tests/fuzz/fuzz_targets/fuzz_header_name.rs | 7 +++++++ 5 files changed, 53 insertions(+) create mode 100644 tests/fuzz/fuzz_targets/fuzz_body_buffer.rs create mode 100644 tests/fuzz/fuzz_targets/fuzz_cidr_parse.rs create mode 100644 tests/fuzz/fuzz_targets/fuzz_header_name.rs diff --git a/tests/fuzz/Cargo.lock b/tests/fuzz/Cargo.lock index 50a9c141e5..1c7b4bc16b 100644 --- a/tests/fuzz/Cargo.lock +++ b/tests/fuzz/Cargo.lock @@ -1269,6 +1269,7 @@ dependencies = [ "thiserror 2.0.18", "tracing", "yaml_serde", + "zeroize", ] [[package]] diff --git a/tests/fuzz/Cargo.toml b/tests/fuzz/Cargo.toml index 3e84adf4b2..9fd2cc894f 100644 --- a/tests/fuzz/Cargo.toml +++ b/tests/fuzz/Cargo.toml @@ -37,3 +37,18 @@ doc = false name = "fuzz_filter_pipeline" path = "fuzz_targets/fuzz_filter_pipeline.rs" doc = false + +[[bin]] +name = "fuzz_cidr_parse" +path = "fuzz_targets/fuzz_cidr_parse.rs" +doc = false + +[[bin]] +name = "fuzz_header_name" +path = "fuzz_targets/fuzz_header_name.rs" +doc = false + +[[bin]] +name = "fuzz_body_buffer" +path = "fuzz_targets/fuzz_body_buffer.rs" +doc = false diff --git a/tests/fuzz/fuzz_targets/fuzz_body_buffer.rs b/tests/fuzz/fuzz_targets/fuzz_body_buffer.rs new file mode 100644 index 0000000000..ef5fd99ad3 --- /dev/null +++ b/tests/fuzz/fuzz_targets/fuzz_body_buffer.rs @@ -0,0 +1,22 @@ +#![no_main] + +use bytes::Bytes; +use libfuzzer_sys::fuzz_target; +use praxis_filter::BodyBuffer; + +fuzz_target!(|data: &[u8]| { + let max_bytes = 4096; + let mut buffer = BodyBuffer::new(max_bytes); + + for chunk in data.chunks(64) { + if buffer.push(Bytes::copy_from_slice(chunk)).is_err() { + return; + } + } + + let frozen = buffer.freeze(); + assert!( + frozen.len() <= max_bytes, + "frozen buffer must not exceed max_bytes" + ); +}); diff --git a/tests/fuzz/fuzz_targets/fuzz_cidr_parse.rs b/tests/fuzz/fuzz_targets/fuzz_cidr_parse.rs new file mode 100644 index 0000000000..c2427a8218 --- /dev/null +++ b/tests/fuzz/fuzz_targets/fuzz_cidr_parse.rs @@ -0,0 +1,8 @@ +#![no_main] + +use libfuzzer_sys::fuzz_target; +use praxis_core::connectivity::CidrRange; + +fuzz_target!(|data: &str| { + let _ = CidrRange::parse(data); +}); diff --git a/tests/fuzz/fuzz_targets/fuzz_header_name.rs b/tests/fuzz/fuzz_targets/fuzz_header_name.rs new file mode 100644 index 0000000000..8591b1f4f5 --- /dev/null +++ b/tests/fuzz/fuzz_targets/fuzz_header_name.rs @@ -0,0 +1,7 @@ +#![no_main] + +use libfuzzer_sys::fuzz_target; + +fuzz_target!(|data: &[u8]| { + let _ = http::HeaderName::from_bytes(data); +}); From 73645ea7da6f142e3200f8783f037914b9422018 Mon Sep 17 00:00:00 2001 From: Shane Utt Date: Mon, 1 Jun 2026 22:37:31 -0400 Subject: [PATCH 014/646] test: add cross-phase filter_metadata integration test Verify that metadata written during on_request_body survives to on_response via the filter_metadata writeback path. Uses a custom MetadataWriterFilter that writes in the body phase and promotes to a response header in the response phase. Signed-off-by: Shane Utt --- .../tests/suite/filter_metadata.rs | 108 ++++++++++++++++++ tests/integration/tests/suite/main.rs | 1 + 2 files changed, 109 insertions(+) create mode 100644 tests/integration/tests/suite/filter_metadata.rs diff --git a/tests/integration/tests/suite/filter_metadata.rs b/tests/integration/tests/suite/filter_metadata.rs new file mode 100644 index 0000000000..8669e9cf13 --- /dev/null +++ b/tests/integration/tests/suite/filter_metadata.rs @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2026 Praxis Contributors + +//! Integration test verifying `filter_metadata` survives across Pingora lifecycle phases. + +use bytes::Bytes; +use praxis_core::config::Config; +use praxis_filter::{BodyAccess, FilterAction, FilterError, HttpFilter, HttpFilterContext}; +use praxis_test_utils::{ + custom_filter_yaml, free_port, parse_header, registry_with, start_echo_backend_with_shutdown, + start_proxy_with_registry, +}; + +// --------------------------------------------------------------------------- +// Tests +// --------------------------------------------------------------------------- + +#[test] +fn metadata_written_in_request_body_survives_to_response_phase() { + let backend_guard = start_echo_backend_with_shutdown(); + let backend_port = backend_guard.port(); + let proxy_port = free_port(); + let config = Config::from_yaml(&custom_filter_yaml(proxy_port, backend_port, "test_metadata_writer")).unwrap(); + let registry = registry_with("test_metadata_writer", || Box::new(MetadataWriterFilter)); + let proxy = start_proxy_with_registry(&config, ®istry); + + let raw = praxis_test_utils::http_send( + proxy.addr(), + &format!("POST /echo HTTP/1.1\r\nHost: localhost\r\nContent-Length: 5\r\nConnection: close\r\n\r\nhello"), + ); + let status = praxis_test_utils::parse_status(&raw); + assert_eq!(status, 200, "metadata writer proxy should return 200"); + + let header_val = parse_header(&raw, "x-metadata-proof"); + assert_eq!( + header_val.as_deref(), + Some("body_phase_value"), + "metadata written in on_request_body must be readable in on_response" + ); +} + +#[test] +fn metadata_not_set_when_no_body_sent() { + let backend_guard = start_echo_backend_with_shutdown(); + let backend_port = backend_guard.port(); + let proxy_port = free_port(); + let config = Config::from_yaml(&custom_filter_yaml(proxy_port, backend_port, "test_metadata_writer")).unwrap(); + let registry = registry_with("test_metadata_writer", || Box::new(MetadataWriterFilter)); + let proxy = start_proxy_with_registry(&config, ®istry); + + let raw = praxis_test_utils::http_send( + proxy.addr(), + "GET /echo HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n", + ); + let status = praxis_test_utils::parse_status(&raw); + assert_eq!(status, 200, "GET without body should return 200"); + + let header_val = parse_header(&raw, "x-metadata-proof"); + assert!( + header_val.is_none(), + "metadata header must be absent when on_request_body never ran" + ); +} + +// --------------------------------------------------------------------------- +// Test Utilities +// --------------------------------------------------------------------------- + +/// Filter that writes metadata during the request body phase and promotes it to a response header. +struct MetadataWriterFilter; + +#[async_trait::async_trait] +impl HttpFilter for MetadataWriterFilter { + fn name(&self) -> &'static str { + "test_metadata_writer" + } + + async fn on_request(&self, _ctx: &mut HttpFilterContext<'_>) -> Result { + Ok(FilterAction::Continue) + } + + fn request_body_access(&self) -> BodyAccess { + BodyAccess::ReadOnly + } + + async fn on_request_body( + &self, + ctx: &mut HttpFilterContext<'_>, + body: &mut Option, + _end_of_stream: bool, + ) -> Result { + if body.as_ref().is_some_and(|b| !b.is_empty()) { + ctx.set_metadata("test.proof", "body_phase_value"); + } + Ok(FilterAction::Continue) + } + + async fn on_response(&self, ctx: &mut HttpFilterContext<'_>) -> Result { + let val = ctx.get_metadata("test.proof").map(str::to_owned); + if let Some(val) = val + && let Some(resp) = ctx.response_header.as_mut() + { + resp.headers.insert("x-metadata-proof", val.parse().unwrap()); + ctx.response_headers_modified = true; + } + Ok(FilterAction::Continue) + } +} diff --git a/tests/integration/tests/suite/main.rs b/tests/integration/tests/suite/main.rs index 86c49db548..ff51b1a14b 100644 --- a/tests/integration/tests/suite/main.rs +++ b/tests/integration/tests/suite/main.rs @@ -47,6 +47,7 @@ mod downstream_read_timeout; mod examples; mod failure_mode; mod filter_composition; +mod filter_metadata; mod guardrails; mod health_check; mod hot_reload; From fa833b95f228cef48d9b2c866a54a06d47842d0b Mon Sep 17 00:00:00 2001 From: Shane Utt Date: Mon, 1 Jun 2026 22:41:00 -0400 Subject: [PATCH 015/646] chore: cargo update Signed-off-by: Shane Utt --- Cargo.lock | 80 +++++++++++++++++++++++++++--------------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2e6b95e5c7..dccacc20ad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -355,9 +355,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.11.1" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" +checksum = "84d7ced0ae9557296835c32bf1b1e02b44c746701f898460fb000d7eaa84f00a" [[package]] name = "blake2" @@ -429,9 +429,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.62" +version = "1.2.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98" +checksum = "556e016178bb5662a08681bbe0f00f8e17631781a4dfc8c45e466e4b185ec27f" dependencies = [ "find-msvc-tools", "jobserver", @@ -1007,9 +1007,9 @@ dependencies = [ [[package]] name = "generator" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52f04ae4152da20c76fe800fa48659201d5cf627c5149ca0b707b69d7eef6cf9" +checksum = "b3b854b0e584ead1a33f18b2fcad7cf7be18b3875c78816b753639aa501513ae" dependencies = [ "cc", "cfg-if", @@ -1216,9 +1216,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "1.10.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb92f162bf56536459fc83c79b974bb12837acfed43d6bc370a7916d0ae15ecc" +checksum = "55281c53a1894c864990125767da440a4e630446785086f52523b20033b74498" dependencies = [ "atomic-waker", "bytes", @@ -1323,11 +1323,11 @@ dependencies = [ [[package]] name = "inotify" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd5b3eaf1a28b758ac0faa5a4254e8ab2705605496f1b1f3fbbc3988ad73d199" +checksum = "533e68a5842e734946fe159fb03fc9bbbb254f590dd0d8ad321ae5ff7beca2c1" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "inotify-sys", "libc", ] @@ -1404,9 +1404,9 @@ dependencies = [ [[package]] name = "kqueue" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac30106d7dce88daf4a3fcb4879ea939476d5074a9b7ddd0fb97fa4bed5596a" +checksum = "273c0752728918e0ac4976f2b275b6fefb9ecd400585dec929419f3844cd87b5" dependencies = [ "kqueue-sys", "libc", @@ -1418,7 +1418,7 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07293a4e297ac234359b510362495713f75ea345d5307140414f20c69ffeb087" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "libc", ] @@ -1459,9 +1459,9 @@ checksum = "2e126dda6f34391ab7b444f9922055facc83c07a910da3eb16f1e4d9c45dc777" [[package]] name = "libz-ng-sys" -version = "1.1.28" +version = "1.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be734b33b7bc6a42d92d23e25e69758f866cf564a88d0bf80866fcf5a52c2255" +checksum = "879917b256f6317769b9f374b435805a8697013098aacce5a38ac106cd6a9469" dependencies = [ "cmake", "libc", @@ -1484,9 +1484,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.30" +version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616ec5685824bcc94416c6d4a7a446eea774a31efd7062c8480ba6fd06d7a6e5" +checksum = "113b30b4cd05f7c06868fdb2854f66a7b9fece9a48425351cd532e810d74024f" [[package]] name = "logos" @@ -1694,9 +1694,9 @@ dependencies = [ [[package]] name = "mio" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" +checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" dependencies = [ "libc", "log", @@ -1728,7 +1728,7 @@ version = "0.31.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "cfg-if", "cfg_aliases", "libc", @@ -1756,7 +1756,7 @@ version = "8.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d3d07927151ff8575b7087f245456e549fea62edf0ec4e565a5ee50c8402bc3" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "fsevent-sys", "inotify", "kqueue", @@ -1774,7 +1774,7 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42b8cfee0e339a0337359f3c88165702ac6e600dc01c0cc9579a92d62b08477a" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", ] [[package]] @@ -2671,7 +2671,7 @@ version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9f068eba8e7071c5f9511831b44f32c740d5adf574e990f946ddb53db2f314e" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "memchr", "unicase", ] @@ -2804,7 +2804,7 @@ version = "11.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", ] [[package]] @@ -2847,7 +2847,7 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", ] [[package]] @@ -2946,7 +2946,7 @@ version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "errno", "libc", "linux-raw-sys", @@ -3060,7 +3060,7 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "core-foundation", "core-foundation-sys", "libc", @@ -3178,9 +3178,9 @@ dependencies = [ [[package]] name = "shlex" -version = "1.3.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" [[package]] name = "signal-hook-registry" @@ -3218,9 +3218,9 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "socket2" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" +checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51" dependencies = [ "libc", "windows-sys 0.61.2", @@ -3724,9 +3724,9 @@ checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" [[package]] name = "typenum" -version = "1.20.0" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" [[package]] name = "typetag" @@ -3922,7 +3922,7 @@ version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "hashbrown 0.15.5", "indexmap 2.14.0", "semver", @@ -4257,7 +4257,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" dependencies = [ "anyhow", - "bitflags 2.11.1", + "bitflags 2.12.1", "indexmap 2.14.0", "log", "serde", @@ -4373,18 +4373,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.49" +version = "0.8.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bce33a6288fa3f072a8c2c7d0f2fdbb90e28298f0135c1f99b96c3db2efcc60b" +checksum = "3b065d4f0e55f82fae73202e189638116a87c55ab6b8e6c2721e13dd9d854ad1" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.49" +version = "0.8.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd425244944f4ab65ccff928e7323354c5a018c75838362fdce749dfad2ee1e" +checksum = "0b631b19d36a892ab55420c92dbc83ccd79274f25be714855d3074aa71cab639" dependencies = [ "proc-macro2", "quote", From 49325e34efa473def98a01c326d1716b5bc1b2e7 Mon Sep 17 00:00:00 2001 From: Francisco Javier Arceo Date: Tue, 2 Jun 2026 14:15:02 -0400 Subject: [PATCH 016/646] proposal: Anthropic Messages API filters (What + Why) (#420) --- .../xxxxx_anthropic-messages-api-filters.md | 346 ++++++++++++++++++ 1 file changed, 346 insertions(+) create mode 100644 docs/proposals/xxxxx_anthropic-messages-api-filters.md diff --git a/docs/proposals/xxxxx_anthropic-messages-api-filters.md b/docs/proposals/xxxxx_anthropic-messages-api-filters.md new file mode 100644 index 0000000000..c965507764 --- /dev/null +++ b/docs/proposals/xxxxx_anthropic-messages-api-filters.md @@ -0,0 +1,346 @@ +--- +issue: # to be created; rename file to match issue number +discussion: https://github.com/praxis-proxy/praxis/pull/420 +status: proposed +authors: + - franciscojavierarceo +stakeholders: + - leseb + - shaneutt + - nerdalert +--- + +# Anthropic Messages API Filters + +## What? + +Add Anthropic Messages API support to Praxis as +composable filters, mirroring the pattern established +by the `OpenAI` Responses API filters in #354. This +enables Praxis to classify, route, and transform +requests between the `Anthropic` Messages API +(`/v1/messages`) and `OpenAI` Chat Completions +(`/v1/chat/completions`). + +The `OpenAI` Responses API (`/v1/responses`) is a +fundamentally different protocol with stateful +semantics and is out of scope for format +transformation. Responses API support is covered +separately. + +The scope covers five capabilities: + +1. **Classification and routing**: detect `Anthropic` + Messages API requests by body structure and + promote routing facts to headers for downstream + filter chains and cluster selection. The + classifier extends the shared `AiRequestFormat` + enum (at `ai/classifier/`) with an + `AnthropicMessages` variant, keeping a single + classifier for all formats. It must distinguish + `Anthropic` Messages from `OpenAI` Chat + Completions even though both use a `messages` + field, using discriminating signals: top-level + `system` parameter, required `max_tokens`, + `anthropic-version` header, and typed content + blocks. Mid-conversation system messages + (`"role": "system"` inside the messages array) + are supported on newer `Anthropic` models per + the [mid-conversation system messages docs]. + The `anthropic-version` header is the strongest + signal. The promoted header name is + `x-praxis-ai-format` (matching the existing + `responses_format` filter convention). + + [mid-conversation system messages docs]: https://platform.claude.com/docs/en/build-with-claude/mid-conversation-system-messages + +2. **Request validation**: validate proxy-needed + fields before forwarding, following the same + principle as #354's `request_validate`. Checks + that `messages` is non-empty, `max_tokens` is + present and > 0, and `model` is non-empty. + Message role ordering (e.g. first message must + be `role: user`) is deferred to the backend, + consistent with the principle of validating + only what the proxy needs for its own operation. + Unlike the Responses API, `Anthropic` Messages + does not require persistence or stateful + orchestration, so the validation filter is + lighter: no shared state struct, no store + initialization. Let the backend handle parameter + ranges, model availability, and inference-specific + validation. + +3. **Format transformation**: bidirectional conversion + between `Anthropic` Messages and `OpenAI` Chat + Completions so that clients speaking one dialect + can reach backends speaking the other. This is + validated by existing production implementations + in OGX (the open-source agentic API server) which + performs the same translation in Python. The known + mapping rules are: + + **Request (`Anthropic` to `OpenAI`):** + - `system` (top-level string or text block array) + to prepended `OpenAI` message with + `role: "system"` + - Content blocks flattened: + - `type: "text"` to string content + - `type: "tool_use"` to `OpenAI` `tool_calls` + with `function.arguments = JSON-serialized + input` + - `type: "tool_result"` to separate `OpenAI` + message with `role: "tool"` (images in tool + results promoted to follow-up user messages + since `OpenAI` tool messages are text-only) + - `max_tokens` to `max_tokens` (direct mapping) + - `stop_sequences` to `stop` + - `tool_choice`: `"any"` to `"required"`, + `"none"` to `"none"`, default to `"auto"`, + `{"type": "tool", "name": "X"}` to + `{"type": "function", "function": {"name": "X"}}` + - Tool definitions: custom tools convert + (`input_schema` to `parameters`); server-side + tools (web_search, bash, text_editor) are + dropped with a log warning + - `top_k`: no standard `OpenAI` equivalent, + passed as extra body parameter for backends + that support it (e.g. vLLM) + - `temperature`, `top_p`, `top_k`: not supported + on newer `Anthropic` models (returns 400); + transformation must strip these when targeting + those models + - `thinking` blocks: dropped (no `OpenAI` + equivalent) + - Image blocks: `Anthropic` uses `type: "image"` + with `source.type: "base64"|"url"|"file"`; + `OpenAI` uses `type: "image_url"` with + `image_url.url`. For `source.type: "base64"` + and `"url"`, structural mapping is applied. + For `source.type: "file"`, the file reference + must be resolved to a data URL before + transformation (deferred to the How section) + + **Response (`OpenAI` to `Anthropic`):** + - `message.content` string to content block + with `type: "text"` + - `tool_calls` to content block per call with + `type: "tool_use"` and `input = JSON-parsed + arguments` + - Finish reason mapping: + `"stop"` to `"end_turn"`, + `"tool_calls"` to `"tool_use"`, + `"length"` to `"max_tokens"`, + `"content_filter"` to `"end_turn"` (note: + this is a lossy mapping; the original + `finish_reason` is preserved in filter + metadata as `openai.finish_reason` so + downstream filters can distinguish + safety-filtered responses from natural + completions) + - Usage: `prompt_tokens` to `input_tokens`, + `completion_tokens` to `output_tokens`, + `cached_tokens` to `cache_read_input_tokens` + - Response ID generated as `msg_{uuid}` + +4. **Streaming SSE transformation**: a separate + filter (following the `stream_events` pattern in + #354) that transforms streaming responses between + `Anthropic` and `OpenAI` SSE formats. Decoupled + from request body transformation so operators can + use SSE event handling independently (e.g. for + logging or guardrails on passthrough streams). + + **Event mapping (`OpenAI` chunks to `Anthropic` SSE):** + 1. Emit `MessageStartEvent` with empty content + 2. Per text delta: `ContentBlockStartEvent` + + `ContentBlockDeltaEvent(text_delta)` + 3. Per tool call delta: + `ContentBlockStartEvent` with empty + `ToolUseBlock`, then + `ContentBlockDeltaEvent(input_json_delta)` + 4. `ContentBlockStopEvent` to close each block + 5. `MessageDeltaEvent` with final `stop_reason` + and usage + 6. `MessageStopEvent` + +5. **`Anthropic`-native features**: proxy and preserve + `Anthropic`-specific capabilities that have no + `OpenAI` equivalent when routing to `Anthropic` + backends in pass-through mode: + - Prompt caching (`cache_control` blocks with + `ephemeral` type; 5-minute TTL is standard, + 1-hour TTL requires the `extended-cache-ttl` + beta header) + - Extended thinking (`thinking` parameter with + `budget_tokens`) + - Citations in responses + - `Anthropic` SSE streaming event protocol + - `anthropic-version` header preservation + - Rate-limit headers (`x-ratelimit-limit-tokens`, + etc.) + +Each capability is a separate filter implementing +`HttpFilter`, composable in YAML pipelines. Operators +deploy only what they need. + +### Goals + +- Validate proxy-needed fields in `Anthropic` + Messages requests (`messages` non-empty, + `max_tokens` > 0, `model` present) and reject + malformed requests with consistent error responses + before they reach the backend. +- Classify `Anthropic` Messages API requests and + promote `x-praxis-ai-format: anthropic_messages` + to headers for routing, extending the existing + `AiRequestFormat` enum alongside `responses` and + `chat_completions`. +- Transform requests bidirectionally between + `Anthropic` Messages and `OpenAI` Chat Completions + using the mapping rules documented above, + validated against OGX's production implementation. +- Transform streaming responses between `Anthropic` + SSE events (`message_start`, `content_block_start`, + `content_block_delta`, `content_block_stop`, + `message_delta`, `message_stop`) and `OpenAI` SSE + chunks (`chat.completion.chunk`). +- Gracefully degrade when transforming `Anthropic` + requests for `OpenAI` backends: drop unsupported + features (thinking, server-side tools, + `cache_control`) with structured log warnings + rather than rejecting the request. +- Preserve `Anthropic`-specific headers and request + features end-to-end when routing to backends + that natively support `/v1/messages` (e.g. vLLM, + `Anthropic` API). +- Provide a pass-through fast path for backends + that natively support `/v1/messages` with + sub-millisecond proxy overhead. +- Support credential injection for `Anthropic` + backends using the existing `credential_injection` + filter (inject `x-api-key` and + `anthropic-version` headers per cluster). +- Enable unified gateway configurations where a + single Praxis instance routes to vLLM (`OpenAI`), + llm-d (`OpenAI` via vLLM), KServe/MaaS backends, + and `Anthropic` API simultaneously, with automatic + format detection and transformation. + +## Why? + +### Motivation + +Production AI platforms increasingly need to support +multiple inference backends and API formats +simultaneously. The `Anthropic` Messages API is a +first-class inference protocol alongside `OpenAI`'s +Chat Completions and Responses APIs, with +significant adoption in enterprise deployments. + +Today, Praxis classifies requests as either +`responses` (`OpenAI` Responses API) or +`chat_completions` (`OpenAI` Chat Completions) in the +`AiRequestFormat` enum. `Anthropic` Messages requests +arrive with `messages` (like Chat Completions) but +are structurally different: `system` is a top-level +parameter, `max_tokens` is required, content uses +typed blocks (`text`, `image`, `tool_use`, +`tool_result`), and streaming uses a distinct SSE +event protocol. The current classifier would +misidentify these as `chat_completions`, leading to +incorrect routing or transformation failures. + +The format transformation filters are needed because +real deployments mix backends: + +- **vLLM and llm-d** expose `OpenAI`-compatible + endpoints (`/v1/chat/completions`) and also + support `/v1/messages` natively, but not all + deployments enable `Anthropic` compatibility. + vLLM's `/v1/messages` endpoint supports core + `Anthropic` features (system, tools, tool_choice, + thinking blocks, streaming SSE) but does not + support `cache_control` or `budget_tokens` (these + are accepted but ignored). llm-d is a + Kubernetes-native orchestration layer that + routes to vLLM workers using the Gateway API + Inference Extension with prefix-cache-aware + scheduling and prefill/decode disaggregation. +- **KServe and MaaS** (Models as a Service) provide + model discovery and API key management. MaaS + returns model URLs that clients call directly; + the model endpoints may implement either format. + MaaS uses `OpenAI`-compatible API keys + (`sk-oai-*`) and `/v1/models` for discovery. +- **`Anthropic` API** is the canonical backend for + Claude models and uses a distinct wire format + with features that have no `OpenAI` equivalent: + prompt caching with `cache_control` blocks + (5-minute TTL standard; 1-hour TTL requires the + `extended-cache-ttl` beta header), extended + thinking with `budget_tokens`, typed content + blocks, and a block-based SSE streaming protocol. + `Anthropic` also provides an `OpenAI` + compatibility endpoint at `/v1/chat/completions`, + but it lacks prompt caching, extended thinking + details, and strict tool use, making native + `/v1/messages` routing necessary for full feature + access. + +The bidirectional format transformation is a +validated pattern. OGX (the open-source agentic API +server) implements the same `Anthropic` to `OpenAI` +mapping in production, with a native-passthrough +fast path when backends support `/v1/messages` +directly. The mapping rules documented in this +proposal are derived from that implementation and +cover the known edge cases: tool result image +promotion, server-side tool filtering, thinking +block handling, and streaming event sequencing. + +Without format transformation, operators must either +standardize all clients on one format (impractical) +or run separate gateway instances per format +(operationally expensive). Praxis should handle this +at the filter pipeline level. + +`Anthropic`-native features (prompt caching, extended +thinking) represent capabilities that cannot be +expressed in `OpenAI` format. When routing to +`Anthropic` backends, these must be preserved +end-to-end. When routing `Anthropic` requests to +`OpenAI`-compatible backends, the filters must +gracefully degrade: strip unsupported fields, map +what can be mapped, and log what was dropped. + +### User Stories + +- As a platform engineer, I want to route + `/v1/messages` requests to vLLM backends that + only support `/v1/chat/completions` so that + clients using the `Anthropic` SDK can reach any + backend in my fleet. +- As an AI gateway operator, I want a single Praxis + instance to serve clients speaking `OpenAI` Chat + Completions and `Anthropic` Messages formats, + routing each to the appropriate backend with + automatic format detection. +- As a developer, I want to send `Anthropic`-format + requests with prompt caching to a Claude backend + through Praxis without losing the `cache_control` + blocks or `anthropic-version` header. +- As an SRE, I want to use Praxis credential + injection to manage `x-api-key` headers for + `Anthropic` backends the same way I manage + `Authorization: Bearer` headers for `OpenAI` + backends. +- As a security engineer, I want `Anthropic`-specific + rate-limit headers (`x-ratelimit-limit-tokens`, + etc.) to be forwarded to clients so that + client-side backoff works correctly. +- As a platform engineer using MaaS for model + discovery, I want Praxis to detect whether a + discovered model endpoint speaks `Anthropic` or + `OpenAI` format and apply the appropriate + transformation filters automatically. From 874939e7ef861c56669784f2948512cbcf55aff1 Mon Sep 17 00:00:00 2001 From: Yehudit Kerido Date: Thu, 28 May 2026 12:27:03 +0300 Subject: [PATCH 017/646] proposal: add proposal for provider token usage mapping Signed-off-by: Yehudit Kerido --- .../proposals/00216_provider-token-mapping.md | 118 ++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 docs/proposals/00216_provider-token-mapping.md diff --git a/docs/proposals/00216_provider-token-mapping.md b/docs/proposals/00216_provider-token-mapping.md new file mode 100644 index 0000000000..004499945c --- /dev/null +++ b/docs/proposals/00216_provider-token-mapping.md @@ -0,0 +1,118 @@ +--- +issue: https://github.com/praxis-proxy/praxis/issues/216 +discussion: https://github.com/praxis-proxy/praxis/issues/216#issuecomment-4563373566 +status: proposed +authors: + - yehuditkerido +stakeholders: + - shaneutt + - twhgu +--- + +# Provider-Specific Token Usage Mapping + +## What? + +An internal module to extract token usage from AI provider responses +and convert them to a unified format. + +Each provider returns token counts in different JSON structures: + +| Provider | Field Path | +|-----------|------------| +| OpenAI | `usage.prompt_tokens`, `usage.completion_tokens` | +| Anthropic | `usage.input_tokens`, `usage.output_tokens` | +| Google | `usageMetadata.promptTokenCount`, `usageMetadata.candidatesTokenCount` | +| Bedrock (InvokeModel) | `inputTokenCount`, `outputTokenCount` (root level) | +| Bedrock (Converse) | `usage.inputTokens`, `usage.outputTokens` | +| Azure | Same as OpenAI | + +This proposal adds a mapping library that: + +1. Takes a provider identifier and response body +2. Parses the provider-specific JSON structure +3. Returns a unified `TokenUsage` struct + +```rust +pub struct TokenUsage { /* fields private */ } + +impl TokenUsage { + pub fn input_tokens(&self) -> u64; + pub fn output_tokens(&self) -> u64; + pub fn total_tokens(&self) -> u64; // from response, or computed: input + output +} + +pub enum Provider { + OpenAi, + Anthropic, + Google, + Bedrock, + Azure, +} + +/// Extracts token usage from a provider's JSON response body. +/// Returns `None` if usage data is missing or malformed. +pub fn extract_token_usage(provider: Provider, body: &[u8]) -> Option; +``` + +### Goals + +- Extract token usage from 5 AI provider response formats +- Provide a unified `TokenUsage` representation +- Enable reuse by other filters ([#210], [#212]) and systems + +### Non-Goals + +- Rate limiting logic (separate issue) +- Streaming-specific logic: SSE parsing, chunk identification ([#211]) +- Exposing tokens in headers or metrics ([#214]) + +**Note on streaming:** This module parses JSON containing `usage` data, +regardless of whether it came from a non-streaming response or the +final chunk of a streaming response. The JSON structure is the same +in both cases. Streaming-specific handling (SSE format, identifying +which chunk has usage) is #211's scope. + +## Why? + +### Motivation + +Other filters and systems need token counts in a consistent +format. Without this library, each consumer would need to +implement provider-specific parsing separately. + +This is foundational work for the Token Counting epic ([#20]) +that enables: +- Token-based rate limiting +- Usage logging and metrics +- Cost tracking + +### User Stories + +- As a **rate limiting filter**, I need consistent token counts + regardless of which AI provider was used, so that I can enforce + limits without provider-specific code. + +- As the **token counting filter ([#210])**, I need a mapping + from each provider's field names to a unified format, so that I + can parse any provider's response. + +- As a **logging/metrics system**, I need token data in a + predictable structure, so that I can track usage across all + providers consistently. + +## Open Question + +This proposal focuses on extracting token usage only. Should +we consider a broader "provider response translator" that +normalizes the entire response to a common format (e.g., OpenAI)? + +If there are future requirements that would benefit from full +response translation, it may be worth designing the library +with that in mind. + +[#20]: https://github.com/praxis-proxy/praxis/issues/20 +[#210]: https://github.com/praxis-proxy/praxis/issues/210 +[#211]: https://github.com/praxis-proxy/praxis/issues/211 +[#212]: https://github.com/praxis-proxy/praxis/issues/212 +[#214]: https://github.com/praxis-proxy/praxis/issues/214 From b81a6478dc44826bc7eff751b9f585fd0446f109 Mon Sep 17 00:00:00 2001 From: Brent Salisbury Date: Tue, 2 Jun 2026 21:54:18 -0400 Subject: [PATCH 018/646] feat(mcp): add protocol profile and version plumbing (#465) Adds minimal MCP protocol profile/version plumbing for the existing static broker without changing current runtime behavior. Signed-off-by: Brent Salisbury --- docs/operating/filter-reference.md | 40 +++ .../mcp-static-catalog.yaml | 3 + .../http/ai/agentic/mcp/broker/config.rs | 51 ++++ .../http/ai/agentic/mcp/broker/mod.rs | 69 ++++- .../http/ai/agentic/mcp/broker/tests.rs | 287 +++++++++++++++++- .../src/builtins/http/ai/agentic/mcp/mod.rs | 1 + .../builtins/http/ai/agentic/mcp/protocol.rs | 126 ++++++++ 7 files changed, 566 insertions(+), 11 deletions(-) create mode 100644 filter/src/builtins/http/ai/agentic/mcp/protocol.rs diff --git a/docs/operating/filter-reference.md b/docs/operating/filter-reference.md index 642c267c87..9975979acd 100644 --- a/docs/operating/filter-reference.md +++ b/docs/operating/filter-reference.md @@ -394,6 +394,46 @@ a JSON-RPC error if the selector is missing and and `json_rpc.*` entries to the filter result set for branch chain conditions. +### MCP Broker Mode + +When the `mcp` filter config includes a `servers` +block, broker mode activates. The broker aggregates +tool catalogs from configured backends and handles +`initialize`, `tools/list`, `ping`, and notifications +directly as synthetic responses. + +```yaml +- filter: mcp + path: /mcp + max_body_bytes: 65536 + protocol_profile: current + default_version: "2025-03-26" + supported_versions: ["2025-03-26"] + servers: + - name: weather + cluster: weather-mcp + path: /mcp + tool_prefix: "weather_" + tools: + - name: get_weather + description: Get current weather +``` + +| Field | Type | Default | Description | +| ----- | ---- | ------- | ----------- | +| `path` | string | `"/mcp"` | Public endpoint path | +| `max_body_bytes` | integer | 65536 | Maximum body size to buffer (64 KiB) | +| `protocol_profile` | string | `"current"` | Protocol profile governing session semantics | +| `default_version` | string | `"2025-03-26"` | Protocol version used in `initialize` responses when the client's requested version is not supported | +| `supported_versions` | list | `["2025-03-26"]` | Protocol versions accepted during `initialize` negotiation; every entry must be implemented by this build | +| `invalid_tool_policy` | string | `"reject_server"` | `"reject_server"` or `"filter_out"` for tools with invalid schemas | +| `servers` | list | `[]` | Backend MCP server definitions | + +Each server entry supports `name`, `cluster`, `path` +(default `"/mcp"`), `tool_prefix`, and `tools`. Tool +definitions include `name`, optional `description`, +optional `inputSchema`, and optional `annotations`. + ## Static Response Returns a fixed response without contacting any upstream. diff --git a/examples/configs/payload-processing/mcp-static-catalog.yaml b/examples/configs/payload-processing/mcp-static-catalog.yaml index ba6087290e..930ea15a69 100644 --- a/examples/configs/payload-processing/mcp-static-catalog.yaml +++ b/examples/configs/payload-processing/mcp-static-catalog.yaml @@ -19,6 +19,9 @@ filter_chains: - filter: mcp path: /mcp max_body_bytes: 65536 + protocol_profile: current + default_version: "2025-03-26" + supported_versions: ["2025-03-26"] servers: - name: weather cluster: weather-mcp diff --git a/filter/src/builtins/http/ai/agentic/mcp/broker/config.rs b/filter/src/builtins/http/ai/agentic/mcp/broker/config.rs index 5299c5e9f9..e7760f404c 100644 --- a/filter/src/builtins/http/ai/agentic/mcp/broker/config.rs +++ b/filter/src/builtins/http/ai/agentic/mcp/broker/config.rs @@ -5,6 +5,7 @@ use serde::Deserialize; +use super::super::protocol::{self, ProtocolProfile}; use crate::{FilterError, builtins::http::transformation::has_dot_dot_traversal}; // ----------------------------------------------------------------------------- @@ -79,6 +80,12 @@ pub(super) struct McpServerConfig { #[derive(Debug, Deserialize)] #[serde(deny_unknown_fields)] pub(super) struct McpBrokerConfig { + /// Fallback MCP protocol version returned in broker `initialize` + /// responses when the client's requested version is not supported. + /// Must be present in `supported_versions` and implemented by this + /// build. Defaults to [`protocol::DEFAULT_VERSION`]. + #[serde(default = "default_version")] + pub default_version: String, /// Behavior when a tool has an invalid schema. #[serde(default)] pub invalid_tool_policy: InvalidToolPolicy, @@ -88,9 +95,19 @@ pub(super) struct McpBrokerConfig { /// Public MCP path handled by Praxis. #[serde(default = "default_path")] pub path: String, + /// Protocol profile governing session semantics and header + /// requirements for this broker instance. + #[serde(default)] + pub protocol_profile: ProtocolProfile, /// Backend server definitions. #[serde(default)] pub servers: Vec, + /// Protocol versions accepted during `initialize` negotiation. + /// Every entry must be implemented by this build (present in + /// [`protocol::SUPPORTED_VERSIONS`]). Defaults to the versions + /// this build implements. + #[serde(default = "default_supported_versions")] + pub supported_versions: Vec, } // ----------------------------------------------------------------------------- @@ -133,6 +150,16 @@ fn default_max_body_bytes() -> usize { DEFAULT_MAX_BODY_BYTES } +/// Default protocol version from the centralized constant. +fn default_version() -> String { + protocol::DEFAULT_VERSION.to_owned() +} + +/// Default supported versions from the centralized constant. +fn default_supported_versions() -> Vec { + protocol::SUPPORTED_VERSIONS.iter().map(|s| (*s).to_owned()).collect() +} + // ----------------------------------------------------------------------------- // Validation // ----------------------------------------------------------------------------- @@ -143,6 +170,7 @@ pub(super) fn build_config(cfg: McpBrokerConfig) -> Result<(McpBrokerConfig, Vec return Err("mcp: max_body_bytes must be greater than 0".into()); } + validate_versions(&cfg)?; validate_path("mcp", &cfg.path)?; validate_unique_server_names(&cfg.servers)?; validate_server_clusters(&cfg.servers)?; @@ -155,6 +183,29 @@ pub(super) fn build_config(cfg: McpBrokerConfig) -> Result<(McpBrokerConfig, Vec Ok((cfg, catalog)) } +/// Validate that every configured version is implemented by this build +/// and that `default_version` appears in `supported_versions`. +fn validate_versions(cfg: &McpBrokerConfig) -> Result<(), FilterError> { + if cfg.supported_versions.is_empty() { + return Err("mcp: supported_versions must not be empty".into()); + } + for v in &cfg.supported_versions { + if !protocol::is_supported_version(v) { + return Err( + format!("mcp: supported_versions contains '{v}' which is not implemented by this build").into(), + ); + } + } + if !cfg.supported_versions.iter().any(|v| v == &cfg.default_version) { + return Err(format!( + "mcp: default_version '{}' must appear in supported_versions", + cfg.default_version, + ) + .into()); + } + Ok(()) +} + /// Validate that all server names are unique and non-empty. fn validate_unique_server_names(servers: &[McpServerConfig]) -> Result<(), FilterError> { let mut seen = std::collections::HashSet::new(); diff --git a/filter/src/builtins/http/ai/agentic/mcp/broker/mod.rs b/filter/src/builtins/http/ai/agentic/mcp/broker/mod.rs index 396a4c9c6f..1f5e326f38 100644 --- a/filter/src/builtins/http/ai/agentic/mcp/broker/mod.rs +++ b/filter/src/builtins/http/ai/agentic/mcp/broker/mod.rs @@ -25,6 +25,7 @@ use rand::{TryRngCore, rngs::OsRng}; use tracing::{debug, trace}; use self::config::{CatalogTool, McpBrokerConfig, build_config}; +use super::protocol; use crate::{ FilterAction, FilterError, Rejection, body::{BodyAccess, BodyMode}, @@ -43,9 +44,6 @@ use crate::{ // Constants // ----------------------------------------------------------------------------- -/// MCP protocol version currently supported by Praxis. -const SUPPORTED_PROTOCOL_VERSION: &str = "2025-03-26"; - /// Server name reported in MCP initialize responses. const SERVER_NAME: &str = "praxis"; @@ -86,12 +84,19 @@ const SERVER_NAME: &str = "praxis"; pub(crate) struct McpBrokerFilter { /// Static tool catalog built from config. catalog: Vec, + /// Protocol version the broker uses in `initialize` responses. + default_version: String, /// Shared JSON-RPC parser configuration. json_rpc_config: JsonRpcConfig, /// Maximum body bytes for `StreamBuffer`. max_body_bytes: usize, + /// Configured protocol profile (stored for future profile-aware dispatch). + #[allow(dead_code, reason = "plumbing for follow-up profile-aware behavior")] + protocol_profile: protocol::ProtocolProfile, /// Public path this MCP broker handles (e.g. `/mcp`). public_path: String, + /// Implemented versions used for protocol version negotiation. + supported_versions: Vec, } impl McpBrokerFilter { @@ -114,9 +119,12 @@ impl McpBrokerFilter { Ok(Box::new(Self { catalog, + default_version: validated.default_version.clone(), json_rpc_config, max_body_bytes: validated.max_body_bytes, + protocol_profile: validated.protocol_profile, public_path: validated.path.clone(), + supported_versions: validated.supported_versions.clone(), })) } } @@ -149,6 +157,7 @@ impl HttpFilter for McpBrokerFilter { } } + #[allow(clippy::too_many_lines, reason = "sequential parse-extract-dispatch pipeline")] async fn on_request_body( &self, ctx: &mut HttpFilterContext<'_>, @@ -188,7 +197,15 @@ impl HttpFilter for McpBrokerFilter { ctx.set_metadata("mcp.method", method_str.clone()); } - dispatch_method(ctx, &self.catalog, &value, &envelope, method_str) + dispatch_method( + ctx, + &self.catalog, + &value, + &envelope, + method_str, + &self.supported_versions, + &self.default_version, + ) } } @@ -199,12 +216,18 @@ impl HttpFilter for McpBrokerFilter { /// Maps a JSON-RPC method to the MCP handler that owns it. /// Never returns [`FilterAction::Release`] — all paths produce /// a terminal synthetic response. +#[allow( + clippy::too_many_arguments, + reason = "project threshold is 5; version plumbing adds two" +)] fn dispatch_method( ctx: &mut HttpFilterContext<'_>, catalog: &[CatalogTool], value: &serde_json::Value, envelope: &JsonRpcEnvelope, method_str: &str, + supported_versions: &[String], + default_version: &str, ) -> Result { if method_str.starts_with("notifications/") { return Ok(handle_notification(envelope)); @@ -215,7 +238,7 @@ fn dispatch_method( } let action = match method_str { - "initialize" => handle_initialize(ctx, value, envelope)?, + "initialize" => handle_initialize(ctx, value, envelope, supported_versions, default_version)?, "tools/list" => handle_tools_list(catalog, envelope)?, "tools/call" => json_rpc_error_action(envelope, -32601, "method not yet supported"), "ping" => handle_ping(envelope), @@ -278,8 +301,11 @@ fn handle_initialize( ctx: &mut HttpFilterContext<'_>, value: &serde_json::Value, envelope: &JsonRpcEnvelope, + supported_versions: &[String], + default_version: &str, ) -> Result { record_client_protocol_version(ctx, value); + let response_version = negotiate_protocol_version(value, supported_versions, default_version); let session_id = generate_session_id()?; debug!(session_id_len = session_id.len(), "MCP initialize"); @@ -289,10 +315,35 @@ fn handle_initialize( Rejection::status(200) .with_header("content-type", "application/json") .with_header("mcp-session-id", &session_id) - .with_body(Bytes::from(initialize_response_body(envelope).to_string())), + .with_body(Bytes::from( + initialize_response_body(envelope, response_version).to_string(), + )), )) } +/// Select the protocol version for the initialize response. +/// +/// Echoes the client's requested version when the broker supports it, +/// otherwise falls back to `default_version`. +fn negotiate_protocol_version<'a>( + value: &serde_json::Value, + supported_versions: &'a [String], + default_version: &'a str, +) -> &'a str { + let requested = value + .get("params") + .and_then(|p| p.get("protocolVersion")) + .and_then(|v| v.as_str()); + + if let Some(req) = requested + && let Some(matched) = supported_versions.iter().find(|v| v.as_str() == req) + { + return matched.as_str(); + } + + default_version +} + /// Persist the client's advertised MCP protocol version for later negotiation /// work, avoiding metadata writes for malformed control-character values. fn record_client_protocol_version(ctx: &mut HttpFilterContext<'_>, value: &serde_json::Value) { @@ -306,13 +357,13 @@ fn record_client_protocol_version(ctx: &mut HttpFilterContext<'_>, value: &serde } } -/// Build the initialize response from dynamic crate and protocol constants. -fn initialize_response_body(envelope: &JsonRpcEnvelope) -> serde_json::Value { +/// Build the initialize response from the configured protocol version. +fn initialize_response_body(envelope: &JsonRpcEnvelope, protocol_version: &str) -> serde_json::Value { serde_json::json!({ "jsonrpc": "2.0", "id": id_value(envelope), "result": { - "protocolVersion": SUPPORTED_PROTOCOL_VERSION, + "protocolVersion": protocol_version, "capabilities": { "tools": { "listChanged": false, diff --git a/filter/src/builtins/http/ai/agentic/mcp/broker/tests.rs b/filter/src/builtins/http/ai/agentic/mcp/broker/tests.rs index 6eaf18cc2e..ccd0e9dcfc 100644 --- a/filter/src/builtins/http/ai/agentic/mcp/broker/tests.rs +++ b/filter/src/builtins/http/ai/agentic/mcp/broker/tests.rs @@ -1138,11 +1138,280 @@ async fn delete_with_query_param_matches_configured_mcp_path() { } // ----------------------------------------------------------------------------- -// Test Utilities +// Protocol Profile Config Tests // ----------------------------------------------------------------------------- -fn make_broker_filter() -> McpBrokerFilter { +#[test] +fn default_profile_config_preserves_current_behavior() { + let filter = make_broker_filter(); + assert_eq!( + filter.protocol_profile, + protocol::ProtocolProfile::Current, + "default profile should be Current" + ); + assert_eq!( + filter.default_version, + protocol::PROTOCOL_VERSION_CURRENT, + "default version should match centralized constant" + ); + assert!( + !filter.supported_versions.is_empty(), + "supported versions should not be empty" + ); + assert!( + filter.supported_versions.contains(&filter.default_version), + "default version should appear in supported versions" + ); +} + +#[test] +fn explicit_current_profile_parses() { + let yaml = r#" +protocol_profile: current +servers: + - name: s + cluster: c + tools: [] +"#; + let cfg: McpBrokerConfig = serde_yaml::from_str(yaml).unwrap(); + let (validated, _catalog) = build_config(cfg).unwrap(); + assert_eq!( + validated.protocol_profile, + protocol::ProtocolProfile::Current, + "explicit 'current' should parse" + ); +} + +#[test] +fn unsupported_profile_rejects_at_config_load() { let yaml = r#" +protocol_profile: nonexistent +servers: + - name: s + cluster: c + tools: [] +"#; + let result = serde_yaml::from_str::(yaml); + assert!(result.is_err(), "unknown protocol_profile should reject at parse time"); +} + +#[test] +fn explicit_supported_versions_parses() { + let yaml = r#" +supported_versions: ["2025-03-26"] +default_version: "2025-03-26" +servers: + - name: s + cluster: c + tools: [] +"#; + let cfg: McpBrokerConfig = serde_yaml::from_str(yaml).unwrap(); + let (validated, _catalog) = build_config(cfg).unwrap(); + assert_eq!( + validated.supported_versions, + vec!["2025-03-26"], + "explicit supported_versions should parse" + ); + assert_eq!( + validated.default_version, "2025-03-26", + "explicit default_version should parse" + ); +} + +#[test] +fn default_version_not_in_supported_versions_rejected() { + let yaml = r#" +supported_versions: ["2025-03-26"] +default_version: "9999-12-31" +servers: [] +"#; + let cfg: McpBrokerConfig = serde_yaml::from_str(yaml).unwrap(); + let result = build_config(cfg); + assert!(result.is_err(), "default_version not in supported_versions should fail"); + assert!( + result + .err() + .unwrap() + .to_string() + .contains("must appear in supported_versions"), + "error should mention supported_versions" + ); +} + +#[test] +fn empty_supported_versions_rejected() { + let yaml = r#" +supported_versions: [] +servers: [] +"#; + let cfg: McpBrokerConfig = serde_yaml::from_str(yaml).unwrap(); + let result = build_config(cfg); + assert!(result.is_err(), "empty supported_versions should fail"); + assert!( + result.err().unwrap().to_string().contains("must not be empty"), + "error should mention empty supported_versions" + ); +} + +#[test] +fn unsupported_supported_version_rejected() { + let yaml = r#" +supported_versions: ["9999-12-31"] +default_version: "9999-12-31" +servers: [] +"#; + let cfg: McpBrokerConfig = serde_yaml::from_str(yaml).unwrap(); + let result = build_config(cfg); + assert!(result.is_err(), "version not implemented by this build should fail"); + assert!( + result + .err() + .unwrap() + .to_string() + .contains("not implemented by this build"), + "error should mention build implementation" + ); +} + +#[test] +fn unsupported_default_version_rejected_even_when_listed() { + let yaml = r#" +supported_versions: ["2025-03-26", "9999-12-31"] +default_version: "9999-12-31" +servers: [] +"#; + let cfg: McpBrokerConfig = serde_yaml::from_str(yaml).unwrap(); + let result = build_config(cfg); + assert!( + result.is_err(), + "unimplemented version in supported_versions should fail even if default_version matches" + ); +} + +#[tokio::test] +async fn explicit_current_version_preserves_initialize_response() { + let filter = make_broker_filter_with_versions("2025-03-26"); + let body_str = + r#"{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{}}}"#; + let req = make_mcp_request(); + let mut ctx = crate::test_utils::make_filter_context(&req); + let mut body = Some(Bytes::from(body_str)); + + let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); + + match action { + FilterAction::Reject(ref rejection) => { + assert_eq!(rejection.status, 200, "initialize should return 200"); + let body_str = std::str::from_utf8(rejection.body.as_ref().unwrap()).unwrap(); + let parsed: serde_json::Value = serde_json::from_str(body_str).unwrap(); + assert_eq!( + parsed["result"]["protocolVersion"], "2025-03-26", + "explicit default_version should appear in initialize response" + ); + assert!( + rejection.headers.iter().any(|(k, _)| k == "mcp-session-id"), + "initialize should still return mcp-session-id" + ); + }, + _ => panic!("expected Reject with 200"), + } +} + +// ----------------------------------------------------------------------------- +// Version Negotiation Tests +// ----------------------------------------------------------------------------- + +#[tokio::test] +async fn initialize_echoes_supported_requested_version() { + let filter = make_broker_filter_with_versions("2025-03-26"); + let body_str = + r#"{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{}}}"#; + let req = make_mcp_request(); + let mut ctx = crate::test_utils::make_filter_context(&req); + let mut body = Some(Bytes::from(body_str)); + + let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); + + match action { + FilterAction::Reject(ref rejection) => { + let body_str = std::str::from_utf8(rejection.body.as_ref().unwrap()).unwrap(); + let parsed: serde_json::Value = serde_json::from_str(body_str).unwrap(); + assert_eq!( + parsed["result"]["protocolVersion"], "2025-03-26", + "should echo the client's requested version when it is supported" + ); + }, + _ => panic!("expected Reject with 200"), + } +} + +#[tokio::test] +async fn initialize_unsupported_requested_version_falls_back_to_default() { + let filter = make_broker_filter_with_versions("2025-03-26"); + let body_str = + r#"{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"9999-12-31","capabilities":{}}}"#; + let req = make_mcp_request(); + let mut ctx = crate::test_utils::make_filter_context(&req); + let mut body = Some(Bytes::from(body_str)); + + let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); + + match action { + FilterAction::Reject(ref rejection) => { + let body_str = std::str::from_utf8(rejection.body.as_ref().unwrap()).unwrap(); + let parsed: serde_json::Value = serde_json::from_str(body_str).unwrap(); + assert_eq!( + parsed["result"]["protocolVersion"], "2025-03-26", + "unsupported client version should fall back to default_version" + ); + }, + _ => panic!("expected Reject with 200"), + } +} + +#[tokio::test] +async fn initialize_missing_version_falls_back_to_default() { + let filter = make_broker_filter_with_versions("2025-03-26"); + let body_str = r#"{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"capabilities":{}}}"#; + let req = make_mcp_request(); + let mut ctx = crate::test_utils::make_filter_context(&req); + let mut body = Some(Bytes::from(body_str)); + + let action = filter.on_request_body(&mut ctx, &mut body, true).await.unwrap(); + + match action { + FilterAction::Reject(ref rejection) => { + let body_str = std::str::from_utf8(rejection.body.as_ref().unwrap()).unwrap(); + let parsed: serde_json::Value = serde_json::from_str(body_str).unwrap(); + assert_eq!( + parsed["result"]["protocolVersion"], "2025-03-26", + "missing client version should fall back to default_version" + ); + }, + _ => panic!("expected Reject with 200"), + } +} + +#[test] +fn default_version_only_config_uses_default_supported_versions() { + let yaml = r#" +default_version: "2025-03-26" +servers: [] +"#; + let cfg: McpBrokerConfig = serde_yaml::from_str(yaml).unwrap(); + let (validated, _catalog) = build_config(cfg).unwrap(); + assert_eq!( + validated.supported_versions, + vec!["2025-03-26"], + "omitting supported_versions should default to implemented versions" + ); +} + +// ----------------------------------------------------------------------------- +// Test Utilities +// ----------------------------------------------------------------------------- + +const BROKER_SERVERS_YAML: &str = r#" servers: - name: weather cluster: weather-mcp @@ -1160,14 +1429,28 @@ servers: - name: create_event description: Create a calendar event "#; + +fn make_broker_filter() -> McpBrokerFilter { + build_broker_filter_from_yaml(BROKER_SERVERS_YAML) +} + +fn make_broker_filter_with_versions(version: &str) -> McpBrokerFilter { + let yaml = format!("default_version: \"{version}\"\nsupported_versions: [\"{version}\"]\n{BROKER_SERVERS_YAML}"); + build_broker_filter_from_yaml(&yaml) +} + +fn build_broker_filter_from_yaml(yaml: &str) -> McpBrokerFilter { let cfg: McpBrokerConfig = serde_yaml::from_str(yaml).unwrap(); let (validated, catalog) = build_config(cfg).unwrap(); let json_rpc_config = build_json_rpc_config(validated.max_body_bytes); McpBrokerFilter { catalog, + default_version: validated.default_version.clone(), json_rpc_config, max_body_bytes: validated.max_body_bytes, + protocol_profile: validated.protocol_profile, public_path: validated.path.clone(), + supported_versions: validated.supported_versions.clone(), } } diff --git a/filter/src/builtins/http/ai/agentic/mcp/mod.rs b/filter/src/builtins/http/ai/agentic/mcp/mod.rs index 2f1d9e1ff2..ebb9888b9b 100644 --- a/filter/src/builtins/http/ai/agentic/mcp/mod.rs +++ b/filter/src/builtins/http/ai/agentic/mcp/mod.rs @@ -6,6 +6,7 @@ mod broker; pub(crate) mod config; pub(crate) mod envelope; +pub(crate) mod protocol; #[cfg(test)] #[allow( diff --git a/filter/src/builtins/http/ai/agentic/mcp/protocol.rs b/filter/src/builtins/http/ai/agentic/mcp/protocol.rs new file mode 100644 index 0000000000..3da713f2c7 --- /dev/null +++ b/filter/src/builtins/http/ai/agentic/mcp/protocol.rs @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2026 Praxis Contributors + +//! MCP protocol version and profile types. +//! +//! Centralizes the protocol version string so it is not scattered through +//! handlers and tests. Future MCP spec versions can be added to +//! [`SUPPORTED_VERSIONS`] without modifying individual request handlers. + +use serde::Deserialize; + +// ----------------------------------------------------------------------------- +// Constants +// ----------------------------------------------------------------------------- + +/// Protocol version implemented by the current broker behavior. +pub(crate) const PROTOCOL_VERSION_CURRENT: &str = "2025-03-26"; + +/// All protocol versions this build of Praxis can handle. +pub(crate) const SUPPORTED_VERSIONS: &[&str] = &[PROTOCOL_VERSION_CURRENT]; + +/// Fallback protocol version used when no explicit version is configured. +pub(crate) const DEFAULT_VERSION: &str = PROTOCOL_VERSION_CURRENT; + +// ----------------------------------------------------------------------------- +// ProtocolProfile +// ----------------------------------------------------------------------------- + +/// MCP protocol profile governing session semantics and header requirements. +/// +/// The `Current` profile preserves the existing `initialize`/session behavior. +/// Future profiles can be added when the MCP spec finalizes additional +/// transport modes. +#[derive(Debug, Clone, Copy, Default, Deserialize, PartialEq, Eq)] +#[serde(rename_all = "snake_case")] +pub(crate) enum ProtocolProfile { + /// Current MCP Streamable HTTP behavior: `initialize` handshake, + /// optional `MCP-Session-Id`, and session-aware DELETE. + #[default] + Current, +} + +impl ProtocolProfile { + /// String label for logging and metadata. + #[allow(dead_code, reason = "plumbing for follow-up profile-aware logging")] + pub(crate) fn as_str(self) -> &'static str { + match self { + Self::Current => "current", + } + } +} + +// ----------------------------------------------------------------------------- +// Helpers +// ----------------------------------------------------------------------------- + +/// Returns `true` when `version` appears in [`SUPPORTED_VERSIONS`]. +pub(crate) fn is_supported_version(version: &str) -> bool { + SUPPORTED_VERSIONS.contains(&version) +} + +// ----------------------------------------------------------------------------- +// Tests +// ----------------------------------------------------------------------------- + +#[cfg(test)] +#[allow( + clippy::unwrap_used, + clippy::expect_used, + clippy::needless_raw_strings, + clippy::needless_raw_string_hashes, + reason = "tests" +)] +mod tests { + use super::*; + + #[test] + fn default_version_is_supported() { + assert!( + is_supported_version(DEFAULT_VERSION), + "DEFAULT_VERSION must appear in SUPPORTED_VERSIONS" + ); + } + + #[test] + fn current_version_is_supported() { + assert!( + is_supported_version(PROTOCOL_VERSION_CURRENT), + "PROTOCOL_VERSION_CURRENT must be supported" + ); + } + + #[test] + fn unknown_version_is_not_supported() { + assert!( + !is_supported_version("9999-12-31"), + "arbitrary version should not be supported" + ); + } + + #[test] + fn default_profile_is_current() { + assert_eq!( + ProtocolProfile::default(), + ProtocolProfile::Current, + "default profile should be Current" + ); + } + + #[test] + fn profile_as_str_round_trips() { + assert_eq!(ProtocolProfile::Current.as_str(), "current"); + } + + #[test] + fn profile_deserializes_from_yaml() { + let profile: ProtocolProfile = serde_yaml::from_str("current").unwrap(); + assert_eq!(profile, ProtocolProfile::Current, "should parse 'current'"); + } + + #[test] + fn profile_rejects_unknown_value() { + let result = serde_yaml::from_str::("unknown"); + assert!(result.is_err(), "unknown profile value should fail to parse"); + } +} From c978feb30c58b4a3c81c611b174a8ae4abc91db4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Han?= Date: Wed, 3 Jun 2026 13:55:43 +0200 Subject: [PATCH 019/646] refactor(filter): prefix API format values and filter name with openai_ (#446) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor(filter): prefix API format values and filter name with openai_ Rename the responses_format filter to openai_responses_format and its classified format values from responses/chat_completions to openai_responses/openai_chat_completions, namespacing them under the OpenAI provider for clarity as multi-provider support expands. * style(filter): rename test fn to match openai_ prefix convention Signed-off-by: Sébastien Han --- docs/proposals/00354_responses-api-filters.md | 6 +- .../ai/openai/responses/format-routing.yaml | 12 +-- .../ai/openai/responses/classifier/mod.rs | 8 +- .../http/ai/openai/responses/config.rs | 8 +- .../builtins/http/ai/openai/responses/mod.rs | 27 +++--- .../http/ai/openai/responses/tests.rs | 82 +++++++++++-------- filter/src/registry.rs | 6 +- tests/integration/tests/suite/examples/mod.rs | 4 +- ...s_format.rs => openai_responses_format.rs} | 6 +- tests/integration/tests/suite/main.rs | 4 +- ...s_format.rs => openai_responses_format.rs} | 32 ++++---- 11 files changed, 108 insertions(+), 87 deletions(-) rename tests/integration/tests/suite/examples/{responses_format.rs => openai_responses_format.rs} (94%) rename tests/integration/tests/suite/{responses_format.rs => openai_responses_format.rs} (96%) diff --git a/docs/proposals/00354_responses-api-filters.md b/docs/proposals/00354_responses-api-filters.md index 30d3e653b3..401b6b9b0b 100644 --- a/docs/proposals/00354_responses-api-filters.md +++ b/docs/proposals/00354_responses-api-filters.md @@ -76,7 +76,7 @@ need to support this protocol whether their backends speak it natively or only support Chat Completions. Praxis already classifies Responses API requests via -the `responses_format` filter (#372). The next step +the `openai_responses_format` filter (#372). The next step is processing them: parsing requests, managing conversation state, calling inference, transforming streaming responses, dispatching tools, and looping @@ -174,7 +174,7 @@ Request arrives at POST /v1/responses **Pass-through is the fast path.** A simple `POST /v1/responses` with `store=false` and a string input hits vLLM directly with sub-millisecond proxy overhead. The filter chain only activates when the request actually needs stateful processing. **What #361 promotes to headers for downstream routing:** -- `x-praxis-api-format: responses | chat_completions` — detected API format +- `x-praxis-api-format: openai_responses | openai_chat_completions` — detected API format - `x-praxis-responses-mode: passthrough | stateful` — routing decision - Model name extracted from body for cluster routing @@ -255,7 +255,7 @@ struct ResponsesState { Filters access the orchestrator state via a well-known handle. Since filters run sequentially within a request, a full `Mutex` may not be necessary — simpler interior mutability (e.g., `RefCell` or just `&mut` access) could suffice. The exact synchronization primitive can be determined during implementation. -**Relationship to #372 (`responses_format` classifier):** The #372 classifier runs upstream of our filter chain. It uses `StreamBuffer` in read-only mode to classify the request format (Responses vs Chat Completions) and promotes routing facts to metadata/headers/filter_results, but does NOT retain the parsed body. Our `request_validate` filter parses the body independently via its own `StreamBuffer`, creates `ResponsesState`, and makes it available to the rest of the chain. This means the JSON body is parsed twice (once by #372 for classification, once by `request_validate` for validation) — sub-millisecond cost, clean separation of concerns. +**Relationship to #372 (`openai_responses_format` classifier):** The #372 classifier runs upstream of our filter chain. It uses `StreamBuffer` in read-only mode to classify the request format (Responses vs Chat Completions) and promotes routing facts to metadata/headers/filter_results, but does NOT retain the parsed body. Our `request_validate` filter parses the body independently via its own `StreamBuffer`, creates `ResponsesState`, and makes it available to the rest of the chain. This means the JSON body is parsed twice (once by #372 for classification, once by `request_validate` for validation) — sub-millisecond cost, clean separation of concerns. ### Filter Specifications diff --git a/examples/configs/ai/openai/responses/format-routing.yaml b/examples/configs/ai/openai/responses/format-routing.yaml index 72113b4da5..62e39215d4 100644 --- a/examples/configs/ai/openai/responses/format-routing.yaml +++ b/examples/configs/ai/openai/responses/format-routing.yaml @@ -1,8 +1,8 @@ # Responses Format Routing # -# Routes AI API traffic by detected body format. The `responses_format` -# filter parses JSON request bodies and classifies them as `responses` -# (Responses API), `chat_completions` (Chat Completions API), or +# Routes AI API traffic by detected body format. The `openai_responses_format` +# filter parses JSON request bodies and classifies them as `openai_responses` +# (Responses API), `openai_chat_completions` (Chat Completions API), or # `unknown` (valid JSON but unrecognized format). # # Classification facts are promoted to internal routing headers @@ -22,7 +22,7 @@ listeners: filter_chains: - name: ai-routing filters: - - filter: responses_format + - filter: openai_responses_format on_invalid: continue max_body_bytes: 67108864 headers: @@ -34,11 +34,11 @@ filter_chains: routes: - path: "/v1/responses" headers: - x-praxis-ai-format: "responses" + x-praxis-ai-format: "openai_responses" cluster: "responses-backend" - path: "/v1/chat/completions" headers: - x-praxis-ai-format: "chat_completions" + x-praxis-ai-format: "openai_chat_completions" cluster: "chat-backend" - path_prefix: "/" cluster: "default-backend" diff --git a/filter/src/builtins/http/ai/openai/responses/classifier/mod.rs b/filter/src/builtins/http/ai/openai/responses/classifier/mod.rs index 7b61ea7394..d0b0c9fd77 100644 --- a/filter/src/builtins/http/ai/openai/responses/classifier/mod.rs +++ b/filter/src/builtins/http/ai/openai/responses/classifier/mod.rs @@ -26,8 +26,8 @@ impl AiRequestFormat { /// Stable string representation for headers, metadata, and filter results. pub(crate) fn as_str(self) -> &'static str { match self { - Self::Responses => "responses", - Self::ChatCompletions => "chat_completions", + Self::Responses => "openai_responses", + Self::ChatCompletions => "openai_chat_completions", Self::UnknownJson => "unknown", Self::InvalidJson => "invalid_json", Self::NonJson => "non_json", @@ -226,7 +226,7 @@ mod tests { assert_eq!( result.format, AiRequestFormat::ChatCompletions, - "messages array should classify as chat_completions" + "messages array should classify as openai_chat_completions" ); assert_eq!(result.model.as_deref(), Some("gpt-4"), "model should be extracted"); } @@ -239,7 +239,7 @@ mod tests { assert_eq!( result.format, AiRequestFormat::ChatCompletions, - "should be chat_completions" + "should be openai_chat_completions" ); assert_eq!(result.stream, Some(true), "stream should be extracted"); } diff --git a/filter/src/builtins/http/ai/openai/responses/config.rs b/filter/src/builtins/http/ai/openai/responses/config.rs index 5cc4beef2e..244bfae4e4 100644 --- a/filter/src/builtins/http/ai/openai/responses/config.rs +++ b/filter/src/builtins/http/ai/openai/responses/config.rs @@ -47,7 +47,7 @@ pub(crate) enum OnInvalidBehavior { #[derive(Debug, Clone, Deserialize)] #[serde(deny_unknown_fields)] pub(crate) struct ResponsesFormatHeaders { - /// Header name for the detected format (e.g. `responses`, `chat_completions`). + /// Header name for the detected format (e.g. `openai_responses`, `openai_chat_completions`). #[serde(default = "default_format_header")] pub format: Option, @@ -132,7 +132,7 @@ fn default_max_body_bytes() -> usize { /// Validate the parsed configuration. pub(crate) fn build_config(cfg: ResponsesFormatConfig) -> Result { if cfg.max_body_bytes == 0 { - return Err("responses_format: 'max_body_bytes' must be greater than 0".into()); + return Err("openai_responses_format: 'max_body_bytes' must be greater than 0".into()); } if cfg.max_body_bytes > MAX_JSON_BODY_BYTES { @@ -156,10 +156,10 @@ fn validate_header_name(field: &str, header_name: Option<&str>) -> Result<(), Fi return Ok(()); }; if header_name.is_empty() { - return Err(format!("responses_format: {field} header name must not be empty").into()); + return Err(format!("openai_responses_format: {field} header name must not be empty").into()); } if http::HeaderName::from_bytes(header_name.as_bytes()).is_err() { - return Err(format!("responses_format: {field} header name is not a valid HTTP header name").into()); + return Err(format!("openai_responses_format: {field} header name is not a valid HTTP header name").into()); } Ok(()) } diff --git a/filter/src/builtins/http/ai/openai/responses/mod.rs b/filter/src/builtins/http/ai/openai/responses/mod.rs index fc77cefb8a..df71ecf0ad 100644 --- a/filter/src/builtins/http/ai/openai/responses/mod.rs +++ b/filter/src/builtins/http/ai/openai/responses/mod.rs @@ -59,13 +59,13 @@ use crate::{ /// # YAML /// /// ```yaml -/// filter: responses_format +/// filter: openai_responses_format /// ``` /// /// # Full YAML /// /// ```yaml -/// filter: responses_format +/// filter: openai_responses_format /// on_invalid: continue /// max_body_bytes: 67108864 /// headers: @@ -87,7 +87,7 @@ impl ResponsesFormatFilter { /// /// [`FilterError`]: crate::FilterError pub fn from_config(config: &serde_yaml::Value) -> Result, FilterError> { - let cfg: ResponsesFormatConfig = parse_filter_config("responses_format", config)?; + let cfg: ResponsesFormatConfig = parse_filter_config("openai_responses_format", config)?; let validated = build_config(cfg)?; Ok(Box::new(Self { config: validated })) } @@ -96,7 +96,7 @@ impl ResponsesFormatFilter { #[async_trait] impl HttpFilter for ResponsesFormatFilter { fn name(&self) -> &'static str { - "responses_format" + "openai_responses_format" } fn request_body_access(&self) -> BodyAccess { @@ -179,32 +179,35 @@ fn handle_invalid_format(format: AiRequestFormat, config: &ResponsesFormatConfig /// Write durable metadata that persists across all Pingora lifecycle phases. fn write_metadata(ctx: &mut HttpFilterContext<'_>, classified: &classifier::ClassifiedRequest) { let format_str = classified.format.as_str(); - ctx.set_metadata("responses_format.format", format_str); + ctx.set_metadata("openai_responses_format.format", format_str); if let Some(model) = &classified.model && is_safe_promoted_value(model) { - ctx.set_metadata("responses_format.model", model.clone()); + ctx.set_metadata("openai_responses_format.model", model.clone()); } if let Some(stream) = classified.stream { - ctx.set_metadata("responses_format.stream", if stream { "true" } else { "false" }); + ctx.set_metadata("openai_responses_format.stream", if stream { "true" } else { "false" }); } if let Some(store) = classified.store { - ctx.set_metadata("responses_format.store", if store { "true" } else { "false" }); + ctx.set_metadata("openai_responses_format.store", if store { "true" } else { "false" }); } if let Some(background) = classified.background { - ctx.set_metadata("responses_format.background", if background { "true" } else { "false" }); + ctx.set_metadata( + "openai_responses_format.background", + if background { "true" } else { "false" }, + ); } if classified.has_previous_response_id { - ctx.set_metadata("responses_format.has_previous_response_id", "true"); + ctx.set_metadata("openai_responses_format.has_previous_response_id", "true"); } if classified.has_conversation { - ctx.set_metadata("responses_format.has_conversation", "true"); + ctx.set_metadata("openai_responses_format.has_conversation", "true"); } } @@ -243,7 +246,7 @@ fn promote_filter_results( ctx: &mut HttpFilterContext<'_>, classified: &classifier::ClassifiedRequest, ) -> Result<(), FilterError> { - let results = ctx.filter_results.entry("responses_format").or_default(); + let results = ctx.filter_results.entry("openai_responses_format").or_default(); results.set("format", classified.format.as_str())?; diff --git a/filter/src/builtins/http/ai/openai/responses/tests.rs b/filter/src/builtins/http/ai/openai/responses/tests.rs index d8df7878c8..31d6aa3060 100644 --- a/filter/src/builtins/http/ai/openai/responses/tests.rs +++ b/filter/src/builtins/http/ai/openai/responses/tests.rs @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // Copyright (c) 2026 Praxis Contributors -//! Unit tests for the `responses_format` filter. +//! Unit tests for the `openai_responses_format` filter. use bytes::Bytes; @@ -17,8 +17,8 @@ fn default_config_parses() { let filter = ResponsesFormatFilter::from_config(&yaml).unwrap(); assert_eq!( filter.name(), - "responses_format", - "filter name should be responses_format" + "openai_responses_format", + "filter name should be openai_responses_format" ); } @@ -39,8 +39,8 @@ headers: let filter = ResponsesFormatFilter::from_config(&yaml).unwrap(); assert_eq!( filter.name(), - "responses_format", - "filter name should be responses_format" + "openai_responses_format", + "filter name should be openai_responses_format" ); } @@ -48,14 +48,14 @@ headers: fn on_invalid_continue_parses() { let yaml: serde_yaml::Value = serde_yaml::from_str("on_invalid: continue").unwrap(); let filter = ResponsesFormatFilter::from_config(&yaml).unwrap(); - assert_eq!(filter.name(), "responses_format", "continue mode should parse"); + assert_eq!(filter.name(), "openai_responses_format", "continue mode should parse"); } #[test] fn on_invalid_reject_parses() { let yaml: serde_yaml::Value = serde_yaml::from_str("on_invalid: reject").unwrap(); let filter = ResponsesFormatFilter::from_config(&yaml).unwrap(); - assert_eq!(filter.name(), "responses_format", "reject mode should parse"); + assert_eq!(filter.name(), "openai_responses_format", "reject mode should parse"); } #[test] @@ -122,7 +122,7 @@ headers: let filter = ResponsesFormatFilter::from_config(&yaml).unwrap(); assert_eq!( filter.name(), - "responses_format", + "openai_responses_format", "null headers should disable promotion" ); } @@ -191,7 +191,7 @@ fn non_json_reject_returns_reject() { } #[test] -fn responses_format_not_rejected() { +fn openai_responses_format_not_rejected() { let cfg: ResponsesFormatConfig = serde_yaml::from_str("on_invalid: reject").unwrap(); let result = handle_invalid_format(AiRequestFormat::Responses, &cfg); assert!(result.is_none(), "responses format should not be rejected"); @@ -201,7 +201,10 @@ fn responses_format_not_rejected() { fn chat_completions_not_rejected() { let cfg: ResponsesFormatConfig = serde_yaml::from_str("on_invalid: reject").unwrap(); let result = handle_invalid_format(AiRequestFormat::ChatCompletions, &cfg); - assert!(result.is_none(), "chat_completions format should not be rejected"); + assert!( + result.is_none(), + "openai_chat_completions format should not be rejected" + ); } #[test] @@ -249,7 +252,11 @@ async fn promotes_headers_for_full_responses_request() { let ctx = run_filter("{}", FULL_RESPONSES_BODY).await; let headers = collect_headers(&ctx); - assert_eq!(headers.get("x-praxis-ai-format"), Some(&"responses"), "format header"); + assert_eq!( + headers.get("x-praxis-ai-format"), + Some(&"openai_responses"), + "format header" + ); assert_eq!(headers.get("x-praxis-ai-model"), Some(&"gpt-4.1"), "model header"); assert_eq!(headers.get("x-praxis-ai-stream"), Some(&"true"), "stream header"); assert!( @@ -263,36 +270,44 @@ async fn promotes_metadata_for_full_responses_request() { let ctx = run_filter("{}", FULL_RESPONSES_BODY).await; assert_eq!( - ctx.filter_metadata.get("responses_format.format").map(String::as_str), - Some("responses") + ctx.filter_metadata + .get("openai_responses_format.format") + .map(String::as_str), + Some("openai_responses") ); assert_eq!( - ctx.filter_metadata.get("responses_format.model").map(String::as_str), + ctx.filter_metadata + .get("openai_responses_format.model") + .map(String::as_str), Some("gpt-4.1") ); assert_eq!( - ctx.filter_metadata.get("responses_format.stream").map(String::as_str), + ctx.filter_metadata + .get("openai_responses_format.stream") + .map(String::as_str), Some("true") ); assert_eq!( - ctx.filter_metadata.get("responses_format.store").map(String::as_str), + ctx.filter_metadata + .get("openai_responses_format.store") + .map(String::as_str), Some("false") ); assert_eq!( ctx.filter_metadata - .get("responses_format.background") + .get("openai_responses_format.background") .map(String::as_str), Some("true") ); assert_eq!( ctx.filter_metadata - .get("responses_format.has_previous_response_id") + .get("openai_responses_format.has_previous_response_id") .map(String::as_str), Some("true") ); assert_eq!( ctx.filter_metadata - .get("responses_format.has_conversation") + .get("openai_responses_format.has_conversation") .map(String::as_str), Some("true") ); @@ -301,9 +316,9 @@ async fn promotes_metadata_for_full_responses_request() { #[tokio::test] async fn promotes_filter_results_for_full_responses_request() { let ctx = run_filter("{}", FULL_RESPONSES_BODY).await; - let results = ctx.filter_results.get("responses_format").unwrap(); + let results = ctx.filter_results.get("openai_responses_format").unwrap(); - assert_eq!(results.get("format"), Some("responses")); + assert_eq!(results.get("format"), Some("openai_responses")); assert_eq!(results.get("model"), Some("gpt-4.1")); assert_eq!(results.get("stream"), Some("true")); assert_eq!(results.get("store"), Some("false")); @@ -319,34 +334,35 @@ async fn missing_optional_facts_not_promoted() { assert_eq!( headers.get("x-praxis-ai-format"), - Some(&"responses"), + Some(&"openai_responses"), "format still promoted" ); assert!(!headers.contains_key("x-praxis-ai-model"), "model header absent"); assert!(!headers.contains_key("x-praxis-ai-stream"), "stream header absent"); assert!( - !ctx.filter_metadata.contains_key("responses_format.model"), + !ctx.filter_metadata.contains_key("openai_responses_format.model"), "model metadata absent" ); assert!( - !ctx.filter_metadata.contains_key("responses_format.stream"), + !ctx.filter_metadata.contains_key("openai_responses_format.stream"), "stream metadata absent" ); assert!( - !ctx.filter_metadata.contains_key("responses_format.store"), + !ctx.filter_metadata.contains_key("openai_responses_format.store"), "store metadata absent" ); assert!( - !ctx.filter_metadata.contains_key("responses_format.background"), + !ctx.filter_metadata.contains_key("openai_responses_format.background"), "background metadata absent" ); assert!( !ctx.filter_metadata - .contains_key("responses_format.has_previous_response_id"), + .contains_key("openai_responses_format.has_previous_response_id"), "prev_id metadata absent" ); assert!( - !ctx.filter_metadata.contains_key("responses_format.has_conversation"), + !ctx.filter_metadata + .contains_key("openai_responses_format.has_conversation"), "conversation metadata absent" ); } @@ -362,7 +378,7 @@ async fn oversized_model_not_promoted_to_header_or_results() { !headers.contains_key("x-praxis-ai-model"), "oversized model not in header" ); - let results = ctx.filter_results.get("responses_format").unwrap(); + let results = ctx.filter_results.get("openai_responses_format").unwrap(); assert!(results.get("model").is_none(), "oversized model not in results"); } @@ -383,7 +399,7 @@ async fn custom_headers_emitted_at_runtime() { let ctx = run_filter(cfg, r#"{"model":"gpt-4.1","input":"test","stream":true}"#).await; let headers = collect_headers(&ctx); - assert_eq!(headers.get("x-custom-fmt"), Some(&"responses"), "custom format"); + assert_eq!(headers.get("x-custom-fmt"), Some(&"openai_responses"), "custom format"); assert_eq!(headers.get("x-custom-mdl"), Some(&"gpt-4.1"), "custom model"); assert_eq!(headers.get("x-custom-strm"), Some(&"true"), "custom stream"); assert!( @@ -402,8 +418,10 @@ async fn null_headers_suppress_emission() { "null headers suppress all emission" ); assert_eq!( - ctx.filter_metadata.get("responses_format.format").map(String::as_str), - Some("responses"), + ctx.filter_metadata + .get("openai_responses_format.format") + .map(String::as_str), + Some("openai_responses"), "metadata still written with null headers" ); } diff --git a/filter/src/registry.rs b/filter/src/registry.rs index 7a1a2bdc5e..b8947f96b0 100644 --- a/filter/src/registry.rs +++ b/filter/src/registry.rs @@ -158,7 +158,7 @@ fn register_http_builtins(factories: &mut HashMap) { #[cfg(feature = "ai-inference")] register_http( factories, - "responses_format", + "openai_responses_format", crate::builtins::ResponsesFormatFilter::from_config, ); } @@ -278,8 +278,8 @@ mod tests { assert!(names.contains(&"prompt_enrich"), "prompt_enrich should be registered"); #[cfg(feature = "ai-inference")] assert!( - names.contains(&"responses_format"), - "responses_format should be registered" + names.contains(&"openai_responses_format"), + "openai_responses_format should be registered" ); } diff --git a/tests/integration/tests/suite/examples/mod.rs b/tests/integration/tests/suite/examples/mod.rs index 77f4c8a45a..ec88237bf3 100644 --- a/tests/integration/tests/suite/examples/mod.rs +++ b/tests/integration/tests/suite/examples/mod.rs @@ -29,6 +29,8 @@ mod max_connections; #[cfg(feature = "ai-inference")] mod model_to_header; mod multi_listener; +#[cfg(feature = "ai-inference")] +mod openai_responses_format; mod p2c; mod path_based_routing; mod path_rewriting; @@ -37,8 +39,6 @@ mod payload_processing; mod prompt_enrichment; mod protocols; mod redirect; -#[cfg(feature = "ai-inference")] -mod responses_format; mod round_robin; mod session_affinity; mod static_response; diff --git a/tests/integration/tests/suite/examples/responses_format.rs b/tests/integration/tests/suite/examples/openai_responses_format.rs similarity index 94% rename from tests/integration/tests/suite/examples/responses_format.rs rename to tests/integration/tests/suite/examples/openai_responses_format.rs index 3744250a52..ec413c64c0 100644 --- a/tests/integration/tests/suite/examples/responses_format.rs +++ b/tests/integration/tests/suite/examples/openai_responses_format.rs @@ -15,7 +15,7 @@ use praxis_test_utils::{ // ----------------------------------------------------------------------------- #[test] -fn responses_format_routing_example_routes_responses_input() { +fn openai_responses_format_routing_example_routes_responses_input() { let responses_guard = start_backend_with_shutdown("responses-backend"); let chat_guard = start_backend_with_shutdown("chat-backend"); let default_guard = start_backend_with_shutdown("default-backend"); @@ -44,7 +44,7 @@ fn responses_format_routing_example_routes_responses_input() { } #[test] -fn responses_format_routing_example_routes_chat_completions() { +fn openai_responses_format_routing_example_routes_chat_completions() { let responses_guard = start_backend_with_shutdown("responses-backend"); let chat_guard = start_backend_with_shutdown("chat-backend"); let default_guard = start_backend_with_shutdown("default-backend"); @@ -73,7 +73,7 @@ fn responses_format_routing_example_routes_chat_completions() { } #[test] -fn responses_format_routing_example_unknown_falls_to_default() { +fn openai_responses_format_routing_example_unknown_falls_to_default() { let responses_guard = start_backend_with_shutdown("responses-backend"); let chat_guard = start_backend_with_shutdown("chat-backend"); let default_guard = start_backend_with_shutdown("default-backend"); diff --git a/tests/integration/tests/suite/main.rs b/tests/integration/tests/suite/main.rs index ff51b1a14b..248e22dcc5 100644 --- a/tests/integration/tests/suite/main.rs +++ b/tests/integration/tests/suite/main.rs @@ -56,14 +56,14 @@ mod json_body_field; mod json_rpc; mod mcp; mod mcp_broker; +#[cfg(feature = "ai-inference")] +mod openai_responses_format; mod path_rewrite; mod payload_processing; mod per_listener_pipeline; #[cfg(feature = "ai-inference")] mod prompt_enrich; mod rate_limit; -#[cfg(feature = "ai-inference")] -mod responses_format; mod retry; mod routing; mod security; diff --git a/tests/integration/tests/suite/responses_format.rs b/tests/integration/tests/suite/openai_responses_format.rs similarity index 96% rename from tests/integration/tests/suite/responses_format.rs rename to tests/integration/tests/suite/openai_responses_format.rs index 37e19020f5..03d2ca4ea2 100644 --- a/tests/integration/tests/suite/responses_format.rs +++ b/tests/integration/tests/suite/openai_responses_format.rs @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // Copyright (c) 2026 Praxis Contributors -//! Integration tests for the `responses_format` classifier filter. +//! Integration tests for the `openai_responses_format` classifier filter. use praxis_core::config::Config; use praxis_test_utils::{ @@ -396,7 +396,7 @@ fn filter_results_enable_branch_routing() { assert_eq!( parse_body(&raw_chat), "default-branch-miss", - "branch should not fire for chat_completions, falling through to default" + "branch should not fire for openai_chat_completions, falling through to default" ); } @@ -496,17 +496,17 @@ listeners: filter_chains: - name: main filters: - - filter: responses_format + - filter: openai_responses_format on_invalid: continue - filter: router routes: - path: "/v1/responses" headers: - x-praxis-ai-format: "responses" + x-praxis-ai-format: "openai_responses" cluster: "responses" - path: "/v1/chat/completions" headers: - x-praxis-ai-format: "chat_completions" + x-praxis-ai-format: "openai_chat_completions" cluster: "chat" - path_prefix: "/" cluster: "default" @@ -536,7 +536,7 @@ listeners: filter_chains: - name: main filters: - - filter: responses_format + - filter: openai_responses_format on_invalid: continue - filter: router routes: @@ -562,7 +562,7 @@ listeners: filter_chains: - name: main filters: - - filter: responses_format + - filter: openai_responses_format on_invalid: reject - filter: router routes: @@ -588,7 +588,7 @@ listeners: filter_chains: - name: main filters: - - filter: responses_format + - filter: openai_responses_format - filter: router routes: - path_prefix: "/" @@ -613,7 +613,7 @@ listeners: filter_chains: - name: main filters: - - filter: responses_format + - filter: openai_responses_format - filter: router routes: - path_prefix: "/" @@ -638,13 +638,13 @@ listeners: filter_chains: - name: main filters: - - filter: responses_format + - filter: openai_responses_format branch_chains: - name: responses_branch on_result: - filter: responses_format + filter: openai_responses_format key: format - result: responses + result: openai_responses rejoin: terminal chains: - name: responses_chain @@ -682,11 +682,11 @@ listeners: filter_chains: - name: main filters: - - filter: responses_format + - filter: openai_responses_format branch_chains: - name: background_branch on_result: - filter: responses_format + filter: openai_responses_format key: background result: true rejoin: terminal @@ -726,7 +726,7 @@ listeners: filter_chains: - name: main filters: - - filter: responses_format + - filter: openai_responses_format - filter: router routes: - path_prefix: "/" @@ -765,7 +765,7 @@ listeners: filter_chains: - name: main filters: - - filter: responses_format + - filter: openai_responses_format - filter: router routes: - path_prefix: "/" From e635747747b924d4b6e0722e2cc0b9658efaa260 Mon Sep 17 00:00:00 2001 From: Shane Utt Date: Wed, 3 Jun 2026 09:05:15 -0400 Subject: [PATCH 020/646] docs(proposals): allow pr lists in proposal details for v0.x.x Signed-off-by: Shane Utt --- docs/proposals.md | 19 +++++++++++++------ docs/proposals/template.md | 20 ++++++++++++++++---- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/docs/proposals.md b/docs/proposals.md index 7c9d6e8427..ade4aab128 100644 --- a/docs/proposals.md +++ b/docs/proposals.md @@ -55,10 +55,16 @@ as a PR. File naming convention: ``` The first PR must contain only the **What?** and **Why?** -sections. The **How?** section is almost always contentious -and must be added in a follow-up PR after the goals and -motivation are accepted. See the [template] for the full -structure. +sections. The **How?** section must be added after the +goals and motivation are accepted. See the [template] +for the full structure. + +> **v0.x.x simplification**: During pre-1.0 development, +> the **How?** section does not require an upfront design +> document. Once the **What?** and **Why?** are agreed on, +> the **How?** can simply list the PRs that implement the +> solution. A full requirements and design writeup is +> welcome but not required until 1.0. CI will close PRs that: @@ -72,8 +78,9 @@ CI will close PRs that: ### 5. Iteration Iterate on the proposal in subsequent PRs. Add the -**How?** section with requirements and design details. -Refine until a maintainer marks the proposal as accepted. +**How?** section: either a list of implementing PRs +or a full requirements and design writeup. Refine +until a maintainer marks the proposal as accepted. ### 6. Experimental diff --git a/docs/proposals/template.md b/docs/proposals/template.md index 4d4df320ac..2b2b39ee58 100644 --- a/docs/proposals/template.md +++ b/docs/proposals/template.md @@ -33,6 +33,22 @@ Why this change is needed. ## How? +> **Note:** do not include this section in the first PR. +> Submit What? and Why? first. Add How? in a follow-up +> PR after the proposal direction is accepted. + + + + + +### Implementation + +- [#NNN](link) — brief description +- [#NNN](link) — brief description + + + ### Requirements - Requirement 1 @@ -41,7 +57,3 @@ Why this change is needed. ### Design Technical design and architecture details. - -> **Note:** do not include this section in the first PR. -> Submit What? and Why? first. Add How? in a follow-up -> PR after the proposal direction is accepted. From d8855dc66dec04d01aac359187917fc82fea5b93 Mon Sep 17 00:00:00 2001 From: Shane Utt Date: Wed, 3 Jun 2026 09:32:06 -0400 Subject: [PATCH 021/646] fix(ci): don't run triage for pull requests Signed-off-by: Shane Utt --- .github/workflows/issue-triage.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/issue-triage.yaml b/.github/workflows/issue-triage.yaml index d99ed6ce86..1ae1317137 100644 --- a/.github/workflows/issue-triage.yaml +++ b/.github/workflows/issue-triage.yaml @@ -16,6 +16,7 @@ jobs: # ---------------------------------------------------------------------------- triage: + if: ${{ !github.event.issue.pull_request }} runs-on: ubuntu-24.04 permissions: issues: write From 62840d0af5db4aa7499615ee680975b92dad2916 Mon Sep 17 00:00:00 2001 From: Francisco Javier Arceo Date: Wed, 3 Jun 2026 10:00:55 -0400 Subject: [PATCH 022/646] docs: add key architectural patterns to CLAUDE.md (#472) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Documents patterns for AI filter development: - Classify → route via internal headers - Branch on filter results for pipeline splitting - Prefer existing routing mechanisms - No full streaming response buffering - Proxy-only validation (defer to backend) - Use dedicated rewrite filters for URL translation Signed-off-by: Francisco Javier Arceo --- .claude/CLAUDE.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index e61305fb77..e26eb64bc7 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -220,6 +220,41 @@ Branches rejoin at configurable points (next, terminal, named filter, re-entrance with iteration limits). +## Key Patterns + +- **Classify → route**: classifier filters promote + facts to internal headers (`x-praxis-ai-*`) and + the router matches those headers to select + clusters. See + `examples/configs/ai/openai/responses/format-routing.yaml`. +- **Branch on filter results**: branch chains split + or rejoin request-phase pipelines based on filter + results (`on_result`). See + `examples/configs/pipeline/branch-chains.yaml` + and `tests/integration/tests/suite/responses_format.rs`. + Branch sub-chains only run `on_request`; + `on_request_body` and `on_response_body` are not + executed for filters inside branch chains. + Body-transforming filters must be in the main + pipeline path or gated with normal filter + conditions. +- **Prefer existing routing mechanisms**: use + classifier-promoted headers, router matches, + filter conditions, and branch chains before + adding new routing or capability mechanisms. +- **Do not buffer full streaming responses**: + streaming and SSE filters should use + `BodyMode::Stream` and process chunks + incrementally unless the feature explicitly + requires buffering. +- **Validate only proxy-needed fields**: let the + backend handle parameter ranges, model + availability, and role ordering. +- **Use dedicated rewrite filters for URL/path + translation**: use `path_rewrite` or `url_rewrite`; + provider and protocol filters should not set + `ctx.rewritten_path` directly. + ## Filter Organization Filters live under From 17c90a217429f7db8af19605e51e2e47b411a2c3 Mon Sep 17 00:00:00 2001 From: Shane Utt Date: Thu, 4 Jun 2026 12:46:55 -0400 Subject: [PATCH 023/646] ci(conventions): relax pull request limits Signed-off-by: Shane Utt --- .github/workflows/conventions.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/conventions.yaml b/.github/workflows/conventions.yaml index 2db9bfa01c..5eac5526af 100644 --- a/.github/workflows/conventions.yaml +++ b/.github/workflows/conventions.yaml @@ -28,7 +28,7 @@ jobs: env: GH_TOKEN: ${{ secrets.PRAXIS_BOT }} PR_NUMBER: ${{ github.event.pull_request.number }} - MAX_ADDITIONS: "500" + MAX_ADDITIONS: "750" run: | labels=$(gh pr view "$PR_NUMBER" --repo "${{ github.repository }}" --json labels -q '.labels[].name') if echo "$labels" | grep -q '^skip/pr-hygiene$'; then @@ -46,7 +46,7 @@ jobs: fi added=$(gh api "repos/${{ github.repository }}/pulls/${PR_NUMBER}/files" --paginate \ - --jq '[.[] | select(.filename | test("^(Cargo\\.lock|examples/)") | not) | .additions] | add // 0') + --jq '[.[] | select(.filename | test("^(Cargo\\.lock|examples/|tests/|benchmarks/|docs/)") | not) | select(.filename | test("\\.md$") | not) | .additions] | add // 0') if [ "$added" -gt "$MAX_ADDITIONS" ]; then marker="" @@ -55,7 +55,7 @@ jobs: if [ "$already" -eq 0 ]; then gh pr comment "$PR_NUMBER" --repo "${{ github.repository }}" \ --body "${marker} - **PR too large**: ${added} lines added (limit: ${MAX_ADDITIONS}). Please split into smaller PRs. Add \`skip/pr-hygiene\` label to override." + **PR too large**: ${added} lines added (limit: ${MAX_ADDITIONS}, excludes tests, docs, examples, and benchmarks). Please split into smaller PRs. Add \`skip/pr-hygiene\` label to override." fi echo "::error::PR has ${added} lines added (limit: ${MAX_ADDITIONS})" exit 1 From 8d38823614e78a2592de393a542a852b0ec43269 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 4 Jun 2026 13:12:27 -0400 Subject: [PATCH 024/646] build(deps): Bump actions/checkout from 6.0.2 to 6.0.3 (#477) Bumps [actions/checkout](https://github.com/actions/checkout) from 6.0.2 to 6.0.3. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/de0fac2e4500dabe0009e67214ff5f5447ce83dd...df4cb1c069e1874edd31b4311f1884172cec0e10) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 6.0.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/benchmarks.yaml | 2 +- .github/workflows/codeql.yaml | 2 +- .github/workflows/conformance.yaml | 2 +- .github/workflows/container.yaml | 2 +- .github/workflows/coverage.yaml | 2 +- .github/workflows/documentation.yaml | 2 +- .github/workflows/fuzz.yaml | 2 +- .github/workflows/integration.yaml | 2 +- .github/workflows/microbenchmarks.yaml | 2 +- .github/workflows/msrv.yaml | 2 +- .github/workflows/nightly.yaml | 14 +++++++------- .github/workflows/publish.yaml | 2 +- .github/workflows/release.yaml | 8 ++++---- .github/workflows/supply-chain.yaml | 4 ++-- .github/workflows/tests.yaml | 4 ++-- 15 files changed, 26 insertions(+), 26 deletions(-) diff --git a/.github/workflows/benchmarks.yaml b/.github/workflows/benchmarks.yaml index 34856ac25b..bf96d140f7 100644 --- a/.github/workflows/benchmarks.yaml +++ b/.github/workflows/benchmarks.yaml @@ -35,7 +35,7 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Install stable Rust uses: dtolnay/rust-toolchain@10c3493d811a9096cee4fdf287e41e852f6a51ba # 1.94.0 diff --git a/.github/workflows/codeql.yaml b/.github/workflows/codeql.yaml index 82890cb771..0ca0b35ae5 100644 --- a/.github/workflows/codeql.yaml +++ b/.github/workflows/codeql.yaml @@ -35,7 +35,7 @@ jobs: matrix: language: [ actions, rust ] steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Install stable Rust if: matrix.language == 'rust' diff --git a/.github/workflows/conformance.yaml b/.github/workflows/conformance.yaml index bef33260ff..a66f5874a2 100644 --- a/.github/workflows/conformance.yaml +++ b/.github/workflows/conformance.yaml @@ -30,7 +30,7 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Install stable Rust uses: dtolnay/rust-toolchain@10c3493d811a9096cee4fdf287e41e852f6a51ba # 1.94.0 diff --git a/.github/workflows/container.yaml b/.github/workflows/container.yaml index 4058db38b5..b9d2e913c7 100644 --- a/.github/workflows/container.yaml +++ b/.github/workflows/container.yaml @@ -26,7 +26,7 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Build container image run: docker build -t praxis:ci -f Containerfile . diff --git a/.github/workflows/coverage.yaml b/.github/workflows/coverage.yaml index a409987ba5..7c0abb94ea 100644 --- a/.github/workflows/coverage.yaml +++ b/.github/workflows/coverage.yaml @@ -28,7 +28,7 @@ jobs: contents: read pull-requests: write steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@10c3493d811a9096cee4fdf287e41e852f6a51ba # 1.94.0 diff --git a/.github/workflows/documentation.yaml b/.github/workflows/documentation.yaml index c1eddd9690..6f6adf2238 100644 --- a/.github/workflows/documentation.yaml +++ b/.github/workflows/documentation.yaml @@ -30,7 +30,7 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Install stable Rust uses: dtolnay/rust-toolchain@10c3493d811a9096cee4fdf287e41e852f6a51ba # 1.94.0 diff --git a/.github/workflows/fuzz.yaml b/.github/workflows/fuzz.yaml index f900d75ec0..3fa6907cda 100644 --- a/.github/workflows/fuzz.yaml +++ b/.github/workflows/fuzz.yaml @@ -38,7 +38,7 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Install nightly Rust uses: dtolnay/rust-toolchain@5b842231ba77f5c045dba54ac5560fed2db780e2 # nightly-2026-03-28 (rustc 1.96.0) diff --git a/.github/workflows/integration.yaml b/.github/workflows/integration.yaml index 9696416468..94d361100f 100644 --- a/.github/workflows/integration.yaml +++ b/.github/workflows/integration.yaml @@ -37,7 +37,7 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Install stable Rust uses: dtolnay/rust-toolchain@10c3493d811a9096cee4fdf287e41e852f6a51ba # 1.94.0 diff --git a/.github/workflows/microbenchmarks.yaml b/.github/workflows/microbenchmarks.yaml index ea9debb24b..c60d1ec757 100644 --- a/.github/workflows/microbenchmarks.yaml +++ b/.github/workflows/microbenchmarks.yaml @@ -28,7 +28,7 @@ jobs: contents: read pull-requests: write steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Install Rust uses: dtolnay/rust-toolchain@10c3493d811a9096cee4fdf287e41e852f6a51ba # 1.94.0 diff --git a/.github/workflows/msrv.yaml b/.github/workflows/msrv.yaml index 451ba7e178..5061e263ea 100644 --- a/.github/workflows/msrv.yaml +++ b/.github/workflows/msrv.yaml @@ -30,7 +30,7 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Install MSRV Rust (1.94.0) uses: dtolnay/rust-toolchain@10c3493d811a9096cee4fdf287e41e852f6a51ba # 1.94.0 diff --git a/.github/workflows/nightly.yaml b/.github/workflows/nightly.yaml index 3b95af0309..9aa427d250 100644 --- a/.github/workflows/nightly.yaml +++ b/.github/workflows/nightly.yaml @@ -28,7 +28,7 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Install nightly Rust (for rustfmt) uses: dtolnay/rust-toolchain@5b842231ba77f5c045dba54ac5560fed2db780e2 # nightly-2026-03-28 (rustc 1.96.0) @@ -67,7 +67,7 @@ jobs: env: RUSTDOCFLAGS: "-D warnings" steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Install stable Rust uses: dtolnay/rust-toolchain@10c3493d811a9096cee4fdf287e41e852f6a51ba # 1.94.0 @@ -97,7 +97,7 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Install stable Rust uses: dtolnay/rust-toolchain@10c3493d811a9096cee4fdf287e41e852f6a51ba # 1.94.0 @@ -130,7 +130,7 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Install stable Rust uses: dtolnay/rust-toolchain@10c3493d811a9096cee4fdf287e41e852f6a51ba # 1.94.0 @@ -169,7 +169,7 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Install stable Rust uses: dtolnay/rust-toolchain@10c3493d811a9096cee4fdf287e41e852f6a51ba # 1.94.0 @@ -202,7 +202,7 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Install Rust uses: dtolnay/rust-toolchain@10c3493d811a9096cee4fdf287e41e852f6a51ba # 1.94.0 @@ -233,7 +233,7 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@10c3493d811a9096cee4fdf287e41e852f6a51ba # 1.94.0 diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 7a6980988a..479eb7d033 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -32,7 +32,7 @@ jobs: contents: read packages: write steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Log in to GHCR uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 658ec3356c..6e65c96b9e 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -31,7 +31,7 @@ jobs: outputs: version: ${{ steps.version.outputs.version }} steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Extract version from tag id: version @@ -56,7 +56,7 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Install stable Rust uses: dtolnay/rust-toolchain@10c3493d811a9096cee4fdf287e41e852f6a51ba # 1.94.0 @@ -91,7 +91,7 @@ jobs: contents: read packages: write steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Log in to GHCR uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 @@ -132,7 +132,7 @@ jobs: permissions: contents: write steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Generate release notes env: diff --git a/.github/workflows/supply-chain.yaml b/.github/workflows/supply-chain.yaml index e5243971b5..f85b13cb7a 100644 --- a/.github/workflows/supply-chain.yaml +++ b/.github/workflows/supply-chain.yaml @@ -27,7 +27,7 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Install Rust uses: dtolnay/rust-toolchain@10c3493d811a9096cee4fdf287e41e852f6a51ba # 1.94.0 @@ -53,7 +53,7 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Install Rust uses: dtolnay/rust-toolchain@10c3493d811a9096cee4fdf287e41e852f6a51ba # 1.94.0 diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index f5a4023505..e774c9d870 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -37,7 +37,7 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Install nightly Rust (for rustfmt) uses: dtolnay/rust-toolchain@5b842231ba77f5c045dba54ac5560fed2db780e2 # nightly-2026-03-28 (rustc 1.96.0) @@ -74,7 +74,7 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Install stable Rust uses: dtolnay/rust-toolchain@10c3493d811a9096cee4fdf287e41e852f6a51ba # 1.94.0 From fde113e77869540722b50daa182e12131ed859ad Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 4 Jun 2026 13:12:59 -0400 Subject: [PATCH 025/646] build(deps): Bump github/codeql-action from 4.36.0 to 4.36.2 (#476) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.36.0 to 4.36.2. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/7211b7c8077ea37d8641b6271f6a365a22a5fbfa...8aad20d150bbac5944a9f9d289da16a4b0d87c1e) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: 4.36.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Shane Utt --- .github/workflows/codeql.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/codeql.yaml b/.github/workflows/codeql.yaml index 0ca0b35ae5..230782321f 100644 --- a/.github/workflows/codeql.yaml +++ b/.github/workflows/codeql.yaml @@ -56,7 +56,7 @@ jobs: save-always: true - name: Initialize CodeQL - uses: github/codeql-action/init@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0 + uses: github/codeql-action/init@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2 with: languages: ${{ matrix.language }} @@ -65,6 +65,6 @@ jobs: run: cargo build --workspace - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0 + uses: github/codeql-action/analyze@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2 with: category: "/language:${{ matrix.language }}" From 70c246ac33bcfcef1bbdd2bf3dd3f88d14e24567 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Han?= Date: Thu, 4 Jun 2026 19:15:32 +0200 Subject: [PATCH 026/646] feat(website): add project website (#376) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(website): add project website Docusaurus 3 site with landing page, documentation, examples showcase, and blog. The website builds and deploys directly from this repository via GitHub Actions. Docs live in docs/ as the single source of truth. The site is served at praxis.fast through GitHub Pages. - Landing page with animated filter pipeline visualization - Documentation restructured into categories with sidebar icons - Interactive examples page with 82 YAML configs and overlay viewer - Blog with editorial post styling - Local search, responsive design, dark theme - GitHub Actions workflow for automated deployment on push to main Fixes praxis-proxy/praxis-proxy.github.io#1 Signed-off-by: Sébastien Han * fix(ci): fix bash syntax error and regex bug in conventions workflow (#456) Signed-off-by: Sébastien Han --------- Signed-off-by: Sébastien Han Co-authored-by: Shane Utt --- .github/workflows/codeql.yaml | 2 + .github/workflows/conformance.yaml | 2 + .github/workflows/container.yaml | 2 + .github/workflows/conventions.yaml | 3 +- .github/workflows/coverage.yaml | 2 + .github/workflows/documentation.yaml | 2 + .github/workflows/fuzz.yaml | 2 + .github/workflows/integration.yaml | 2 + .github/workflows/microbenchmarks.yaml | 2 + .github/workflows/msrv.yaml | 2 + .github/workflows/supply-chain.yaml | 2 + .github/workflows/tests.yaml | 2 + .github/workflows/website.yaml | 60 + .gitignore | 15 + Makefile | 15 + docs/architecture/_category_.json | 4 + docs/architecture/filter-pipeline.md | 179 + docs/architecture/pingora-integration.md | 151 + docs/architecture/system-design.md | 670 + docs/configuration/_category_.json | 4 + docs/configuration/overview.md | 1233 ++ docs/development/_category_.json | 4 + docs/{ => development}/benchmarks.md | 5 + docs/development/contributing.md | 237 + docs/{ => development}/proposals.md | 7 +- docs/{ => development}/release.md | 5 + docs/development/testing.md | 190 + docs/filters/_category_.json | 4 + docs/filters/custom-filters.md | 457 + docs/filters/filter-model.md | 678 + docs/getting-started/_category_.json | 4 + docs/{ => getting-started}/features.md | 19 +- docs/getting-started/installation.md | 78 + docs/getting-started/introduction.md | 34 + docs/{ => getting-started}/quickstart.md | 15 +- docs/protocols/_category_.json | 4 + docs/protocols/tls.md | 172 + docs/security/_category_.json | 4 + docs/security/hardening.md | 125 + website/.gitignore | 20 + website/README.md | 41 + website/blog/2026-06-02-welcome.md | 21 + website/docusaurus.config.ts | 166 + website/package-lock.json | 19950 ++++++++++++++++++ website/package.json | 50 + website/sidebars.ts | 12 + website/src/css/custom.css | 1180 ++ website/src/data/examples.ts | 619 + website/src/pages/examples/index.module.css | 277 + website/src/pages/examples/index.tsx | 131 + website/src/pages/index.module.css | 631 + website/src/pages/index.tsx | 233 + website/static/.nojekyll | 0 website/static/CNAME | 1 + website/static/img/favicon.ico | Bin 0 -> 64 bytes website/tsconfig.json | 12 + 56 files changed, 27728 insertions(+), 14 deletions(-) create mode 100644 .github/workflows/website.yaml create mode 100644 docs/architecture/_category_.json create mode 100644 docs/architecture/filter-pipeline.md create mode 100644 docs/architecture/pingora-integration.md create mode 100644 docs/architecture/system-design.md create mode 100644 docs/configuration/_category_.json create mode 100644 docs/configuration/overview.md create mode 100644 docs/development/_category_.json rename docs/{ => development}/benchmarks.md (99%) create mode 100644 docs/development/contributing.md rename docs/{ => development}/proposals.md (97%) rename docs/{ => development}/release.md (98%) create mode 100644 docs/development/testing.md create mode 100644 docs/filters/_category_.json create mode 100644 docs/filters/custom-filters.md create mode 100644 docs/filters/filter-model.md create mode 100644 docs/getting-started/_category_.json rename docs/{ => getting-started}/features.md (96%) create mode 100644 docs/getting-started/installation.md create mode 100644 docs/getting-started/introduction.md rename docs/{ => getting-started}/quickstart.md (73%) create mode 100644 docs/protocols/_category_.json create mode 100644 docs/protocols/tls.md create mode 100644 docs/security/_category_.json create mode 100644 docs/security/hardening.md create mode 100644 website/.gitignore create mode 100644 website/README.md create mode 100644 website/blog/2026-06-02-welcome.md create mode 100644 website/docusaurus.config.ts create mode 100644 website/package-lock.json create mode 100644 website/package.json create mode 100644 website/sidebars.ts create mode 100644 website/src/css/custom.css create mode 100644 website/src/data/examples.ts create mode 100644 website/src/pages/examples/index.module.css create mode 100644 website/src/pages/examples/index.tsx create mode 100644 website/src/pages/index.module.css create mode 100644 website/src/pages/index.tsx create mode 100644 website/static/.nojekyll create mode 100644 website/static/CNAME create mode 100644 website/static/img/favicon.ico create mode 100644 website/tsconfig.json diff --git a/.github/workflows/codeql.yaml b/.github/workflows/codeql.yaml index 230782321f..558edfe975 100644 --- a/.github/workflows/codeql.yaml +++ b/.github/workflows/codeql.yaml @@ -7,8 +7,10 @@ name: CodeQL on: push: branches: [ main ] + paths-ignore: ['website/**'] pull_request: branches: [ main ] + paths-ignore: ['website/**'] schedule: - cron: "0 6 * * 1" workflow_dispatch: diff --git a/.github/workflows/conformance.yaml b/.github/workflows/conformance.yaml index a66f5874a2..5c7ec36e99 100644 --- a/.github/workflows/conformance.yaml +++ b/.github/workflows/conformance.yaml @@ -7,8 +7,10 @@ name: Conformance on: push: branches: [main] + paths-ignore: ['website/**'] pull_request: branches: [main] + paths-ignore: ['website/**'] workflow_dispatch: concurrency: diff --git a/.github/workflows/container.yaml b/.github/workflows/container.yaml index b9d2e913c7..4934c55191 100644 --- a/.github/workflows/container.yaml +++ b/.github/workflows/container.yaml @@ -7,8 +7,10 @@ name: Container on: push: branches: [main] + paths-ignore: ['website/**'] pull_request: branches: [main] + paths-ignore: ['website/**'] concurrency: group: ${{ github.workflow }}-${{ github.ref }} diff --git a/.github/workflows/conventions.yaml b/.github/workflows/conventions.yaml index 5eac5526af..87f9b33448 100644 --- a/.github/workflows/conventions.yaml +++ b/.github/workflows/conventions.yaml @@ -8,6 +8,7 @@ on: pull_request_target: branches: [main] types: [opened, synchronize, reopened, ready_for_review] + paths-ignore: ['website/**'] concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number }} @@ -226,7 +227,7 @@ jobs: missing=$(gh api \ "repos/${{ github.repository }}/pulls/${PR_NUMBER}/commits" \ --paginate \ - --jq '[.[] | select(.parents | length == 1) | select(.commit.message | test("(?m)^Signed-off-by: ") | not) | .sha[:7]] | join(", ")') + --jq '[.[] | select(.commit.message | test("(?m)^Signed-off-by: ") | not) | .sha[:7]] | join(", ")') if [ -n "$missing" ]; then marker="" diff --git a/.github/workflows/coverage.yaml b/.github/workflows/coverage.yaml index 7c0abb94ea..03c4283a19 100644 --- a/.github/workflows/coverage.yaml +++ b/.github/workflows/coverage.yaml @@ -7,8 +7,10 @@ name: Coverage on: push: branches: [main] + paths-ignore: ['website/**'] pull_request: branches: [main] + paths-ignore: ['website/**'] workflow_dispatch: concurrency: diff --git a/.github/workflows/documentation.yaml b/.github/workflows/documentation.yaml index 6f6adf2238..7c6f1ceb9d 100644 --- a/.github/workflows/documentation.yaml +++ b/.github/workflows/documentation.yaml @@ -7,8 +7,10 @@ name: Documentation on: push: branches: [main] + paths-ignore: ['website/**'] pull_request: branches: [main] + paths-ignore: ['website/**'] concurrency: group: ${{ github.workflow }}-${{ github.ref }} diff --git a/.github/workflows/fuzz.yaml b/.github/workflows/fuzz.yaml index 3fa6907cda..eba8e48986 100644 --- a/.github/workflows/fuzz.yaml +++ b/.github/workflows/fuzz.yaml @@ -7,8 +7,10 @@ name: Fuzz on: push: branches: [main] + paths-ignore: ['website/**'] pull_request: branches: [main] + paths-ignore: ['website/**'] schedule: - cron: "23 3 * * *" workflow_dispatch: diff --git a/.github/workflows/integration.yaml b/.github/workflows/integration.yaml index 94d361100f..d43b7b750b 100644 --- a/.github/workflows/integration.yaml +++ b/.github/workflows/integration.yaml @@ -7,8 +7,10 @@ name: Tests (Integration) on: push: branches: [main] + paths-ignore: ['website/**'] pull_request: branches: [main] + paths-ignore: ['website/**'] workflow_dispatch: inputs: debug: diff --git a/.github/workflows/microbenchmarks.yaml b/.github/workflows/microbenchmarks.yaml index c60d1ec757..1d4b1cb236 100644 --- a/.github/workflows/microbenchmarks.yaml +++ b/.github/workflows/microbenchmarks.yaml @@ -7,8 +7,10 @@ name: Microbenchmarks on: push: branches: [main] + paths-ignore: ['website/**'] pull_request: branches: [main] + paths-ignore: ['website/**'] concurrency: group: ${{ github.workflow }}-${{ github.ref }} diff --git a/.github/workflows/msrv.yaml b/.github/workflows/msrv.yaml index 5061e263ea..52ba6b0737 100644 --- a/.github/workflows/msrv.yaml +++ b/.github/workflows/msrv.yaml @@ -7,8 +7,10 @@ name: MSRV on: push: branches: [main] + paths-ignore: ['website/**'] pull_request: branches: [main] + paths-ignore: ['website/**'] workflow_dispatch: concurrency: diff --git a/.github/workflows/supply-chain.yaml b/.github/workflows/supply-chain.yaml index f85b13cb7a..9bbed6c0f7 100644 --- a/.github/workflows/supply-chain.yaml +++ b/.github/workflows/supply-chain.yaml @@ -7,8 +7,10 @@ name: Supply Chain on: push: branches: [main] + paths-ignore: ['website/**'] pull_request: branches: [main] + paths-ignore: ['website/**'] workflow_dispatch: concurrency: diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index e774c9d870..ca320414ca 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -7,8 +7,10 @@ name: Tests (Unit) on: push: branches: [main] + paths-ignore: ['website/**'] pull_request: branches: [main] + paths-ignore: ['website/**'] workflow_dispatch: inputs: debug: diff --git a/.github/workflows/website.yaml b/.github/workflows/website.yaml new file mode 100644 index 0000000000..80fa10d22d --- /dev/null +++ b/.github/workflows/website.yaml @@ -0,0 +1,60 @@ +name: Deploy Website + +on: + push: + branches: [main] + paths: + - 'website/**' + - 'docs/**' + - 'examples/**' + - '.github/workflows/website.yml' + workflow_dispatch: + inputs: {} + +concurrency: + group: pages + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: '20' + cache: npm + cache-dependency-path: website/package-lock.json + + - name: Install dependencies + run: cd website && npm ci + + - name: Build website + run: cd website && npm run build + env: + NODE_OPTIONS: '--max-old-space-size=4096' + + - name: Setup Pages + uses: actions/configure-pages@v5 + + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: website/build + + deploy: + runs-on: ubuntu-latest + needs: build + permissions: + pages: write + id-token: write + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index 40b371f7c7..88b238c971 100644 --- a/.gitignore +++ b/.gitignore @@ -38,5 +38,20 @@ docs/**/ !docs/architecture/ !docs/developing/ !docs/filters/ +!docs/getting-started/ +!docs/configuration/ +!docs/protocols/ +!docs/security/ +!docs/development/ !docs/operating/ !docs/proposals/ + +# Docs spec files +docs/superpowers/ + +# Website +website/node_modules/ +website/.docusaurus/ +website/build/ +.superpowers/ +.gstack/ diff --git a/Makefile b/Makefile index a1b3e848c9..706431b380 100644 --- a/Makefile +++ b/Makefile @@ -54,6 +54,7 @@ endif check-prereqs-cmake \ check-prereqs-nightly \ setup-hooks \ + website website-dev \ help # Uses --version rather than command -v so we catch broken installs. @@ -240,6 +241,16 @@ run-echo: run-debug: cargo xtask debug +# ------------------------------------------------------------------- +# Website +# ------------------------------------------------------------------- + +website: ## Build the website + cd website && npm run build + +website-dev: ## Start website dev server + cd website && npm start + # ------------------------------------------------------------------- # Binutils # ------------------------------------------------------------------- @@ -391,3 +402,7 @@ help: @echo "Dev tools:" @echo " run-echo start echo server (xtask)" @echo " run-debug start debug server (xtask)" + @echo "" + @echo "Website:" + @echo " website build the website" + @echo " website-dev start website dev server" diff --git a/docs/architecture/_category_.json b/docs/architecture/_category_.json new file mode 100644 index 0000000000..b7a3ae9db0 --- /dev/null +++ b/docs/architecture/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Architecture", + "position": 2 +} diff --git a/docs/architecture/filter-pipeline.md b/docs/architecture/filter-pipeline.md new file mode 100644 index 0000000000..37256c0bc1 --- /dev/null +++ b/docs/architecture/filter-pipeline.md @@ -0,0 +1,179 @@ +--- +sidebar_position: 2 +title: Filter Pipeline & Branch Chains +--- + +# Filter Pipeline & Branch Chains + +This page covers the filter pipeline execution model, payload processing, +and the condition system that controls filter execution. + +## Filter-First Design + +Every behavior in Praxis is a filter. Built-in filters use the same +traits as user-provided filters. Filters are chained into pipelines; +the pipeline executor calls each filter in order on requests and in +reverse on responses. + +```mermaid +sequenceDiagram + participant C as Client + participant F1 as RequestIdFilter + participant F2 as RouterFilter + participant F3 as HeaderFilter + participant F4 as LoadBalancerFilter + participant U as Upstream + + C ->> F1: request + F1 ->> F2: on_request + F2 ->> F3: on_request (sets ctx.cluster) + F3 ->> F4: on_request + F4 ->> U: on_request (sets ctx.upstream) + + U -->> F4: response + F4 -->> F3: on_response + F3 -->> F2: on_response + F2 -->> F1: on_response + F1 -->> C: response +``` + +Any filter can short-circuit the pipeline by returning a `Reject` action, +which immediately sends a response to the client without continuing +to the next filter or contacting the upstream. + +## Filter Chains + +Filter chains are named, reusable groups of filters defined +at the top level of the config. A listener references one or +more chains by name; the filters are concatenated in order +to form that listener's pipeline. + +```mermaid +flowchart LR + subgraph "Listener: public" + direction LR + S["security chain"] --> O["observability chain"] + O --> R["routing chain"] + end + + subgraph "Listener: internal" + direction LR + O2["observability chain"] --> R2["routing chain"] + end +``` + +This enables reuse without duplication. A "security" chain +can be shared across public listeners while internal +listeners skip it entirely. + +## Payload Processing + +Filters declare body access needs at construction time via +`request_body_access()`, `response_body_access()`, and the +corresponding `*_body_mode()` methods. The pipeline +pre-computes aggregate `BodyCapabilities` at build time so +the protocol layer knows whether to buffer or stream. + +```mermaid +flowchart TD + FA["Filter A: BodyAccess::None"] --> Caps + FB["Filter B: ReadOnly + Stream"] --> Caps + FC["Filter C: ReadOnly + StreamBuffer"] --> Caps + + Caps["BodyCapabilities\nneeds_request_body: true\nrequest_body_mode: StreamBuffer"] + + Caps --> |"accumulate + deliver each chunk"| Proto["Protocol Layer"] + Proto --> |"on Release or EOS: forward buffer"| Upstream +``` + +Two delivery modes: + +- **Stream**: chunks flow through filters as they arrive. + Low latency, low memory. +- **StreamBuffer**: chunks are delivered to filters + incrementally (like Stream) but accumulated in a buffer + and not forwarded to upstream until a filter returns + `FilterAction::Release` or end-of-stream. After release, + remaining chunks flow through in stream mode. No size + limit by default; an optional `max_bytes` returns 413 + when exceeded. Enables streaming inspection with deferred + forwarding for AI inference, Agentic networks, and + Security systems use cases including content scanning, + payload inspection, and body-based routing. + +When StreamBuffer mode is active, the protocol layer +pre-reads the body during the request phase (before +upstream selection) so that body filters can influence +routing decisions. The pre-read body is stored and +forwarded to the upstream after the connection is +established. + +Precedence: `StreamBuffer` > `SizeLimit` > `Stream`. If +any filter requests `StreamBuffer`, the pipeline uses +stream-buffered mode. +Global `body_limits.max_request_bytes` / `body_limits.max_response_bytes` +config limits force buffer mode for size enforcement even +when no filter requests body access. + +The `on_response_body` hook is synchronous (not async) +because Pingora's `response_body_filter` callback is `fn`, +not `async fn`. + +## Filter Condition System + +Filters can be conditionally executed based on request or +response attributes. Each `FilterEntry` carries optional +`conditions` (request phase) and `response_conditions` +(response phase). + +Condition types: + +- **`when`**: execute the filter only if the predicate + matches +- **`unless`**: skip the filter if the predicate matches + +Request predicates: `path`, `path_prefix`, `methods`, +`headers`. Response predicates: `status`, `headers`. All +fields within a predicate use AND semantics; multiple +conditions short-circuit in order. + +Request conditions gate both `on_request` and body hooks. +Response conditions gate only `on_response` and response +body hooks. + +## Branch Chains + +Conditional branching in filter pipelines based on +filter results. Key concepts: + +- **Branch conditions** evaluate filter results to decide + which execution path to take +- **FilterResultSet** stores results from filters without + the filters needing to know about branching +- **Rejoin points** control where branches merge back into + the main pipeline (next filter, terminal, named filter, + or re-entrance with iteration limits) + +The pipeline executor reads results from `FilterResultSet` +to evaluate branch conditions and dispatch to the +appropriate branch. Filters write results to +`FilterResultSet` without knowing about branches, keeping +filter logic decoupled from pipeline flow control. + +## Dynamic Configuration Reload + +Praxis swaps filter pipelines at runtime without +restarting the server or disrupting in-flight requests. + +Each handler holds an `Arc>` +instead of a plain `Arc`. On every +request, the handler calls `pipeline.load()` to get a +snapshot pinned for that request's lifetime. A reload +stores a new pipeline into the `ArcSwap`; the next +request loads the new pointer while in-flight requests +drain on the old one. + +A file watcher (`notify` crate, 500ms debounce) monitors +the config file. On change it validates the new config, +rebuilds all pipelines, and swaps them atomically. If +validation fails, nothing changes. diff --git a/docs/architecture/pingora-integration.md b/docs/architecture/pingora-integration.md new file mode 100644 index 0000000000..bc0bf57c39 --- /dev/null +++ b/docs/architecture/pingora-integration.md @@ -0,0 +1,151 @@ +--- +sidebar_position: 3 +title: Pingora Integration +--- + +# Pingora Integration + +Praxis uses [Pingora](https://github.com/cloudflare/pingora), Cloudflare's +open-source HTTP proxy framework, as the foundation for protocol handling. +This page covers how Praxis integrates with Pingora and the responsibilities +of each layer. + +## Protocol Adapters + +Adapters translate Pingora's callback-based API into Praxis filter pipeline +invocations. When feasible, Praxis owns no protocol logic, instead handing +it off to Pingora's well-maintained and battle-tested implementations. + +```text +HTTP --> praxis-protocol/http --> Pingora +TCP --> praxis-protocol/tcp --> Pingora +QUIC --> praxis-protocol/http3 --> Quiche (planned, not yet implemented) +``` + +These adapters are modular. New protocols can be added by writing new +adapters, and multiple implementations of a single protocol can be swapped +via build features or runtime configuration. + +## PingoraServerRuntime + +`PingoraServerRuntime` wraps the underlying Pingora server. Protocols call +`Protocol::register()` to add their listeners, then the runtime runs all +protocols on a single server. This enables mixed HTTP + TCP listeners in +one process. + +Add new protocols by writing an adapter that implements +`Protocol::register()`. + +## HTTP Connection Lifecycle + +The HTTP adapter maps Pingora's `ProxyHttp` trait callbacks to the Praxis +filter pipeline: + +```mermaid +sequenceDiagram + participant C as Client + participant P as Pingora + participant RF as request_filter + participant BF as request_body_filter + participant UP as upstream_peer + participant B as Backend + participant RSF as response_filter + participant RBF as response_body_filter + + C->>P: TCP + TLS + HTTP decode + P->>RF: request_filter(session, ctx) + RF->>RF: pipeline.execute_http_request() + Note over RF: router sets ctx.cluster
load_balancer sets ctx.upstream + + opt body present + P->>BF: request_body_filter(body, eos) + BF->>BF: buffer or stream through pipeline + end + + P->>UP: upstream_peer(ctx) + UP->>UP: build HttpPeer from ctx.upstream + + opt upstream connect failure + P->>P: fail_to_connect (retry if idempotent) + end + + P->>P: upstream_request_filter (strip hop-by-hop) + P->>B: forward request + B-->>P: response headers + + P->>RSF: response_filter(upstream_response, ctx) + RSF->>RSF: pipeline.execute_http_response() + + loop each body chunk + B-->>P: response body chunk + P->>RBF: response_body_filter(body, eos) + end + + P-->>C: response + P->>P: logging (response-filter cleanup) +``` + +1. TCP accept, TLS handshake, HTTP decode (Pingora) +2. `request_filter`: pipeline runs filters in order; router + sets `ctx.cluster`, load balancer sets `ctx.upstream` +3. `request_body_filter`: buffer or stream body chunks + through filters (if any filter declares body access) +4. `upstream_peer`: converts `ctx.upstream` to `HttpPeer` +5. Connect to upstream; `fail_to_connect` retries + idempotent requests on failure +6. `upstream_request_filter`: strips hop-by-hop headers +7. Request forwarded, response headers received +8. `response_filter`: pipeline runs filters in reverse +9. `response_body_filter`: stream response body through + filters (synchronous; Pingora constraint) +10. `logging`: re-runs response filters if response + phase was skipped (upstream error, filter rejection) +11. Connection returned to pool + +## HTTP Correctness + +A proxy must enforce HTTP invariants that upstream servers +and downstream clients may not. The Praxis project _strongly_ prefers +relying on [Cloudflare](https://cloudflare.com)'s protocol +implementations whenever feasible. + +- For TCP, we rely on [Pingora](https://github.com/cloudflare/pingora) +- For HTTP/1 + HTTP/2, we rely on [Pingora](https://github.com/cloudflare/pingora) +- For QUIC + HTTP/3, we rely on [Quiche](https://github.com/cloudflare/quiche) + +### What Pingora Handles + +Pingora 0.8.x handles several correctness concerns at +the framework level: + +- **Request smuggling**: Content-Length vs + Transfer-Encoding validation per + [RFC 9112](https://datatracker.ietf.org/doc/html/rfc9112). + Invalid Content-Length headers are rejected. Request + body draining before connection reuse. +- **Backpressure**: H2 flow control and bounded H1 + channels between upstream reader and downstream writer. +- **Connection pool safety**: connections are only pooled + when requests complete cleanly. Unconsumed response + bodies cause the connection to be discarded. + +### What Praxis Handles + +- **Hop-by-hop headers**: Praxis strips `Connection`, + `Keep-Alive`, `Transfer-Encoding`, `TE`, `Trailer`, + `Upgrade`, and `Proxy-Authenticate`, plus any custom + headers declared in the `Connection` header value. + Stripping is applied on both request and response paths + per [RFC 9110 Section 7.6.1](https://datatracker.ietf.org/doc/html/rfc9110#section-7.6.1). +- **Host header validation**: Praxis rejects requests + with conflicting `Host` headers (400) and + canonicalizes duplicate identical values. +- **Proxy headers**: Praxis injects `X-Forwarded-For`, + `X-Forwarded-Proto`, and similar headers with + configurable trust boundaries via the `forwarded_headers` + filter. +- **Reserved internal headers**: Praxis uses + `x-praxis-*`, `x-mcp-*`, and `x-a2a-*` prefixes + for proxy-internal routing metadata. +- **Retry safety**: retries only apply to idempotent + requests where no bytes have been written upstream. diff --git a/docs/architecture/system-design.md b/docs/architecture/system-design.md new file mode 100644 index 0000000000..86691e43cf --- /dev/null +++ b/docs/architecture/system-design.md @@ -0,0 +1,670 @@ +--- +sidebar_position: 1 +title: System Design +--- + +# Architecture + +## Design Principles + +**Fast.** Performance is a primary design goal. + +**Secure by default.** Security is a primary design goal. + +**Composable.** Everything is a filter. Routing, load +balancing, rate limiting, AI model selection: all filters, +all using the same traits, all assembled through chains. + +**Extensible.** Your filters implement the same [`HttpFilter`] +and [`TcpFilter`] traits as built-in filters. Register with +one macro. + +**Adaptive.** Praxis is a framework for building proxies, +not just a proxy. Use a provided build out of the box, or +compose a bespoke proxy server from the same primitives. + +[`HttpFilter`]:/docs/filters/filter-model +[`TcpFilter`]:/docs/filters/filter-model + +## Primary Use-Cases + +- **Ingress**: Reverse proxy, API gateway, edge proxy +- **Egress**: Outbound proxy, service-to-service +- **East/West**: Sidecar or converged proxy for service mesh +- **AI Inference**: Proxy for AI inference workloads +- **AI Agents**: Proxy for AI agents +- **Security Gateway**: Guardrails, Network Policy + +## System Architecture + +### Protocol Adapters + +Adapters translate upstream library callbacks into pipeline +invocations. When feasible Praxis owns no protocol logic, +instead handing it off to well-maintained and battle-tested +upstream solutions. + +```text +HTTP --> praxis-protocol/http --> Pingora +TCP --> praxis-protocol/tcp --> Pingora +QUIC --> praxis-protocol/http3 --> Quiche (planned, not yet implemented) +``` + +These adapters are modular, it's intended to enable adding new protocols by +writing new adapters, and even having multiple implementations of a single +protocol that can be swapped via build features or runtime configuration. + +### Filter-First Design + +Every behavior is a filter. Built-in filters use the same +traits as user-provided filters. + +```mermaid +sequenceDiagram + participant C as Client + participant F1 as RequestIdFilter + participant F2 as RouterFilter + participant F3 as HeaderFilter + participant F4 as LoadBalancerFilter + participant U as Upstream + + C ->> F1: request + F1 ->> F2: on_request + F2 ->> F3: on_request (sets ctx.cluster) + F3 ->> F4: on_request + F4 ->> U: on_request (sets ctx.upstream) + + U -->> F4: response + F4 -->> F3: on_response + F3 -->> F2: on_response + F2 -->> F1: on_response + F1 -->> C: response +``` + +Request filters run in declared order, response filters in +reverse. Any filter can short-circuit, and multiple payload +processing options are available to do filtering, routing, +caching and load-balancing based on request or response bodies. + +See [Filter Model](/docs/filters/filter-model) for more extensive documentation on the filter +system, and [Custom Filters](/docs/filters/custom-filters) for how to write your own. + +### Listeners + +```mermaid +flowchart LR + Client -->|TCP| L1["Listener (named)"] + L1 -->|rustls| TLS + TLS --> Resolve["Chain Resolution"] + Resolve --> Pipeline["Filter Pipeline"] + Pipeline --> Pool["Upstream Pool"] + Pool --> Backend + + Config["Config (YAML)"] -. startup .-> Chains + Chains["filter_chains:"] -. per listener .-> Resolve +``` + +Each listener has a `name` and a list of `filter_chains`. +At startup, the referenced chains are resolved and +concatenated into a single pipeline per listener. Different +listeners can compose different subsets of chains. + +### Filters + +Filter chains are named, reusable groups of filters defined +at the top level of the config. A listener references one or +more chains by name; the filters are concatenated in order +to form that listener's pipeline. + +```mermaid +flowchart LR + subgraph "Listener: public" + direction LR + S["security chain"] --> O["observability chain"] + O --> R["routing chain"] + end + + subgraph "Listener: internal" + direction LR + O2["observability chain"] --> R2["routing chain"] + end +``` + +This enables reuse without duplication. A "security" chain +can be shared across public listeners while internal +listeners skip it entirely. + +#### Protocol-Aware Filters + +Filters are protocol-aware. HTTP filters implement the +`HttpFilter` trait (`on_request`, `on_response`, body hooks). +TCP filters implement the `TcpFilter` trait (`on_connect`, +`on_disconnect`). The `AnyFilter` enum wraps both variants +for storage in a unified pipeline. + +Protocol compatibility is enforced via `ProtocolKind::stack()` +and `supports()`. An HTTP listener supports both HTTP and TCP +filters. A TCP listener supports only TCP filters. + +```mermaid +flowchart TD + AnyFilter --> HttpFilter + AnyFilter --> TcpFilter + + HttpListener["HTTP Listener"] -->|supports| HttpFilter + HttpListener -->|supports| TcpFilter + TcpListener["TCP Listener"] -->|supports| TcpFilter +``` + +### What Stays Outside Filters + +- TCP/TLS, HTTP framing, connection pooling: adapters +- Config loading and validation: `praxis-core` +- Pipeline executor and `HttpFilterContext`: `praxis-filter` + +## HTTP Connection Lifecycle + +```mermaid +sequenceDiagram + participant C as Client + participant P as Pingora + participant RF as request_filter + participant BF as request_body_filter + participant UP as upstream_peer + participant B as Backend + participant RSF as response_filter + participant RBF as response_body_filter + + C->>P: TCP + TLS + HTTP decode + P->>RF: request_filter(session, ctx) + RF->>RF: pipeline.execute_http_request() + Note over RF: router sets ctx.cluster
load_balancer sets ctx.upstream + + opt body present + P->>BF: request_body_filter(body, eos) + BF->>BF: buffer or stream through pipeline + end + + P->>UP: upstream_peer(ctx) + UP->>UP: build HttpPeer from ctx.upstream + + opt upstream connect failure + P->>P: fail_to_connect (retry if idempotent) + end + + P->>P: upstream_request_filter (strip hop-by-hop) + P->>B: forward request + B-->>P: response headers + + P->>RSF: response_filter(upstream_response, ctx) + RSF->>RSF: pipeline.execute_http_response() + + loop each body chunk + B-->>P: response body chunk + P->>RBF: response_body_filter(body, eos) + end + + P-->>C: response + P->>P: logging (response-filter cleanup) +``` + +1. TCP accept, TLS handshake, HTTP decode (Pingora) +2. `request_filter`: pipeline runs filters in order; router + sets `ctx.cluster`, load balancer sets `ctx.upstream` +3. `request_body_filter`: buffer or stream body chunks + through filters (if any filter declares body access) +4. `upstream_peer`: converts `ctx.upstream` to `HttpPeer` +5. Connect to upstream; `fail_to_connect` retries + idempotent requests on failure +6. `upstream_request_filter`: strips hop-by-hop headers +7. Request forwarded, response headers received +8. `response_filter`: pipeline runs filters in reverse +9. `response_body_filter`: stream response body through + filters (synchronous; Pingora constraint) +10. `logging`: re-runs response filters if response + phase was skipped (upstream error, filter rejection) +11. Connection returned to pool + +## TCP Connection Lifecycle + +1. TCP accept, optional TLS handshake +2. `on_connect` : TCP filters run in order +3. Bidirectional byte forwarding to upstream +4. `on_disconnect` : TCP filters run on close + +## Dynamic Configuration Reload + +Praxis swaps filter pipelines at runtime without +restarting the server or disrupting in-flight requests. + +Each handler holds an `Arc>` +instead of a plain `Arc`. On every +request, the handler calls `pipeline.load()` to get a +snapshot pinned for that request's lifetime. A reload +stores a new pipeline into the `ArcSwap`; the next +request loads the new pointer while in-flight requests +drain on the old one. + +A file watcher (`notify` crate, 500ms debounce) monitors +the config file. On change it validates the new config, +rebuilds all pipelines, and swaps them atomically. If +validation fails, nothing changes. Health check tasks +are cancelled and respawned with a fresh registry on +each successful reload. + +Changes that cannot be applied dynamically (listener +topology, protocol type, compression module, TLS toggle) +are detected by diffing old and new configs and logged +as warnings. + +## Crate Layout + +### Workspace Crates + +**`praxis`** : Binary entry point. Loads YAML config, resolves +per-listener filter chains into pipelines, registers protocol +handlers, starts the server. Exposes `run_server` and +`init_tracing` for extension binaries. + +**`praxis-core`** : Configuration types (YAML parsing via +serde), validation, error types, upstream connectivity +options, `KvStoreRegistry` (concurrent registry of +dynamic key-value stores with pluggable backends), and +the `PingoraServerRuntime` wrapper. + +**`praxis-filter`** : Filter pipeline engine. Defines the +`HttpFilter` and `TcpFilter` traits, condition evaluation, +body access declarations, the `FilterPipeline` executor, +`FilterRegistry`, and all built-in filter implementations. + +**`praxis-protocol`** : Thin protocol adapters that translate +upstream library callbacks (Pingora) into filter pipeline +invocations. `Protocol` trait, `ListenerPipelines`, HTTP and +TCP implementations. + +**`praxis-proto`** : Vendored Envoy ext_proc protocol buffer +definitions compiled into Rust types with tonic/prost gRPC +stubs. Optional dependency of `praxis-filter` behind the +`ext-proc` cargo feature. + +**`praxis-tls`** : TLS configuration types and runtime +setup. Defines `ListenerTls` (certificate list, client CA, +cert mode), `ClusterTls` (upstream TLS settings), TLS +certificate loading, and SNI-based certificate selection. +Used by `praxis-core` and `praxis-protocol`. + +### Module Tree + +```text +benchmarks Benchmark tool and library +├── error Benchmark error types +├── net Network utilities +├── proxy/ ProxyConfig trait and implementations +│ ├── envoy Envoy proxy adapter +│ ├── haproxy HAProxy adapter +│ ├── nginx NGINX adapter +│ └── praxis Praxis proxy adapter +├── report Comparison report generation +├── result Structured benchmark results +├── runner Test orchestration +├── scenario/ Benchmark scenario definitions +│ ├── settings Scenario settings +│ └── workload Workload definitions +└── tools/ External load generator integrations + ├── fortio Fortio adapter + └── vegeta Vegeta adapter + +praxis Binary entry point +├── pipelines Pipeline resolution from config +├── reload Config reload orchestration (validate, swap, health lifecycle) +├── server Protocol registration, startup +└── watcher File watcher with debounce for config hot-reload + +praxis-core Configuration, errors, and server factory +├── config/ YAML parsing, defaults, and validation +│ ├── bootstrap Config loading with fallback resolution +│ ├── cluster/ Upstream cluster definitions +│ │ ├── endpoint Endpoint address and weight +│ │ ├── health_check Per-cluster active health check settings +│ │ └── load_balancer_strategy Strategy enum (round-robin, least-conn, etc.) +│ ├── condition/ Condition predicates for gating filters +│ │ ├── request Path, method, header predicates +│ │ └── response Status code, header predicates +│ ├── validate/ Post-deserialization validation rules +│ │ ├── cluster/ Cluster config validation +│ │ │ ├── endpoints Endpoint address and weight validation +│ │ │ ├── health_check Health check config validation +│ │ │ ├── timeouts Cluster timeout validation +│ │ │ └── tls Cluster TLS config validation +│ │ ├── listener/ Listener config validation +│ │ │ ├── address Bind address validation +│ │ │ ├── rules Listener-level validation rules +│ │ │ └── timeouts Listener timeout validation +│ │ ├── filter_chain Filter chain reference validation +│ │ └── rules Top-level validation orchestration +│ ├── admin Admin endpoint address and options +│ ├── body_limits Global max request/response byte limits +│ ├── filters FilterChainConfig and FilterEntry structs +│ ├── insecure_options Security override flags for development +│ ├── listener Bind address, protocol, TLS, chain refs +│ ├── parse YAML safety checks (size, alias expansion) +│ ├── route Route definitions for router filter +│ └── runtime Worker threads, work-stealing, log overrides +├── connectivity/ Upstream connection types +│ ├── connection_options Timeouts, pool sizes, TLS settings +│ ├── network CIDR range matching and IP normalization +│ └── upstream Upstream address representation +├── errors ProxyError (shared workspace error type) +├── health Shared health state types for active health checking +├── kv/ Key-value store trait and registry +│ └── memory In-memory backend (DashMap) +├── logging Tracing subscriber setup +└── server/ Server factory and lifecycle + ├── pingora Pingora server configuration + └── runtime PingoraServerRuntime wrapper and options + +praxis-filter Filter pipeline engine +├── actions FilterAction: continue or reject +├── any_filter AnyFilter enum (Http | Tcp wrapper) +├── body/ Body access declarations and buffering +│ ├── access BodyAccess enum +│ ├── buffer BodyBuffer and overflow handling +│ ├── builder Pre-computed BodyCapabilities +│ └── mode BodyMode enum (Stream, StreamBuffer, SizeLimit) +├── condition/ Condition evaluation for filter gating +│ ├── request Request condition evaluation +│ └── response Response condition evaluation +├── context Transport-agnostic Request/Response types +├── factory FilterFactory enum (Http/Tcp) and utilities +├── filter HttpFilter trait and HttpFilterContext +├── tcp_filter TcpFilter trait and TcpFilterContext +├── registry FilterRegistry: name -> factory map +├── pipeline/ Pipeline execution engine +│ ├── body Body chunk processing and buffer management +│ ├── build Pipeline construction and body capability computation +│ ├── checks Pipeline validation (protocol compatibility) +│ ├── clusters Cluster reference collection from filters +│ ├── http HTTP request/response/body pipeline +│ ├── http_utils Shared HTTP pipeline utilities +│ ├── tcp TCP connect/disconnect pipeline +│ └── tests Pipeline unit tests +└── builtins/ Built-in filter implementations + ├── http/ HTTP protocol filters + │ ├── ai/ AI filters for HTTP workloads + │ │ ├── agentic/ Agentic protocol classifiers + │ │ │ ├── json_rpc JSON-RPC 2.0 envelope parsing and metadata extraction + │ │ │ └── mcp MCP protocol classifier and metadata extraction + │ │ ├── inference/ Model routing and prompt enrichment + │ │ │ └── model_to_header Extract model field, promote to header + │ │ └── prompt_enrich Inject messages into chat completion bodies + │ ├── net Shared IP utilities (IPv4-mapped normalization) + │ ├── observability/ + │ │ ├── access_log Structured JSON request/response logging + │ │ └── request_id Correlation ID generation/propagation + │ ├── payload_processing/ + │ │ ├── compression Gzip/brotli/zstd response compression + │ │ └── json_body_field Extract JSON field, promote to header + │ ├── security/ + │ │ ├── cors CORS preflight handling, origin validation + │ │ ├── credential_injection Per-cluster API key injection + │ │ ├── csrf CSRF protection via origin validation + │ │ ├── forwarded_headers X-Forwarded-For/Proto/Host injection + │ │ ├── guardrails Reject requests matching string/regex rules + │ │ └── ip_acl Allow/deny by source IP/CIDR + │ ├── traffic_management/ + │ │ ├── circuit_breaker Per-cluster circuit breaking (closed/open/half-open) + │ │ ├── rate_limit Token bucket rate limiting (per-IP, global) + │ │ ├── router Path-prefix + host routing to clusters + │ │ ├── redirect 3xx redirect without upstream + │ │ ├── static_response Fixed status/headers/body (no upstream) + │ │ ├── timeout 504 if response exceeds configured ms + │ │ └── load_balancer/ Weighted endpoint selection + │ │ ├── round_robin Round-robin strategy + │ │ ├── least_connections Least-connections strategy + │ │ └── consistent_hash Consistent-hash strategy + │ └── transformation/ + │ ├── header Add/set/remove request/response headers + │ ├── path_rewrite Strip/add prefix or regex replace on paths + │ └── url_rewrite Regex path transform + query manipulation + └── tcp/ TCP protocol filters + ├── observability/ + │ └── tcp_access_log Structured JSON connection logging + └── traffic_management/ + ├── sni_router SNI-based upstream routing + └── tcp_load_balancer Cluster-backed TCP endpoint selection + +praxis-proto Envoy ext_proc protobuf definitions (opt-in via ext-proc feature) +├── envoy/service/common/v3 Common Envoy service types +└── envoy/service/ext_proc/v3 External processor gRPC service + +praxis-protocol Protocol adapters +├── pipelines Maps listener names to resolved pipelines +├── http/ HTTP (Pingora) +│ └── pingora/ Pingora ProxyHttp integration +│ ├── context Per-request state through lifecycle hooks +│ ├── convert Pingora <-> Praxis type conversions +│ ├── health/ Active health checking +│ │ ├── probe HTTP and TCP health check probe functions +│ │ ├── runner Background health check runner +│ │ └── service Admin health-check service (/ready, /healthy) +│ ├── json JSON HTTP response builder +│ ├── kv KV store admin CRUD endpoints +│ ├── listener TCP/TLS listener setup +│ └── handler/ Request/response lifecycle hooks +│ ├── hop_by_hop Shared hop-by-hop header stripping logic +│ ├── no_body ProxyHttp impl without body filter hooks +│ ├── with_body ProxyHttp impl with body filter hooks +│ ├── request_filter/ Pipeline execution on request +│ │ ├── stream_buffer Pre-read logic for StreamBuffer mode +│ │ └── validation Host header validation, Max-Forwards +│ ├── request_body_filter Body chunk processing (request) +│ ├── response_filter Pipeline execution on response +│ ├── response_body_filter Body chunk processing (response) +│ ├── upstream_peer Build HttpPeer from filter context +│ ├── upstream_request Request-path hop-by-hop stripping +│ ├── upstream_response Response-path hop-by-hop stripping +│ └── via Via header injection +├── tcp/ L4 bidirectional forwarding +│ ├── proxy Bidirectional TCP proxy application +│ └── tls_setup TLS configuration and listener grouping + +praxis-tls TLS configuration types and setup +├── client_auth Client certificate authentication mode +├── config/ TLS configuration structs +│ ├── certs CaConfig and CertKeyPair types +│ ├── cluster ClusterTls upstream TLS settings +│ └── listener ListenerTls: cert list, client CA, cert mode +├── error TlsError type +├── setup/ TLS runtime setup +│ ├── loader Certificate and key loading from disk +│ └── sni SNI-based certificate selection +└── sni ClientHello SNI parser for TCP routing + +xtask Developer task runner (cargo xtask) +├── benchmark/ Benchmark orchestration +│ ├── cli CLI argument parsing +│ ├── compare Comparison logic +│ ├── flamegraph Flamegraph generation +│ ├── orchestrate Test orchestration +│ ├── proxy Proxy configuration +│ ├── report Report generation +│ ├── resolve Resolution logic +│ └── visualize Result visualization +├── debug Debug utilities +├── echo Echo server for testing +└── port Free port allocation +``` + +### Dependency Graph + +```mermaid +graph LR + praxis --> praxis-protocol + praxis --> praxis-filter + praxis --> praxis-core + praxis-protocol --> praxis-filter + praxis-protocol --> praxis-core + praxis-protocol --> praxis-tls + praxis-filter --> praxis-core + praxis-filter -.->|ext-proc| praxis-proto + praxis-core --> praxis-tls +``` + +### Startup Sequence + +```mermaid +sequenceDiagram + participant M as main() + participant C as Config + participant R as FilterRegistry + participant LP as ListenerPipelines + participant S as PingoraServerRuntime + + M->>C: Config::load(path, fallback_yaml) + C->>C: serde_yaml → Config{listeners, filter_chains, clusters} + C->>C: validate() (listeners, chains, clusters) + M->>M: init_tracing(&config) + M->>R: FilterRegistry::with_builtins() + Note right of R: name → FilterFactory::Http | Tcp + M->>M: KvStoreRegistry::new() + Note right of M: dynamic, on-demand store creation + + Note over M,LP: resolve_pipelines(&config, ®istry) + M->>M: index filter_chains: HashMap + loop each Listener + M->>M: look up listener.filter_chains, flatten → Vec + M->>R: registry.create(type, yaml) per entry → AnyFilter + M->>M: FilterPipeline{Vec, BodyCapabilities} + M->>M: apply_body_limits(max_req, max_resp) + M->>M: pipeline.set_kv_stores(kv_registry) + M->>LP: insert(listener.name, Arc) + end + + M->>S: PingoraServerRuntime::new(&config) + S->>S: Pingora Server::new + bootstrap() + + opt HTTP listeners present + M->>S: PingoraHttp.register(server, config, pipelines) + S->>S: per listener: bind + PingoraHttpHandler(pipeline) + end + + opt TCP listeners present + M->>S: PingoraTcp.register(server, config, pipelines) + S->>S: per listener: bind + PingoraTcpProxy(pipeline) + end + + M->>S: server.run() (blocks forever) +``` + +Configuration resolves through three phases. First, +YAML is deserialized into `Config` containing +`Vec`, `Vec`, and +`Vec`, then validated. +Second, `resolve_pipelines` indexes chains by name, then +per listener flattens its named chains into +`FilterEntry` values, instantiates each via the registry +into `AnyFilter`, and assembles a `FilterPipeline` with +pre-computed `BodyCapabilities`. All pipelines collect +into `ListenerPipelines` (listener name → +`Arc`). Third, protocol implementations +bind sockets per listener, attaching handlers that hold +a reference to the listener's resolved pipeline. + +### PingoraServerRuntime + +`PingoraServerRuntime` wraps the underlying Pingora server. Protocols call +`Protocol::register()` to add their listeners, then the +runtime runs all protocols on a single server. This enables +mixed HTTP + TCP listeners in one process. + +Add new protocols by writing an adapter that implements +`Protocol::register()`. Contribute missing capabilities +upstream. + +## HTTP Correctness + +A proxy must enforce HTTP invariants that upstream servers +and downstream clients may not. These are critical +correctness and security concerns. + +The Praxis project _strongly_ prefers relying on +[Cloudflare]'s protocol implementations whenever feasible. +Praxis is modular, so it is possible to swap in other +implementations, but Cloudflare has a good track record of +providing correct, hardened and high performance protocol +implementations which are battle-tested with years of +production experience. + +- For TCP, we rely on [Pingora] +- For HTTP/1 + HTTP/2, we rely on [Pingora] +- For QUIC + HTTP/3, we rely on [Quiche] + +[Cloudflare]: https://cloudflare.com +[Pingora]: https://github.com/cloudflare/pingora +[Quiche]: https://github.com/cloudflare/quiche + +### What Pingora handles + +Pingora 0.8.x handles several correctness concerns at +the framework level: + +- **Request smuggling**: Content-Length vs + Transfer-Encoding validation per + [RFC 9112](https://datatracker.ietf.org/doc/html/rfc9112). + Invalid Content-Length headers are rejected. Request + body draining before connection reuse. +- **Backpressure**: H2 flow control and bounded H1 + channels between upstream reader and downstream writer. +- **Connection pool safety**: connections are only pooled + when requests complete cleanly. Unconsumed response + bodies cause the connection to be discarded. + +### What Praxis handles + +- **Hop-by-hop headers**: Pingora does not strip + hop-by-hop headers on the H1-to-H1 path. Praxis + strips `Connection`, `Keep-Alive`, + `Transfer-Encoding`, `TE`, `Trailer`, `Upgrade`, + and `Proxy-Authenticate`, plus any custom headers + declared in the `Connection` header value. + `Proxy-Authorization` is stripped on the request + path only (it is request-specific per RFC 9110). + Stripping is applied on both request + (`upstream_request_filter`) and response + (`response_filter`) paths per + [RFC 9110 Section 7.6.1]. +- **Host header validation**: Praxis rejects requests + with conflicting `Host` headers (400) and + canonicalizes duplicate identical values. Missing + `Host` on HTTP/1.1 is rejected per + [RFC 9112](https://datatracker.ietf.org/doc/html/rfc9112). +- **Proxy headers**: Pingora adds no `X-Forwarded-For`, + `X-Forwarded-Proto`, or similar headers. Praxis + injects these with configurable trust boundaries + via the `forwarded_headers` filter. +- **Reserved internal headers**: Praxis uses + `x-praxis-*`, `x-mcp-*`, and `x-a2a-*` prefixes + for proxy-internal routing metadata (e.g. + body-derived fields promoted to headers). These are + rejected from client requests (400), stripped before + forwarding to backends, and stripped from backend + responses before reaching clients. +- **Retry safety**: retries must only apply to idempotent + requests where no bytes have been written upstream. + +[RFC 9110 Section 7.6.1]:https://datatracker.ietf.org/doc/html/rfc9110#section-7.6.1 + +## Test Structure + +All crates have unit tests, but the `tests/` directory contains +integration, conformance and other test suites that operate at +a higher level and across multiple crates. + +| Crate | Purpose | +| ------- | --------- | +| `tests/schema` | Config parsing and example validation | +| `tests/conformance` | RFC conformance (h2spec, HTTP semantics) | +| `tests/integration` | End-to-end filter and proxy tests | +| `tests/resilience` | Load, failure recovery, throughput | +| `tests/security` | Request smuggling, header injection | +| `tests/smoke` | Quick startup and round-trip sanity | diff --git a/docs/configuration/_category_.json b/docs/configuration/_category_.json new file mode 100644 index 0000000000..918fb7cfe5 --- /dev/null +++ b/docs/configuration/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Configuration", + "position": 3 +} diff --git a/docs/configuration/overview.md b/docs/configuration/overview.md new file mode 100644 index 0000000000..71cc3c6e7d --- /dev/null +++ b/docs/configuration/overview.md @@ -0,0 +1,1233 @@ +--- +sidebar_position: 1 +title: Overview +--- + +# Configuration + +Single YAML file, passed as CLI argument or set via the +`PRAXIS_CONFIG` environment variable. See +[example configs](https://github.com/praxis-proxy/praxis/tree/main/examples/configs) for working examples. + +## Structure + +```yaml +listeners: # Required. Named listeners to bind. +filter_chains: # Named, reusable filter chains. +clusters: # Optional. Standalone cluster defs (health checks). +admin: # Optional. Admin health endpoint. +body_limits: # Optional. Global body size ceilings. +runtime: # Optional. Thread pool and logging tuning. +shutdown_timeout_secs: # Optional. Graceful drain time (default: 30). +insecure_options: # Optional. Dev/test overrides. See development.md. +``` + +## Validating Configuration + +Use `--validate` (or `-t`) to check configuration +without starting the server. The flag loads the config +through the same parsing and validation path used +during startup, including filter pipeline construction +and ordering checks. + +```console +praxis --validate --config praxis.yaml +praxis -t -c praxis.yaml +``` + +Exits `0` on success (no output). Exits non-zero and +prints an error to stderr on failure. Does not bind +listener ports or enter the server runtime. + +## Dumping Effective Configuration + +Use `--dump` (or `-T`) to validate and dump the +effective parsed configuration as YAML to stdout. The +output includes the effective parsed config (with +defaults applied) plus resolved top-level listener +chains. + +```console +praxis --dump --config praxis.yaml +praxis -T -c praxis.yaml +``` + +Exits `0` on valid config, writing YAML to stdout. +Exits non-zero and writes errors to stderr on failure. +Does not start the proxy or bind listeners. `--dump` +and `--validate` are mutually exclusive. + +## Dynamic Configuration Reload + +Praxis watches the config file for changes and +automatically reloads filter pipelines without restart +or disruption. When the file is modified, the server +validates the new config, rebuilds pipelines, and swaps +them atomically. In-flight requests complete on the old +pipeline; new requests pick up the new config. + +If the new config is invalid (bad YAML, unknown filter, +validation failure), the server logs the error and +continues serving with the old config. + +**Dynamically reloadable:** + +- Filter pipeline configuration +- Router routes and path mappings +- Load balancer endpoints and weights +- Rate limit and circuit breaker settings +- Health check configuration + +**Requires restart (logged as warning):** + +- Listener add, remove, or address rebind +- Protocol changes (HTTP to TCP) +- Compression module addition +- TLS enable/disable + +Stateful filters (rate limiter, circuit breaker) reset +their state on reload. Operators should expect a brief +burst window for rate limiters and a closed circuit for +circuit breakers immediately after reload. + +See [hot-reload.yaml](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/operations/hot-reload.yaml) for an example. + +## Admin + +`admin.address` binds a separate HTTP listener that serves +`/healthy`, `/ready`, and `/metrics`. + +- `/healthy` returns `200 OK` with `{"status":"ok"}` + once the server is accepting connections (liveness). +- `/ready` returns per-cluster health status with + healthy/unhealthy/total counts when active health + checks are configured; it returns `503 SERVICE UNAVAILABLE` when any + cluster has zero healthy endpoints. Without health + checks, `/ready` returns `{"status":"ok"}`. +- `/metrics` returns Prometheus text exposition format + with HTTP request metrics (`praxis_http_requests_total`, + `praxis_http_request_duration_seconds`). + +Any other path returns `404 NOT FOUND`. Useful for orchestrator +health checks and monitoring without exposing them on +the main listeners. + +```yaml +admin: + address: "127.0.0.1:9901" +``` + +When `admin.verbose: true`, the `/ready` response +includes per-cluster detail (cluster names, health +counts). Default is `false` to avoid leaking internal +topology. + +```yaml +admin: + address: "127.0.0.1:9901" + verbose: true +``` + +By default, binding admin to a public interface +(`0.0.0.0` / `[::]`) is a validation error. + +## Annotated Example + +```yaml +listeners: + - name: web + address: "0.0.0.0:8080" + filter_chains: + - observability + - routing + +filter_chains: + - name: observability + filters: + - filter: request_id + - filter: access_log + + - name: routing + filters: + - filter: router + routes: + - path_prefix: "/api/" + cluster: api + - path_prefix: "/" + cluster: web + - filter: load_balancer + clusters: + - name: api + endpoints: ["127.0.0.1:4000"] + - name: web + endpoints: # multi-line form + - "127.0.0.1:3000" # (equivalent to inline + - "127.0.0.1:3001" # array above) +``` + +## Listeners + +Each listener has a required `name`, an `address`, optional +`tls`, optional `protocol` (defaults to `http`), and an +optional list of `filter_chains` to apply. When +`filter_chains` is omitted it defaults to empty (no filters +applied). + +```yaml +listeners: + - name: public + address: "0.0.0.0:80" + filter_chains: [main] + + - name: secure + address: "0.0.0.0:443" + filter_chains: [main] + tls: + certificates: + - cert_path: /etc/praxis/tls/cert.pem + key_path: /etc/praxis/tls/key.pem +``` + +The `name` field uniquely identifies the listener and is +used to resolve its pipeline at startup. + +### Network Binding + +Binding to `0.0.0.0` or `[::]` exposes the listener +on all network interfaces. For local development, +prefer `127.0.0.1`. In production, bind to specific +internal IPs and use firewall rules to restrict +access. The default configuration binds to +`127.0.0.1:8080` as a security precaution. + +### TCP Listeners + +TCP listeners set `protocol: tcp` and require an `upstream` +address. Filter chains are optional for TCP listeners. + +```yaml +listeners: + - name: postgres + address: "0.0.0.0:5432" + protocol: tcp + upstream: "10.0.0.1:5432" +``` + +Optional `tcp_idle_timeout_ms` closes connections that have +been idle longer than the specified duration: + +```yaml +listeners: + - name: postgres + address: "0.0.0.0:5432" + protocol: tcp + upstream: "10.0.0.1:5432" + tcp_idle_timeout_ms: 300000 # 5 minutes +``` + +Optional `tcp_max_duration_secs` caps the total session +duration regardless of activity: + +```yaml +listeners: + - name: postgres + address: "0.0.0.0:5432" + protocol: tcp + upstream: "10.0.0.1:5432" + tcp_max_duration_secs: 3600 # 1 hour +``` + +### Downstream Read Timeout + +Optional `downstream_read_timeout_ms` sets how long the +proxy waits for data from downstream clients during body +reads. Mitigates slow-body attacks on HTTP listeners. + +```yaml +listeners: + - name: web + address: "0.0.0.0:8080" + downstream_read_timeout_ms: 10000 # 10 seconds + filter_chains: [main] +``` + +Pingora applies its own 60s default for initial request +header reads on fresh connections. This setting controls +body read timeouts within an active request. + +### Max Connections + +Optional `max_connections` caps concurrent connections +per listener. HTTP listeners reject excess requests +with `503 Service Unavailable` and a `Retry-After: 1` +header. TCP listeners close the socket immediately. + +```yaml +listeners: + - name: public + address: "0.0.0.0:8080" + max_connections: 10000 + filter_chains: [main] +``` + +The limit is enforced via a per-listener semaphore. +Permits are held for the request lifetime (HTTP) or +connection lifetime (TCP) and released automatically on +completion, error, or timeout. Each listener has an +independent limit. + +See [max-connections.yaml](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/operations/max-connections.yaml) for an example. + +### Mixed Protocols + +HTTP and TCP listeners can run on a single server instance. +Each listener gets its own filter chains appropriate to its +protocol. + +```yaml +listeners: + - name: web + address: "0.0.0.0:8080" + filter_chains: [routing] + + - name: db + address: "0.0.0.0:5432" + protocol: tcp + upstream: "10.0.0.1:5432" +``` + +See [TLS & mTLS](/docs/protocols/tls) for TLS details. + +## Filter Chains + +Named filter chains are defined at the top level. Each chain +has a `name` and an ordered list of `filters`. Listeners +reference chains by name via `filter_chains:`. + +```yaml +filter_chains: + - name: security + filters: + - filter: headers + response_set: + - name: "X-Content-Type-Options" + value: "nosniff" + + - name: observability + filters: + - filter: request_id + - filter: access_log + + - name: routing + filters: + - filter: router + routes: + - path_prefix: "/" + cluster: backend + - filter: load_balancer + clusters: + - name: backend + endpoints: ["10.0.0.1:8080"] +``` + +### Chain Composition + +A listener can reference multiple chains. The filters from +each chain are concatenated in order to form the listener's +complete pipeline. This enables reuse without duplication. + +```yaml +listeners: + - name: public + address: "0.0.0.0:8080" + filter_chains: + - security + - observability + - routing + + - name: internal + address: "0.0.0.0:9090" + filter_chains: + - observability + - routing +``` + +The public listener runs security + observability + routing. +The internal listener skips security but shares the same +observability and routing chains. + +### Protocol Compatibility + +Filters are protocol-aware. HTTP filters (e.g. `router`, +`load_balancer`) only work on HTTP listeners. TCP filters +(e.g. `tcp_access_log`) work on both HTTP and TCP listeners. +An HTTP listener's protocol stack includes TCP, so it +supports TCP-level filters too. + +## Built-in Filters + +| Filter | Category | Protocol | +| --- | --- | --- | +| `router` | Traffic Management | HTTP | +| `load_balancer` | Traffic Management | HTTP | +| `timeout` | Traffic Management | HTTP | +| `static_response` | Traffic Management | HTTP | +| `rate_limit` | Traffic Management | HTTP | +| `circuit_breaker` | Traffic Management | HTTP | +| `headers` | Transformation | HTTP | +| `request_id` | Observability | HTTP | +| `access_log` | Observability | HTTP | +| `tcp_access_log` | Observability | TCP | +| `forwarded_headers` | Security | HTTP | +| `guardrails` | Security | HTTP | +| `ip_acl` | Security | HTTP | +| `credential_injection` | Security | HTTP | +| `a2a` | Payload Processing | HTTP | +| `json_body_field` | Payload Processing | HTTP | +| `json_rpc` | Payload Processing | HTTP | +| `mcp` | Payload Processing | HTTP | +| `compression` | Payload Processing | HTTP | +| `cors` | Security | HTTP | +| `csrf` | Security | HTTP | +| `redirect` | Traffic Management | HTTP | +| `path_rewrite` | Transformation | HTTP | +| `url_rewrite` | Transformation | HTTP | +| `sni_router` | Traffic Management | TCP | +| `tcp_load_balancer` | Traffic Management | TCP | +| `model_to_header` | AI / Inference | HTTP (requires `ai-inference` feature) | +| `prompt_enrich` | AI / Inference | HTTP (requires `ai-inference` feature) | + +### Router + +Routes requests to clusters by path prefix. Longest prefix +wins. Optional `host` restricts matching to a specific +`Host` header. Optional `headers` restricts matching to +requests with all specified header values present (AND +semantics, case-sensitive). Routes without `host` match +any host. + +Example configs: [path-based-routing.yaml](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/traffic-management/path-based-routing.yaml), +[hosts.yaml](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/traffic-management/hosts.yaml), [canary-routing.yaml](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/traffic-management/canary-routing.yaml). + +### Load Balancing + +Strategies: + +- `round_robin` (default): cycles through endpoints +- `least_connections`: picks endpoint with fewest active + requests +- `consistent_hash`: hashes a request header (or URI path + as fallback) to pin requests to stable endpoints + +Example configs: [weighted-load-balancing.yaml](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/traffic-management/weighted-load-balancing.yaml), +[least-connections.yaml](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/traffic-management/least-connections.yaml), [session-affinity.yaml](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/traffic-management/session-affinity.yaml). + +Cluster-level options: `connection_timeout_ms`, +`total_connection_timeout_ms`, `idle_timeout_ms`, +`read_timeout_ms`, `write_timeout_ms`, `tls`. + +`total_connection_timeout_ms` sets the combined budget for +TCP connect and TLS handshake. When used alongside +`connection_timeout_ms`, the difference is effectively the +TLS handshake budget. It must be >= `connection_timeout_ms`. + +Cluster `tls` enables TLS to the upstream. See +[TLS & mTLS](/docs/protocols/tls) for full details on upstream TLS, mTLS, +CA trust, and certificate verification. + +#### Health Checks + +Clusters support active health checks via the +`health_check` field. Endpoints that fail consecutive +probes are removed from load balancer rotation until they +recover. See [health-checks.yaml](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/traffic-management/health-checks.yaml). + +| Field | Type | Default | Description | +| ----- | ---- | ------- | ----------- | +| `type` | string | required | `"http"` or `"tcp"` (`"grpc"` parses but is not yet supported) | +| `path` | string | `"/"` | HTTP path to probe (HTTP only) | +| `expected_status` | integer | 200 | Expected HTTP status code | +| `interval_ms` | integer | 5000 | Probe interval in ms | +| `timeout_ms` | integer | 2000 | Per-probe timeout in ms | +| `healthy_threshold` | integer | 2 | Consecutive successes to mark healthy | +| `unhealthy_threshold` | integer | 3 | Consecutive failures to mark unhealthy | +| `passive_unhealthy_threshold` | integer | none | Consecutive upstream failures (5xx or connect error) to mark unhealthy without probes | +| `passive_healthy_threshold` | integer | none | Consecutive upstream successes to recover a passively-marked endpoint | + +TCP health checks only verify a TCP connection can be +established; `path` and `expected_status` are ignored. +When active health checks are configured, the admin +`/ready` endpoint reports per-cluster health counts. + +Passive health checking tracks upstream request +outcomes inline. When `passive_unhealthy_threshold` is +set, endpoints that return consecutive 5xx responses or +connect errors are marked unhealthy without dedicated +probe traffic. Set `passive_healthy_threshold` to +control how many consecutive successes are required to +recover. Passive and active checks can be used together; +either mechanism can mark an endpoint unhealthy, and +either can recover it. + +By default, health check endpoints that resolve to +loopback, link-local, or cloud metadata addresses are +rejected (SSRF protection). + +### Headers + +Add headers to requests; add, set, or remove headers on +responses: + +```yaml +- filter: headers + request_add: + - name: "X-Forwarded-Proto" + value: "https" + response_add: + - name: "X-Served-By" + value: "praxis" + response_set: + - name: "Server" + value: "praxis" + response_remove: + - "X-Powered-By" +``` + +`add` appends (preserves existing), `set` replaces, +`remove` deletes. Request headers support `add` only. +Response headers support all three operations. + +### Timeout + +Returns 504 if upstream response exceeds configured duration: + +```yaml +- filter: timeout + timeout_ms: 5000 +``` + +### Request ID + +Propagates an existing request ID header or generates a +new one: + +```yaml +- filter: request_id + header_name: "X-Request-Id" # optional, this is the default +``` + +### Access Log + +Structured JSON logging of method, path, status, and +timing: + +```yaml +- filter: access_log +``` + +Optional sampling to reduce log volume: + +```yaml +- filter: access_log + sample_rate: 0.1 # log ~10% of requests +``` + +### Forwarded Headers + +Injects `X-Forwarded-For`, `X-Forwarded-Proto`, and +`X-Forwarded-Host` into upstream requests: + +```yaml +- filter: forwarded_headers + trusted_proxies: + - "10.0.0.0/8" + - "172.16.0.0/12" +``` + +When the client IP is from a trusted proxy, existing +`X-Forwarded-For` values are preserved. Otherwise, the +header is overwritten to prevent spoofing. + +### IP ACL + +Allow or deny requests by source IP/CIDR: + +```yaml +- filter: ip_acl + allow: + - "10.0.0.0/8" +``` + +Use either `allow` or `deny`, not both (mutually +exclusive). When `allow` is set, only matching IPs are +permitted (implicit deny-all). Denied requests receive +a `403 Forbidden` response. + +### Credential Injection + +Injects per-cluster API credentials into upstream +requests and strips client-provided credentials to +prevent forwarding. Pair with a source discriminator +(IP ACL, client authentication) to control which +clients receive credential upgrades. See +[credential-injection.yaml](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/ai/credential-injection.yaml). + +```yaml +- filter: credential_injection + clusters: + - name: openai + header: Authorization + value: "sk-example-key" + header_prefix: "Bearer " + strip_client_credential: true +``` + +| Field | Type | Required | Description | +| ----- | ---- | -------- | ----------- | +| `clusters[].name` | string | yes | Cluster to inject credentials for | +| `clusters[].header` | string | yes | Header name to set | +| `clusters[].value` | string | one of | Inline credential value | +| `clusters[].env_var` | string | one of | Environment variable containing the credential | +| `clusters[].header_prefix` | string | no | Prefix prepended to the value (e.g. `"Bearer "`) | +| `clusters[].strip_client_credential` | bool | no | Remove client-sent value before injection (default: true) | + +### TCP Access Log + +Structured JSON logging of TCP connections. Works on both +TCP and HTTP listeners: + +```yaml +- filter: tcp_access_log +``` + +### SNI Router + +Routes TLS connections to upstream addresses based on +the SNI hostname from the TLS ClientHello. Supports +exact matches and wildcard patterns (e.g. +`*.example.com`). Performs exact-match lookup first, +then longest-suffix wildcard match. Matching is +case-insensitive per RFC 4343. + +```yaml +- filter: sni_router + routes: + - server_names: ["api.example.com"] + upstream: "10.0.0.1:443" + - server_names: ["*.example.com"] + upstream: "10.0.0.2:443" + default_upstream: "10.0.0.3:443" +``` + +| Field | Type | Required | Description | +| ----- | ---- | -------- | ----------- | +| `routes` | list | yes | SNI route entries | +| `routes[].server_names` | list | yes | Exact or wildcard hostnames | +| `routes[].upstream` | string | yes | Upstream address for matches | +| `default_upstream` | string | no | Fallback when no route matches | + +Connections without SNI or with no matching route use +`default_upstream` if configured, otherwise receive a +421 rejection. Bare wildcards (`*`), IP addresses as +server names, and duplicate server names across routes +are rejected at config validation. + +### TCP Load Balancer + +Selects an upstream TCP endpoint from a cluster using +the configured load-balancing strategy. Reads +`ctx.cluster` to find the target cluster, selects an +endpoint, and writes `ctx.upstream_addr`. Supports +round-robin (default), least-connections, and +consistent-hash strategies. + +```yaml +- filter: tcp_load_balancer + clusters: + - name: db_pool + endpoints: + - "10.0.0.1:5432" + - "10.0.0.2:5432" +``` + +Weighted endpoints and strategy selection follow the +same syntax as the HTTP `load_balancer` filter. Health +check integration is supported; if all endpoints are +unhealthy, the filter enters panic mode and routes to +all endpoints. + +### JSON Body Field + +Extracts a top-level field from a JSON request body and +promotes its value to a request header. Uses StreamBuffer +mode to inspect the body before upstream selection, +enabling body-based routing. + +```yaml +- filter: json_body_field + field: model + header: X-Model +``` + +`field` is the JSON key to extract. `header` is the +request header name to promote the value into. If the +field is missing or the body is not valid JSON, the +filter passes through without modification. + +### JSON-RPC + +Parses JSON-RPC 2.0 request bodies and promotes +method, id, and message kind to request headers for +routing. Uses StreamBuffer mode to inspect the body +before upstream selection. + +```yaml +- filter: json_rpc + max_body_bytes: 1048576 + batch_policy: reject + on_invalid: continue +``` + +| Field | Type | Default | Description | +| ----- | ---- | ------- | ----------- | +| `max_body_bytes` | integer | 1048576 | Maximum body size to buffer (1 MiB) | +| `batch_policy` | string | `"reject"` | `"reject"` returns 400 for batch arrays; `"first"` uses first valid request | +| `on_invalid` | string | `"continue"` | `"continue"` passes non-JSON through; `"reject"` returns 400; `"error"` raises a filter error | +| `headers.method` | string | `"X-Json-Rpc-Method"` | Header name for the JSON-RPC method | +| `headers.id` | string | `"X-Json-Rpc-Id"` | Header name for the JSON-RPC id | +| `headers.kind` | string | `"X-Json-Rpc-Kind"` | Header name for the message kind | + +Message kinds: `request`, `notification`, `response`, +`batch`. The filter also writes `json_rpc.*` entries +to the filter result set for branch chain conditions. + +### MCP + +Extracts Model Context Protocol metadata from JSON-RPC +request bodies and promotes method, tool/resource/prompt +name, session ID, and protocol version to request +headers and filter results for routing. Validates MCP +headers against body-derived values when +`header_validation` is configured. + +```yaml +- filter: mcp + max_body_bytes: 65536 + on_invalid: reject +``` + +| Field | Type | Default | Description | +| ----- | ---- | ------- | ----------- | +| `max_body_bytes` | integer | 65536 | Maximum body size to buffer (64 KiB) | +| `on_invalid` | string | `"reject"` | `"reject"` returns 400 for non-MCP; `"continue"` passes through | +| `header_validation.mismatch` | string | `"reject"` | `"reject"` or `"ignore"` when MCP headers conflict with body values | +| `header_validation.missing` | string | `"ignore"` | `"ignore"`, `"synthesize"` (inject from body), or `"reject"` | +| `headers.method` | string | `"x-praxis-mcp-method"` | Header name for MCP method | +| `headers.name` | string | `"x-praxis-mcp-name"` | Header name for tool/resource/prompt name | +| `headers.kind` | string | `"x-praxis-mcp-kind"` | Header name for JSON-RPC kind | +| `headers.session_present` | string | `"x-praxis-mcp-session-present"` | Header name for session presence | + +Recognized MCP methods include `initialize`, +`tools/call`, `tools/list`, `resources/read`, +`resources/list`, `prompts/get`, `prompts/list`, +`ping`, and others. Methods requiring a name selector +(`tools/call`, `resources/read`, `prompts/get`) return +a JSON-RPC error if the selector is missing and +`on_invalid` is `"reject"`. The filter writes `mcp.*` +and `json_rpc.*` entries to the filter result set for +branch chain conditions. + +### Static Response + +Returns a fixed response without contacting any upstream. +Useful for health checks, status endpoints, or stub routes: + +```yaml +- filter: static_response + status: 200 + headers: + - name: Content-Type + value: application/json + body: '{"status": "ok", "server": "praxis"}' +``` + +`status` is required. `headers` and `body` are optional. +Combine with conditions to serve static responses on +specific paths. + +### Rate Limit + +Token bucket rate limiter. Supports `per_ip` (one bucket +per source IP) and `global` (one shared bucket) modes. +Rejects excess traffic with 429 and `Retry-After` header. +Injects `X-RateLimit-Limit`, `X-RateLimit-Remaining`, and +`X-RateLimit-Reset` headers into both rejections and +successful responses. + +```yaml +- filter: rate_limit + mode: per_ip # "per_ip" or "global" + rate: 100 # tokens replenished per second + burst: 200 # maximum bucket capacity +``` + +| Field | Type | Required | Description | +| ------- | ------ | ---------- | ------------- | +| `mode` | string | yes | `"per_ip"` or `"global"` | +| `rate` | float | yes | Tokens per second (must be > 0) | +| `burst` | integer | yes | Max bucket capacity (must be >= rate) | + +### Circuit Breaker + +Per-cluster circuit breaker that prevents cascading +failures. When consecutive upstream failures reach the +threshold, the circuit opens and subsequent requests +receive 503 immediately. After the recovery window, a +single probe request is forwarded; if it succeeds the +circuit closes. See [circuit-breaker.yaml](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/traffic-management/circuit-breaker.yaml). + +```yaml +- filter: circuit_breaker + clusters: + - name: backend + consecutive_failures: 5 + recovery_window_secs: 30 +``` + +| Field | Type | Required | Description | +| ----- | ---- | -------- | ----------- | +| `clusters[].name` | string | yes | Cluster name to protect | +| `clusters[].consecutive_failures` | integer | yes | Failures before opening | +| `clusters[].recovery_window_secs` | integer | yes | Seconds before half-open probe | + +### Guardrails + +Rejects requests matching string or regex rules against +headers and/or body content. Rejected requests receive +403 Forbidden. + +```yaml +- filter: guardrails + rules: + - target: header + name: "User-Agent" + pattern: "bad-bot.*" + - target: body + contains: "DROP TABLE" + - target: body + pattern: "^\\{.*\\}$" + negate: true +``` + +Each rule has: + +| Field | Type | Required | Description | +| ------- | ------ | ---------- | ------------- | +| `target` | string | yes | `"header"` or `"body"` | +| `name` | string | header only | Header name to inspect | +| `contains` | string | one of | Literal substring match | +| `pattern` | string | one of | Regex pattern match | +| `negate` | bool | no | Invert match (default: false) | + +Each rule must have either `contains` or `pattern`, not +both. Body rules use StreamBuffer mode (up to 1 MiB by +default) to inspect the full request body. + +### CORS + +Spec-compliant CORS filter with preflight handling, origin +validation, and credential support. See [cors.yaml](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/security/cors.yaml). + +| Field | Type | Default | Description | +| ------- | ------ | --------- | ------------- | +| `allow_origins` | list | required | Origins to allow; `["*"]` for any | +| `allow_methods` | list | GET, HEAD, POST | Allowed HTTP methods | +| `allow_headers` | list | none | Allowed request headers | +| `expose_headers` | list | none | Response headers exposed to client | +| `allow_credentials` | bool | false | Include credentials header | +| `max_age` | integer | 86400 | Preflight cache duration (seconds) | +| `allow_private_network` | bool | false | Private Network Access support | +| `disallowed_origin_mode` | string | "omit" | `"omit"` or `"reject"` for non-matching origins | +| `allow_null_origin` | bool | false | Allow `Origin: null` | + +Wildcard subdomain patterns (e.g. `https://*.example.com`) +are supported. `allow_credentials: true` is incompatible +with wildcard origins, methods, or headers per the Fetch +spec. + +### CSRF + +Cross-site request forgery protection via origin +validation. Safe methods (GET, HEAD, OPTIONS by default) +bypass the check. State-changing methods require an +`Origin` or `Referer` header matching the trusted +origins. Rejected requests receive 403 Forbidden. +See [csrf.yaml](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/security/csrf.yaml). + +```yaml +- filter: csrf + trusted_origins: + - "https://app.example.com" + - "https://*.example.com" + enforce_percentage: 100 + enable_sec_fetch_site: true +``` + +| Field | Type | Default | Description | +| ------- | ------ | --------- | ------------- | +| `trusted_origins` | list | required | Origins to allow; `["*"]` for any | +| `safe_methods` | list | GET, HEAD, OPTIONS | Methods that bypass CSRF checks | +| `enforce_percentage` | integer | 100 | Percentage of requests to enforce (0..=100); enables gradual rollout | +| `enable_sec_fetch_site` | bool | false | Reject requests with `Sec-Fetch-Site: cross-site` | + +Wildcard subdomain patterns (e.g. +`https://*.example.com`) are supported. A bare wildcard +(`"*"`) cannot be mixed with other origins. Set +`insecure_options.csrf_log_only: true` to log violations +without rejecting requests during initial rollout. + +### Redirect + +Returns a 3xx redirect without contacting any upstream: + +```yaml +- filter: redirect + status: 301 + location: "https://example.com${path}" +``` + +| Field | Type | Default | Description | +| ------- | ------ | --------- | ------------- | +| `status` | integer | 301 | Redirect status (301, 302, 307, or 308) | +| `location` | string | required | URL template; `${path}` and `${query}` are substituted | + +### Path Rewrite + +Rewrites the request path before forwarding to upstream. +Exactly one of `strip_prefix`, `add_prefix`, or `replace` +per filter instance. Query strings are preserved. See +[path-rewriting.yaml](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/transformation/path-rewriting.yaml). + +| Field | Type | Description | +| ------- | ------ | ------------- | +| `strip_prefix` | string | Remove this prefix from the path | +| `add_prefix` | string | Prepend this prefix to the path | +| `replace.pattern` | string | Regex pattern to match | +| `replace.replacement` | string | Replacement string (`$1`, `$name` captures) | + +### URL Rewrite + +Regex-based path transformation and query string +manipulation. Operations applied in order: +`regex_replace`, `strip_query_params`, +`add_query_params`. See [url-rewriting.yaml](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/transformation/url-rewriting.yaml). + +### Compression + +Gzip, brotli, and zstd response compression. All three +enabled by default. See [compression.yaml](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/payload-processing/compression.yaml). + +| Field | Type | Default | Description | +| ------- | ------ | --------- | ------------- | +| `level` | integer | 6 | Default compression level (1-12) | +| `min_size_bytes` | integer | 256 | Skip responses smaller than this | +| `gzip` | object | enabled | Per-algorithm `enabled` and `level` | +| `brotli` | object | enabled | Per-algorithm `enabled` and `level` | +| `zstd` | object | enabled | Per-algorithm `enabled` and `level` | +| `content_types` | list | see above | MIME type prefixes that qualify | + +At least one algorithm must be enabled. + +### Prompt Enrich + +Injects statically configured messages into +OpenAI-compatible chat completion request bodies. The +filter parses the JSON body, splices configured messages +into the `messages` array, re-serializes, and updates +`Content-Length`. Requires the `ai-inference` feature. +See [prompt-enrichment.yaml](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/ai/prompt-enrichment.yaml). + +```yaml +- filter: prompt_enrich + prepend: + - role: system + content: "You are a helpful assistant." + append: + - role: user + content: "Cite your sources." +``` + +| Field | Type | Default | Description | +| ------- | ------ | --------- | ------------- | +| `prepend` | list | `[]` | Messages inserted at the beginning of `messages` (system role only) | +| `append` | list | `[]` | Messages added at the end of `messages` (system or user role) | +| `on_invalid` | string | `"continue"` | `"continue"` passes non-JSON through; `"reject"` returns 400 | +| `max_body_bytes` | integer | 10485760 | Maximum body size to buffer (10 MiB) | + +At least one of `prepend` or `append` must be non-empty. +Each message has a `role` (system or user) and a +non-empty `content` string. JSON is re-serialized, so +byte-for-byte body identity is not preserved. In chains +that also use `json_body_field` or `model_to_header`, +place `prompt_enrich` first. + +### Conditions + +`when`/`unless` gates on any filter chain entry. Request +predicates: `path` (exact match), `path_prefix`, +`methods`, `headers`. All fields within a condition are +ANDed. Use `response_conditions` with `status` or +`headers` predicates to gate response hooks. See +[conditional-filters.yaml](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/pipeline/conditional-filters.yaml). + +Request conditions gate both request and body hooks. +Response conditions gate only `on_response` and response +body hooks. A filter can have both `conditions` and +`response_conditions`. + +## Payload Size Limits + +Global hard ceilings on request and response payload +size. These apply across all body modes (Stream, +StreamBuffer). When a filter also declares a per-filter +`max_bytes`, the smaller of the two limits is enforced. +Requests exceeding the limit receive 413 (Payload Too +Large). + +```yaml +body_limits: + max_request_bytes: 10485760 # 10 MiB + max_response_bytes: 5242880 # 5 MiB +``` + +Both default to 10 MiB (10,485,760 bytes) when +omitted. Setting either to `null` removes the ceiling +but requires `insecure_options.allow_unbounded_body: +true`; without that flag, startup fails with a +validation error. + +## Header and Request Limits + +Praxis inherits header and request limits from Pingora's +HTTP/1.x parser. These are compile-time constants in +Pingora and are not currently configurable in Praxis. + +| Limit | Value | Notes | +| ------- | ------- | ------- | +| Max total header size | 1,048,575 B (~1 MiB) | Includes request line | +| Max number of headers | 256 | HTTP/1.x only | +| Request-URI max size | shared with header limit | No separate cap | +| Header read timeout | 60 s | Pingora default | +| Body buffer chunk | 65,536 B (64 KiB) | Per-read buffer | + +HTTP/2 header limits are governed by the `h2` crate's +HPACK and frame-level settings (typically 16 KiB for +HEADERS frames by default, negotiated via SETTINGS). + +Requests that exceed header size or count limits receive +a 400 Bad Request from Pingora before reaching the filter +pipeline. + +## Runtime + +Worker thread pool and scheduling configuration. + +```yaml +runtime: + threads: 8 # 0 = auto-detect (default) + work_stealing: true # default: true +``` + +- `threads`: number of worker threads per service. + When set to 0 (the default), the thread count is + auto-detected from available CPUs. +- `work_stealing`: allow work-stealing between worker + threads of the same service. Enabled by default. +- `global_queue_interval`: fixed global queue interval + for the tokio scheduler. `Option`, defaults to + `Some(61)`. Set to `null` to use tokio's default. +- `upstream_keepalive_pool_size`: maximum number of idle + upstream connections kept per thread. `Option`, + defaults to `Some(64)`. Set to `null` to disable + keepalive pooling. + +```yaml +runtime: + threads: 4 + work_stealing: true + global_queue_interval: 61 + upstream_keepalive_pool_size: 64 +``` + +### Upstream CA + +`upstream_ca_file` sets a PEM CA file used as the root +certificate store for all upstream TLS connections. +Per-cluster `tls.ca` overrides this for individual +clusters. + +```yaml +runtime: + upstream_ca_file: /etc/praxis/tls/internal-ca.pem +``` + +This **replaces** the system trust store (not additive). +See [TLS & mTLS](/docs/protocols/tls) for details on CA trust +precedence and combined bundles. + +### Logging + +Set `PRAXIS_LOG_FORMAT=json` to emit structured JSON log +output instead of the default human-readable format. + +Per-module log level overrides can be configured under +`runtime.log_overrides`: + +```yaml +runtime: + log_overrides: + praxis_filter::pipeline: trace + praxis_protocol: debug +``` + +This is useful for debugging a specific subsystem without +flooding output from every module. + +## Key-Value Stores + +In-memory key-value stores for runtime-updatable +mappings. Stores are created dynamically by filters +at runtime via `KvStoreRegistry::get_or_create` and +managed through the admin API. No YAML configuration +is required. + +Filters access stores by name through +`HttpFilterContext` and `TcpFilterContext`. + +### Match Types + +Stores support four match types for key lookup: + +| Type | Behavior | +| ---- | -------- | +| `exact` | Key must equal the lookup key | +| `prefix` | Stored key starts with the pattern | +| `suffix` | Stored key ends with the pattern | +| `regex` | Stored key matches a regex pattern | + +### Admin API + +When `admin.address` is configured, CRUD endpoints +are available: + +| Method | Path | Description | +| ------ | ---- | ----------- | +| `GET` | `/api/kv/{store}` | List all entries | +| `GET` | `/api/kv/{store}/{key}` | Get a value | +| `PUT` | `/api/kv/{store}/{key}` | Set a value (body) | +| `DELETE` | `/api/kv/{store}/{key}` | Delete a key | + +Writes are immediately visible to all filters on all +threads. Unknown store names return 404. + +### Runtime Cache Semantics + +Key-value stores are **runtime caches, not durable +storage**. Data lives in memory and is lost on process +exit. + +The store is designed for operational overrides (routing +tables, feature flags, config knobs) that can be +reconstructed from an external source of truth. Do not +use it as a primary data store. + +### Pluggable Backends + +The `KvBackend` trait allows alternative implementations +(e.g. Redis). The default `InMemoryKvBackend` uses +DashMap for lock-free reads. See the `praxis_core::kv` +module docs for the trait definition. + +## Graceful Shutdown + +The `shutdown_timeout_secs` field controls how long the +server drains in-flight connections before forcing +shutdown: + +```yaml +shutdown_timeout_secs: 60 # default: 30 +``` + +## Default Configuration + +When no configuration file is provided, Praxis starts with +a built-in default config that listens on `127.0.0.1:8080` +and responds with `{"status": "ok", "server": "praxis"}` +on `/` (exact match) and 404 elsewhere. The default binds +to localhost only, preventing accidental exposure to +public networks during initial setup. This allows zero +config startup for testing. The source lives in +[default.yaml](https://github.com/praxis-proxy/praxis/blob/main/core/src/config/default.yaml). For a realistic starting point, see +[basic-reverse-proxy.yaml](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/traffic-management/basic-reverse-proxy.yaml). + +## Example Configs + +Working examples live under `examples/configs/`, organized +by category: + +| Directory | Contents | +| ----------- | ---------- | +| `ai` | AI inference model-to-header routing | +| `traffic-management` | Router, load balancer, timeouts, static responses, redirects, rate limiting, health checks | +| `payload-processing` | Body processing: compression, field extraction, stream buffering, size limits | +| `security` | Forwarded headers, IP ACL, guardrails, CORS, downstream read timeout | +| `observability` | Access logs, request IDs | +| `transformation` | Header manipulation, path rewriting, URL rewriting | +| `protocols` | TCP, TLS, mixed protocol configs | +| `pipeline` | Filter chain composition and conditions | +| `operations` | Production gateway, multi-listener, admin | + +## Validation and Security + +Praxis validates configuration at startup and fails +closed. Ambiguous or risky settings are errors, not +warnings. Insecure overrides (see [Testing](/docs/development/testing)) +require explicit opt-in and emit warnings at startup. + +Key validations: listener name uniqueness, filter chain +reference resolution, TLS path traversal rejection, +admin endpoint binding restrictions, health check SSRF +protection, upstream TLS SNI requirements, and payload +size enforcement. + +## Error Behavior + +Praxis fails fast at startup for configuration problems. +Common failure modes: + +- **Invalid YAML or missing required fields**: the process + exits with a descriptive error before any listener binds. +- **Unknown filter chain reference**: a listener references + a chain name not defined in `filter_chains:`; caught at + config validation. +- **TLS certificate load failure**: the process exits if + a certificate's `cert_path` or `key_path` cannot be + read or parsed. +- **Address bind failure**: if the listen address is already + in use or invalid, the server fails to start. + +At runtime: + +- **Unreachable upstream**: the request returns 502 (Bad + Gateway). Connection timeouts are configurable per + cluster. +- **Filter error**: an `Err` from a filter results in a + 500 response to the client. The error is logged. +- **Payload too large**: exceeding + `body_limits.max_request_bytes` or a filter's + `max_bytes` returns 413. + +## Overrides + +Some validations and features can be overridden for development +and testing purposes. See `insecure_options` in [Testing](/docs/development/testing#insecure-options). diff --git a/docs/development/_category_.json b/docs/development/_category_.json new file mode 100644 index 0000000000..579aed156a --- /dev/null +++ b/docs/development/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Development", + "position": 7 +} diff --git a/docs/benchmarks.md b/docs/development/benchmarks.md similarity index 99% rename from docs/benchmarks.md rename to docs/development/benchmarks.md index 2e58213c06..70f37881f3 100644 --- a/docs/benchmarks.md +++ b/docs/development/benchmarks.md @@ -1,3 +1,8 @@ +--- +sidebar_position: 3 +title: Benchmarks +--- + # Benchmarks Praxis has two benchmark systems: diff --git a/docs/development/contributing.md b/docs/development/contributing.md new file mode 100644 index 0000000000..ea4ddc8e53 --- /dev/null +++ b/docs/development/contributing.md @@ -0,0 +1,237 @@ +--- +sidebar_position: 1 +title: Contributing +--- + +# Development Conventions + +## Coding Style + +### General Principles + +- Brevity is a component of quality. Keep code lean and + complete; no bloat. +- Small, composable, single-purpose functions are the + default unit of organization. Split code into small + files with focused responsibilities. +- Minimize side effects. Prefer pure transformations when + feasible: data in, data out. Resist mutable state when + feasible and outside the critical paths. +- Keep functions short enough to reason about in isolation. + +### Important Tools + +- **Clippy**: Enforce idiomatic Rust and catch common mistakes +- **rustfmt**: Ensure consistent code formatting +- **cargo-audit**: Check for vulnerable dependencies +- **cargo-deny**: Enforce supply chain safety policies +- **rustdoc**: Generate the API documentation +- **cargo xtask**: Developer task runner for benchmarks, flamegraphs, and debug utilities +- **benchmarks**: Criterion microbenchmarks and scenario-based load tests ([Fortio](https://github.com/fortio/fortio), [Vegeta](https://github.com/tsenart/vegeta)) + +### Comments vs Tracing + +Comments answer **"why?"**, never **"what?"**. + +**"What?" belongs in `tracing`**, not comments. If a +comment describes what the code is doing at runtime +("parse the config", "reject the request", "skip this +filter"), replace it with a `tracing::debug!`, +`tracing::trace!`, or `tracing::info!` call. Runtime +narration (what the code did, what it decided, what it +skipped) is structured logging, not commentary. + +**"Why?" belongs in comments**, but only when +non-obvious. A hidden constraint, a subtle invariant, a +workaround for a specific bug, or behavior that would +surprise a reader: these justify a comment. If removing +the comment would not confuse a future reader, do not +write it. + +**"What?" at the code level needs neither.** Well-named +identifiers already explain what the code does. Do not +write comments that restate what names already convey. + +### Testing + +**New capabilities require all of the following:** + +1. Unit tests covering the implementation +2. Integration tests proving end-to-end behavior +3. An example config in `examples/configs/` +4. A functional integration test for the example config + in `tests/integration/tests/suite/examples/` +5. Update `examples/README.md` to list any new or + renamed example configs +6. Significant changes need to be [benchmarked]. + +This is not optional. A feature without tests and an +example is not complete. + +Prefer more doctests when in doubt. Duplicative coverage +between doctests and unit/integration tests is fine. + +Prefer assertion messages over inline comments. Put the +explanation in the assertion's message argument so it +prints on failure: + +```rust +// Bad: +// ACL should block loopback +assert_eq!(status, 403); + +// Good: +assert_eq!(status, 403, "ACL should block loopback"); +``` + +### RFC Conformance + +When implementing protocol-level behavior (HTTP semantics, +header handling, TLS, etc.), identify the governing RFCs +and verify conformance against them. + +- Cite the specific RFC number and section in test names + or doc comments for protocol conformance tests. +- RFC references in doc comments must use reference-style + rustdoc links to the IETF datatracker: + ```rust + /// Safe methods per [RFC 9110 Section 9.2.1]. + /// + /// [RFC 9110 Section 9.2.1]: https://datatracker.ietf.org/doc/html/rfc9110#section-9.2.1 + ``` +- When in doubt about an edge case, the RFC is the + authority, not other proxy implementations. +- Add dedicated conformance tests when implementing + RFC-specified behavior. These live in + `tests/conformance/`. + +### Rules, Practices & Lints + +Security is enforced at the lint level. See lints in +[Cargo.toml](https://github.com/praxis-proxy/praxis/blob/main/Cargo.toml) for the full set. + +- `unsafe_code = "deny"` in workspace lints (no + exceptions; unsafe belongs upstream) +- Clippy runs with `-D warnings` (zero tolerance) +- Errors via `thiserror` +- Logging via `tracing` +- Use workspace dependencies (`[workspace.dependencies]`) + to keep versions consistent across crates +- Keep dependencies light. Avoid new dependencies + when feasible +- Only add dependencies with well-established + reputation +- `cargo audit` and `cargo deny check` enforce supply + chain safety (see [Testing](testing)) + +#### Type Design + +Make invalid states unrepresentable. The type system +and serde should enforce constraints at parse time, +not at runtime. + +- **Enums over strings for fixed value sets.** Never + use `String` where the valid values are known. Use + `#[serde(rename_all = "snake_case")]` enums. This + gives serde-level validation and eliminates manual + string matching: + + ```rust + // Bad: + mode: String, // "per_ip" | "global" + + // Good: + #[derive(Deserialize)] + #[serde(rename_all = "snake_case")] + enum Mode { PerIp, Global } + ``` + +- **Structs over maps for known keys.** Never use + `BTreeMap`/`HashMap` for config deserialization when + the key set is known. Use a struct with + `#[serde(deny_unknown_fields)]`. Maps silently absorb + unknown keys. Only use maps when the key set is + genuinely open (e.g. user-defined header names). + +- **Enums over multiple `Option` fields.** When + exactly one of N fields must be set, use an N-variant + enum. Three `Option` fields with "exactly one must be + `Some`" invariants should be a three-variant enum. + Serde's `#[serde(rename_all = "snake_case")]` with + external tagging handles YAML naturally. + +- **`#[serde(default)]` over `Option` with + `unwrap_or`.** If an `Option` is always resolved + with `.unwrap_or(DEFAULT)`, use the concrete type with + `#[serde(default = "fn_name")]` instead. + +- **`#[serde(try_from)]` for constrained numerics.** + When a numeric field only accepts specific values + (e.g. HTTP redirect status 301/302/307/308), define + an enum with `TryFrom` and + `#[serde(try_from = "u16")]`. Validation moves to + parse time. + +- **`#[serde(deny_unknown_fields)]` by default.** Apply + to all config structs unless the struct intentionally + accepts arbitrary keys (extension points). Catches + typos at parse time. + +#### Additional Coding Conventions + +- Use separator comments to visually separate distinct + sections of code. +- **No re-export-only files.** If a file exists solely + to `pub use` items from another crate or module, + inline the import at the call site instead. +- **Constants** must be at the top of the file (after + imports), never inside functions or impl blocks. + Give them their own separator comment + (e.g. `// Constants`). +- **File ordering**: + 1. Constants (with separator comment) + 2. Public types, impls, and functions + 3. Private types and impls (below their public + consumers) + 4. Private utility/helper functions (with separator) + 5. `#[cfg(test)] mod tests` block (always last) +- **Field and method ordering**: Alphabetical, with + `name` pinned first on structs and `new()`/`name()` + pinned first in impl blocks. +- **Inside `#[cfg(test)] mod tests`**: + 1. Imports + 2. All test functions (`#[test]` / `#[tokio::test]`) + 3. Test utilities at the end (with `// Test Utilities` + separator) +- Place a blank line between attribute blocks. +- Separate distinct logical actions with blank lines. Function + calls, variable bindings that begin a new step, and expression + blocks that perform a discrete operation should have some newline space. +- Prefer pre-computed numeric literals over expressions + like `1024 * 10`. Always add a trailing comment with + the human-readable size or meaning (e.g. + `const MAX_BODY: usize = 10_485_760; // 10 MiB`). + +## Code Responsibility + +This project does not distinguish between code written by +hand, generated by a tool (e.g. lint), or produced by any +other means. **Every contributor is responsible for the +code they submit**, and *all* code MUST be human reviewed +before submission, or merging. + +Signed-off commits (`Signed-off-by:`) are required and +represent your assertion that you have reviewed and fully +understand the changes you are submitting. + +PRs from a bot or tool (with the exception of GitHub-specific +ones like `dependabot`) will not be accepted. + +Before submitting or merging PRs, ensure that you have: + +- Read every line of the diff. If you cannot explain why something exists, do not submit it. +- Verified that the change does what you intended and nothing more. +- Run the test suite *locally* first. The CI pipeline is not a substitute for local verification. + +> **Note**: `Draft` pull requests are not exempt from these guidelines. +> They are still expected to be reviewed before submission. diff --git a/docs/proposals.md b/docs/development/proposals.md similarity index 97% rename from docs/proposals.md rename to docs/development/proposals.md index ade4aab128..3e86ff2722 100644 --- a/docs/proposals.md +++ b/docs/development/proposals.md @@ -1,3 +1,8 @@ +--- +sidebar_position: 5 +title: Proposals +--- + # Proposals Proposals for new capabilities and refinements in Praxis. @@ -73,7 +78,7 @@ CI will close PRs that: - Have no `stakeholders` listed - Include the `How?` section in a new proposal -[template]: proposals/template.md +[template]: https://github.com/praxis-proxy/praxis/blob/main/docs/proposals/template.md ### 5. Iteration diff --git a/docs/release.md b/docs/development/release.md similarity index 98% rename from docs/release.md rename to docs/development/release.md index 79120509bf..36c749cddf 100644 --- a/docs/release.md +++ b/docs/development/release.md @@ -1,3 +1,8 @@ +--- +sidebar_position: 4 +title: Release Process +--- + # Release Process ## Versioning diff --git a/docs/development/testing.md b/docs/development/testing.md new file mode 100644 index 0000000000..9916208afe --- /dev/null +++ b/docs/development/testing.md @@ -0,0 +1,190 @@ +--- +sidebar_position: 2 +title: Testing +--- + +# Development + +## Requirements + +- Rust stable 1.94+ +- Rust nightly +- CMake 3.31+ +- Docker 29.3.0+ + +## Conventions + +**All contributors must read and understand +[Contributing](/docs/development/contributing) before contributing.** The conventions +cover code style, testing requirements, file +organization, and security practices. Submissions +that do not follow these conventions will be rejected. + +## Build + +```console +make build +make release +make check +``` + +### Test + +```console +make test +``` + +```console +make test-integration +``` + +### Supply Chain Safety + +Security is enforced at every stage of development. +`cargo audit` and `cargo deny check` are run as part of +the `make audit` target. The `deny.toml` config bans +wildcard version requirements, unknown registries, and +unknown git sources. Multiple versions of the same crate +produce a warning. All crates enforce +`unsafe_code = "deny"` in workspace lints and Clippy runs with +`-D warnings` (zero tolerance). + +See [System Design](/docs/architecture/system-design) for workspace layout +and crate dependencies. +See [Hardening Guide](/docs/security/hardening) for +deployment guidance. + +## Adding a new Built-in Filter + +Review [Custom Filters](/docs/filters/custom-filters) first. + +1. Create the filter module under + `filter/src/builtins///`. +2. Implement `HttpFilter` (or `TcpFilter` for TCP-level + filters). Add a `from_config` factory that deserializes + a `serde_yaml::Value` into your config struct. +3. Register it in `filter/src/registry.rs` + alongside the existing built-ins. +4. Add unit tests and doctests. +5. Add an example config in the appropriate category under + `examples/configs/`. +6. Add a functional integration test in + `tests/integration/tests/suite/examples/`. +7. Update `examples/README.md` to list any new or renamed + example configs. + +## Adding a Protocol + +1. Implement the `Protocol` trait in a new module under + `protocol/src/`. +2. Add a variant to `ProtocolKind` in + `core/src/config/listener.rs`. +3. Wire it up in `server/src/server.rs` where the protocol + is selected. + +## Security: Binding Low Ports + +Praxis refuses to start when running as root (UID 0) +on Unix systems. This check runs before any port +binding or protocol registration. If you need to +bind ports below 1024, prefer one of these approaches: + +- Grant `CAP_NET_BIND_SERVICE` to the binary: + `sudo setcap cap_net_bind_service=+ep ./target/release/praxis` +- Run behind a reverse proxy or load balancer that + handles port 80/443. +- Use socket activation (systemd) to pass pre-bound + sockets. + +## Insecure Options + +> **Warning.** These flags are intended for development and +> testing only. Never enable them in production. Each flag demotes +> a security check from an error to a warning. + +All flags live under `insecure_options` in the YAML config and default to `false`. + +```yaml +insecure_options: + allow_open_security_filters: false + allow_private_health_checks: false + allow_public_admin: false + allow_root: false + allow_tls_without_sni: false + allow_unbounded_body: false + csrf_log_only: false + skip_pipeline_validation: false +``` + +| Flag | Effect | +| ------ | -------- | +| `allow_open_security_filters` | Allow security-critical filters (`ip_acl`, `forwarded_headers`) to use `failure_mode: open`. Without this flag, open security filters are rejected because a runtime error would bypass security enforcement. With this flag enabled, the error is demoted to a warning. | +| `allow_private_health_checks` | Allow health check endpoints that resolve to loopback (`127.0.0.0/8`), link-local (`169.254.0.0/16`), or cloud metadata addresses. Blocked by default as SSRF protection. | +| `allow_public_admin` | Allow the admin health endpoint to bind to a public interface (`0.0.0.0` / `[::]`). By default this is a validation error. | +| `allow_root` | Allow starting as root (UID 0). Praxis refuses to run as root by default. | +| `allow_tls_without_sni` | Allow upstream TLS connections without an explicit SNI hostname. Most TLS servers require SNI; without this flag, missing SNI is a validation error. | +| `allow_unbounded_body` | Allow unbounded body processing. This covers two checks: (1) `body_limits.max_request_bytes` or `max_response_bytes` set to `null`, and (2) `StreamBuffer` body mode without a `max_bytes` limit. Without this flag, both are rejected at startup. | +| `csrf_log_only` | Run the CSRF filter in log-only mode: evaluate all rules but log violations as warnings instead of rejecting requests. Useful for initial rollout monitoring. | +| `skip_pipeline_validation` | Demote pipeline ordering errors (e.g. filter placement issues) to warnings instead of failing startup. | + +Example overriding two flags for local development: + +```yaml +admin: + address: "0.0.0.0:9901" + +insecure_options: + allow_public_admin: true + allow_private_health_checks: true +``` + +## Project Management + +All repositories in the `praxis-proxy` organization +use a consistent workflow for planning, prioritizing, +and tracking work. + +### Milestones + +Milestones represent a body of work toward a shared +goal (e.g. a release, a feature area, or a hardening +pass). Every issue and pull request should belong to +a milestone. Milestones provide scope boundaries and +help answer "what ships together?" + +### Priority + +Every issue should have a priority set via the +built-in Priority issue field (not labels). Address +work in priority order: + +| Priority | Description | +| --- | --- | +| Urgent | Must be worked on immediately before anything else | +| High | Needs to be worked on immediately, defer to urgents | +| Medium | Resolve after high and urgent | +| Low | Resolve after all other priority levels | + +### Size + +Every issue should have a size set via the built-in +Size issue field. Size is a rough effort estimate: + +| Size | Rough Estimate | +| --- | --- | +| Large | 1 week or more | +| Medium | Roughly 3 days | +| Small | Roughly 1 day | +| Tiny | Less than a day | + +### Project Boards + +GitHub project boards visualize the state of work +across milestones. Use boards to track issues through +their lifecycle (backlog, in progress, in review, +done). Boards are the primary tool for stand-ups and +status checks. + +## Performance & Benchmarking + +See [Benchmarks](benchmarks). diff --git a/docs/filters/_category_.json b/docs/filters/_category_.json new file mode 100644 index 0000000000..bdbe6a22a9 --- /dev/null +++ b/docs/filters/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Filters", + "position": 4 +} diff --git a/docs/filters/custom-filters.md b/docs/filters/custom-filters.md new file mode 100644 index 0000000000..6b5364b451 --- /dev/null +++ b/docs/filters/custom-filters.md @@ -0,0 +1,457 @@ +--- +sidebar_position: 8 +title: Custom Filters +--- + +# Extensions + +Praxis is designed to be extended. The core library provides +the building blocks for building bespoke proxy servers. +Multiple extension mechanisms are provided to support a +variety of needs. + +## Rust Extensions (Preferred) + +Compile-time extensions with zero overhead. Implement +`HttpFilter` or `TcpFilter` in your own crate, register it, +and reference it in YAML config. + +1. Implement `HttpFilter` (`on_request`, `on_response`, + body hooks) or `TcpFilter` (`on_connect`, + `on_disconnect`) +2. Register with `register_filters!` +3. Reference by name in YAML filter chains + +### HTTP Filter + +```rust +use async_trait::async_trait; +use serde::Deserialize; +use praxis_filter::{ + FilterAction, FilterError, HttpFilter, + HttpFilterContext, Rejection, register_filters, +}; + +struct MaxBodyGuard { + max_content_length: u64, + reject_status: u16, +} + +impl MaxBodyGuard { + pub fn from_config( + config: &serde_yaml::Value, + ) -> Result, FilterError> { + #[derive(Deserialize)] + struct Cfg { + max_content_length: u64, + #[serde(default = "default_status")] + reject_status: u16, + } + fn default_status() -> u16 { 413 } + + let cfg: Cfg = + serde_yaml::from_value(config.clone())?; + Ok(Box::new(Self { + max_content_length: cfg.max_content_length, + reject_status: cfg.reject_status, + })) + } +} + +#[async_trait] +impl HttpFilter for MaxBodyGuard { + fn name(&self) -> &'static str { "max_body_guard" } + + async fn on_request( + &self, ctx: &mut HttpFilterContext<'_>, + ) -> Result { + let too_large = ctx.request.headers + .get("content-length") + .and_then(|v| v.to_str().ok()) + .and_then(|v| v.parse::().ok()) + .is_some_and(|len| { + len > self.max_content_length + }); + + if too_large { + return Ok(FilterAction::Reject( + Rejection::status(self.reject_status), + )); + } + Ok(FilterAction::Continue) + } +} + +// In your binary: +register_filters! { + http "max_body_guard" => MaxBodyGuard::from_config, +} +``` + +### TCP Filter + +TCP custom filters implement `TcpFilter` and register with +the `tcp` keyword: + +```rust +use async_trait::async_trait; +use praxis_filter::{ + FilterAction, FilterError, TcpFilter, TcpFilterContext, +}; + +struct ConnectionCounter { /* ... */ } + +#[async_trait] +impl TcpFilter for ConnectionCounter { + fn name(&self) -> &'static str { + "connection_counter" + } + + async fn on_connect( + &self, ctx: &mut TcpFilterContext<'_>, + ) -> Result { + // Track connection metrics + Ok(FilterAction::Continue) + } +} +``` + +### Custom Load Balancer + +Load balancers are ordinary HTTP filters. The contract: +read `ctx.cluster` (set by the router), select an +endpoint, and set `ctx.upstream`. If your algorithm +tracks in-flight requests, use `on_response` to release +counters. + +```rust +use std::{ + collections::HashMap, + sync::{ + atomic::{AtomicUsize, Ordering}, + Arc, + }, +}; + +use async_trait::async_trait; +use praxis_core::connectivity::{ConnectionOptions, Upstream}; +use praxis_filter::{ + FilterAction, FilterError, HttpFilter, HttpFilterContext, +}; + +/// Picks the endpoint that has handled the fewest +/// total requests (lifetime, not in-flight). +pub struct FewestServedFilter { + clusters: HashMap>, +} + +struct EndpointCounter { + address: Arc, + served: AtomicUsize, +} + +impl FewestServedFilter { + pub fn from_config( + config: &serde_yaml::Value, + ) -> Result, FilterError> { + #[derive(serde::Deserialize)] + struct ClusterCfg { + name: String, + endpoints: Vec, + } + + let cfgs: Vec = serde_yaml::from_value( + config + .get("clusters") + .cloned() + .unwrap_or_default(), + )?; + + let clusters = cfgs + .into_iter() + .map(|c| { + let counters = c + .endpoints + .into_iter() + .map(|addr| EndpointCounter { + address: Arc::from(addr.as_str()), + served: AtomicUsize::new(0), + }) + .collect(); + (c.name, counters) + }) + .collect(); + + Ok(Box::new(Self { clusters })) + } +} + +#[async_trait] +impl HttpFilter for FewestServedFilter { + fn name(&self) -> &'static str { "fewest_served" } + + async fn on_request( + &self, + ctx: &mut HttpFilterContext<'_>, + ) -> Result { + let cluster = ctx.cluster.as_deref().ok_or( + "fewest_served: no cluster set", + )?; + let endpoints = + self.clusters.get(cluster).ok_or_else(|| { + format!("fewest_served: unknown cluster \ + '{cluster}'") + })?; + + // Pick endpoint with lowest lifetime count. + let pick = endpoints + .iter() + .min_by_key(|e| e.served.load(Ordering::Relaxed)) + .expect("cluster must have endpoints"); + + pick.served.fetch_add(1, Ordering::Relaxed); + + ctx.upstream = Some(Upstream { + address: Arc::clone(&pick.address), + tls: None, + connection: Arc::new(ConnectionOptions::default()), + }); + + Ok(FilterAction::Continue) + } +} + +// Register alongside the built-in filters: +register_filters! { + http "fewest_served" => FewestServedFilter::from_config, +} +``` + +Then use it in config: + +```yaml +filter_chains: + - name: main + filters: + - filter: router + routes: + - path_prefix: "/" + cluster: backend + + - filter: fewest_served + clusters: + - name: backend + endpoints: + - "127.0.0.1:3001" + - "127.0.0.1:3002" +``` + +Key points: + +- The router runs first and sets `ctx.cluster`. +- Your filter reads the cluster name, selects an endpoint, + and writes `ctx.upstream`. +- The protocol layer connects to whatever `Upstream` you + set (address, TLS, SNI, timeouts). +- For stateful algorithms, override `on_response` to + update counters when a request completes. + +### Registration + +The `register_filters!` macro uses protocol-prefixed +syntax: + +```rust +register_filters! { + http "max_body_guard" => MaxBodyGuard::from_config, +} +``` + +TCP filters would use `tcp "name" => factory` syntax. + +### YAML Config + +Any keys placed alongside `filter:` in the filter chain +entry are passed to `from_config` as a `serde_yaml::Value`: + +```yaml +filter_chains: + - name: security + filters: + - filter: max_body_guard + max_content_length: 1048576 # 1 MiB + reject_status: 413 + conditions: + - when: + methods: ["POST", "PUT", "PATCH"] +``` + +Custom filters participate identically to built-ins: same +ordering, context access, and short-circuit capability. + +See [Filter Model](filter-model) for extensive documentation. + +## Best Practices + +### Header trust boundaries + +Never blindly trust `X-Forwarded-For` or +`X-Forwarded-Proto`. Attackers spoof these unless trusted +upstream sources are explicitly defined. + +### Keep filters stateless when possible + +Prefer reading all configuration at construction time +(in `from_config`) and keeping the filter struct +immutable. When shared mutable state is required (e.g. +counters, connection tracking), use atomics or interior +mutability with minimal lock scope. Filters are shared +across requests and must be `Send + Sync`. + +### Return early with `Reject`, not panics + +Use `FilterAction::Reject(Rejection::status(code))` to +abort request processing. Never panic inside a filter; +a panic takes down the worker thread. Return +`Err(...)` for unexpected failures and let the pipeline +handle the 500 response. + +### Declare body access accurately + +Only declare `request_body_access()` or +`response_body_access()` if your filter actually +inspects or modifies the body. Each declaration changes +how the pipeline buffers data. `BodyAccess::None` (the +default) avoids overhead. Use `ReadOnly` if you inspect +but do not modify, and `ReadWrite` only if you mutate +chunks in place. + +### Choose the right body mode + +- `Stream`: lowest latency; chunks flow through as they + arrive. Best for filters that inspect headers only or + process chunks independently. +- `StreamBuffer`: chunks flow through filters + incrementally but forwarding to upstream is deferred + until `Release` or end-of-stream. Use when body + content influences routing, when you need the complete + body (e.g. signature verification), or when you need + to inspect the full body before upstream selection. + Set `max_bytes` to avoid unbounded memory growth. + +Two patterns for declaring `StreamBuffer`: + +**Static declaration** (filter always needs the body): + +```rust +fn request_body_mode(&self) -> BodyMode { + BodyMode::StreamBuffer { max_bytes: Some(1_048_576) } +} +``` + +**Per-request upgrade** (conditional buffering): + +```rust +async fn on_request( + &self, ctx: &mut HttpFilterContext<'_>, +) -> Result { + if needs_body_inspection(ctx) { + ctx.set_request_body_mode( + BodyMode::StreamBuffer { + max_bytes: Some(1_048_576), + }, + ); + } + Ok(FilterAction::Continue) +} +``` + +### `on_response_body` is synchronous + +Pingora's response body callback is not async. Do not +block the thread with `block_on` or heavy computation. +If you need async I/O during response payload processing, +spawn a background task and communicate via a channel. + +### Use conditions instead of internal checks + +Rather than writing `if req.method != "POST" { return +Continue }` inside your filter, declare conditions in +YAML: + +```yaml +- filter: my_filter + conditions: + - when: + methods: ["POST", "PUT"] +``` + +This keeps filter logic focused and lets operators +adjust gating without code changes. + +### Use `extra_request_headers` for metadata + +When your filter extracts values from the body or +computes derived data, promote it to a request header +via `ctx.extra_request_headers`. This makes the value +visible to downstream filters (e.g. the router) without +coupling filters to each other. + +### Access KV stores for runtime mappings + +Use `ctx.kv_stores` with `get_or_create` to access +runtime-updatable key-value data without restarting +the proxy. Stores are created on demand: + +```rust +async fn on_request( + &self, + ctx: &mut HttpFilterContext<'_>, +) -> Result { + if let Some(registry) = ctx.kv_stores { + let store = registry.get_or_create("routing_overrides"); + if let Some(cluster) = store.get("preferred_cluster") { + ctx.cluster = Some(Arc::from(cluster.as_ref())); + } + } + Ok(FilterAction::Continue) +} +``` + +Operators update stores at runtime via the admin API +without config reloads: + +```console +curl -X PUT http://127.0.0.1:9901/api/kv/routing_overrides/preferred_cluster \ + -d 'us-east-cluster' +``` + +### Handle missing `ctx.cluster` gracefully + +If your filter depends on a cluster being set (like a +load balancer), return a clear error when +`ctx.cluster` is `None` rather than panicking: + +```rust +let cluster = ctx.cluster.as_deref() + .ok_or("my_filter: no cluster set")?; +``` + +### Provide `from_config` validation + +Validate all configuration values in `from_config` +rather than deferring checks to request time. Fail fast +at startup with a descriptive error. Parse and +type-check every field; use `#[serde(default)]` for +optional fields with sensible defaults. + +### Test with the integration harness + +Use the integration test utilities (`free_port`, +`start_backend`, `start_proxy_with_registry`) to write +end-to-end tests for custom filters. Register your +filter with `FilterFactory::Http(Arc::new(factory))`, +build a minimal YAML config, and assert on status codes +and response bodies. See the +[test suite](https://github.com/praxis-proxy/praxis/tree/main/tests/integration) for +examples. diff --git a/docs/filters/filter-model.md b/docs/filters/filter-model.md new file mode 100644 index 0000000000..5b337b3994 --- /dev/null +++ b/docs/filters/filter-model.md @@ -0,0 +1,678 @@ +--- +sidebar_position: 1 +title: Filter Model +--- + +# Filters + +## Listeners + +```mermaid +flowchart LR + Client -->|TCP| L0["Listener (named)"] + L0 -->|rustls| TLS + TLS --> Resolve["Chain Resolution"] + Resolve --> Pipeline["Filter Pipeline"] + Pipeline --> Pool["Upstream Pool"] + Pool --> Backend + + Config["Config (YAML)"] -. startup .-> Chains + Chains["filter_chains:"] -. per listener .-> Resolve +``` + +Each listener has a `name` and a list of `filter_chains`. +At startup, the referenced chains are resolved and +concatenated into a single pipeline per listener. Different +listeners can compose different subsets of chains. + +## Filter Model + +Filters are the core processing units in Praxis. Each +filter is a small (preferably), composable function that +inspects or transforms traffic at a single point in the +request/response lifecycle. + +Filters are chained into pipelines; the pipeline executor +calls each filter in order on requests and in reverse on responses. + +### What Filters Receive + +**HTTP filters** receive an `HttpFilterContext` containing: + +- `client_addr`: downstream IP (from the TCP connection) +- `downstream_tls`: whether the client connection uses TLS +- `health_registry`: endpoint health state +- `request`: method, URI, and headers +- `response_header`: response status and headers (**only in response phase**) +- `cluster` / `upstream`: current routing selections (may be set by earlier filters) +- `rewritten_path`: path set by a preceding rewrite filter (**Praxis will include this in routing decisions**) +- Request and response body chunks (only if the filter declares `BodyAccess::ReadOnly` or `BodyAccess::ReadWrite`) + +**TCP filters** receive a `TcpFilterContext` with +connection metadata: `remote_addr`, `local_addr`, `sni` +(SNI hostname from TLS ClientHello), `upstream_addr` +(mutable via `Cow`), timing, and byte counters. + +### What Filters Can Do + +Every filter hook returns a `FilterAction`: + +- **`Continue`**: pass to the next filter in the pipeline. +- **`Reject`**: short-circuit with an HTTP response (status code, optional headers and body). + Used by `static_response`, `redirect`, `rate_limit`, `guardrails`, `cors` preflight, and similar filters. +- **`Release`**: forward accumulated body data to upstream when using `StreamBuffer` mode. + Behaves as `Continue` when body data is not relevant. + +Filters also mutate `HttpFilterContext` fields to +influence downstream processing: + +- `ctx.cluster`: select which upstream cluster to route to. +- `ctx.upstream`: select a specific endpoint. +- `ctx.rewritten_path`: rewrite the upstream request path. +- `ctx.extra_request_headers`: inject headers into the upstream request. +- `ctx.response_header`: mutate response headers directly in `on_response`. +- `ctx.response_headers_modified`: flag that response headers were changed + +### Lifecycle Hooks + +| Hook | Direction | Phase | +| --- | --- | --- | +| `on_request` | Forward (pipeline order) | Request | +| `on_response` | Reverse (pipeline order) | Response | +| `on_request_body` | Forward | Request body chunks | +| `on_response_body` | Reverse | Response body chunks | + +Request `conditions` gate both the request and body +hooks. Response `response_conditions` gate only the +response hooks. A filter skipped on request is also +skipped on response. + +### Common Patterns + +See [example configs](https://github.com/praxis-proxy/praxis/tree/main/examples/configs) for working examples of every +pattern. A few highlights: + +- **Host-based routing**: [hosts.yaml](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/traffic-management/hosts.yaml) +- **Path-based routing with rewriting**: [path-based-routing.yaml](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/traffic-management/path-based-routing.yaml) +- **Security chain** (guardrails + IP ACL): [guardrails.yaml](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/security/guardrails.yaml), [ip-acl.yaml](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/security/ip-acl.yaml) +- **Rate limiting with headers**: [rate-limiting.yaml](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/traffic-management/rate-limiting.yaml) +- **Composed filter chains**: [composed-chains.yaml](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/pipeline/composed-chains.yaml) +- **Conditional filters**: [conditional-filters.yaml](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/pipeline/conditional-filters.yaml) +- **Production gateway**: [production-gateway.yaml](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/operations/production-gateway.yaml) + +## Filter Chains + +Filter chains are named, reusable groups of filters defined +at the top level of the config. A listener references one or +more chains by name; the filters are concatenated in order +to form that listener's pipeline. + +```mermaid +flowchart LR + subgraph "Listener: public" + direction LR + S["security chain"] --> O["observability chain"] + O --> R["routing chain"] + end + + subgraph "Listener: internal" + direction LR + O1["observability chain"] --> R2["routing chain"] + end +``` + +This enables reuse without duplication. A "security" chain +can be shared across public listeners while internal +listeners skip it entirely. + +### Protocol-Specific Filters + +Every filter belongs to exactly one protocol level. HTTP +filters implement the `HttpFilter` trait (`on_request`, +`on_response`, body hooks). TCP filters implement the +`TcpFilter` trait (`on_connect`, `on_disconnect`). There +is no generic filter that operates at both levels. The +`AnyFilter` enum tags each filter with its protocol for +storage in a unified pipeline. + +Built-in filters are organized by protocol, then by +category: + +```text +builtins/ + http/ HTTP protocol filters + ai/ AI workloads (inference) + observability/ Access logs, request IDs + payload_processing/ Compression, body field extraction + security/ CORS, CSRF, forwarded headers, guardrails, IP ACL + traffic_management/ Router, load balancer, timeout, rate limit, redirect, static response + transformation/ Header, path rewrite, URL rewrite + tcp/ TCP protocol filters + observability/ Connection logging + traffic_management/ SNI-based routing +``` + +At runtime, pipeline execution dispatches to the correct +filter type. HTTP execution (`execute_http_request`, +`execute_http_response`, body hooks) calls only HTTP +filters, skipping TCP entries. TCP execution +(`execute_tcp_connect`, `execute_tcp_disconnect`) calls +only TCP filters, skipping HTTP entries. + +**Protocol stack model.** Higher-level protocols include +lower levels. HTTP's stack includes TCP, so an HTTP +listener accepts both HTTP and TCP filters in its +pipeline. A TCP listener accepts only TCP filters. +Validation enforces this via `ProtocolKind::supports()`. + +| Listener Protocol | HTTP Filters | TCP Filters | +| --- | --- | --- | +| `http` (default) | Yes | Yes | +| `tcp` | No | Yes | + +```mermaid +flowchart TD + AnyFilter --> HttpFilter + AnyFilter --> TcpFilter + + HttpListener["HTTP Listener"] -->|supports| HttpFilter + HttpListener -->|supports| TcpFilter + TcpListener["TCP Listener"] -->|supports| TcpFilter +``` + +## What Stays Outside Filters + +- TCP/TLS, HTTP framing, connection pooling: adapters +- Config loading and validation: `praxis-core` +- Pipeline executor and `HttpFilterContext`: `praxis-filter` + +## HttpFilter Trait + +Every HTTP behavior in Praxis is an `HttpFilter`: + +```rust +#[async_trait] +pub trait HttpFilter: Send + Sync { + fn name(&self) -> &'static str; + async fn on_request( + &self, ctx: &mut HttpFilterContext<'_>, + ) -> Result; + async fn on_response( + &self, ctx: &mut HttpFilterContext<'_>, + ) -> Result { + Ok(FilterAction::Continue) + } + // Body hooks and access/mode methods omitted for + // brevity; see "Body Access" section below. +} +``` + +The trait also defines body access, body mode, and body +hook methods. See [Body Access](#body-access-http-only) +below for the full API. + +`on_request` runs in order, `on_response` in reverse. + +## TcpFilter Trait + +TCP-level filters implement `TcpFilter`: + +```rust +#[async_trait] +pub trait TcpFilter: Send + Sync { + fn name(&self) -> &'static str; + async fn on_connect( + &self, ctx: &mut TcpFilterContext<'_>, + ) -> Result { + Ok(FilterAction::Continue) + } + async fn on_disconnect( + &self, ctx: &mut TcpFilterContext<'_>, + ) -> Result<(), FilterError> { + Ok(()) + } +} +``` + +`on_connect` fires when a TCP connection is accepted. +`on_disconnect` fires when the connection closes. Both +hooks have default implementations that pass through. + +## FilterAction + +- `Continue` : pass to next filter +- `Reject(rejection)` : stop pipeline, respond now +- `Release` : forward accumulated StreamBuffer data to + upstream; behaves as `Continue` in non-StreamBuffer + contexts +- `BodyDone` : signal that this filter has finished body + processing; subsequent body chunks skip this filter + while other filters continue normally + +```rust +FilterAction::Reject(Rejection::status(429) + .with_header("Retry-After", "60") + .with_body(b"rate limit exceeded" as &[u8])) +``` + +## HttpFilterContext + +Shared state flowing through HTTP filters for a request: + +```rust +pub struct HttpFilterContext<'a> { + pub client_addr: Option, + pub cluster: Option>, + pub downstream_tls: bool, + pub extra_request_headers: Vec<(Cow<'static, str>, String)>, + pub filter_metadata: HashMap, + pub filter_results: HashMap<&'static str, FilterResultSet>, + pub health_registry: Option<&'a HealthRegistry>, + pub kv_stores: Option<&'a KvStoreRegistry>, + pub request: &'a Request, + pub request_body_bytes: u64, + pub request_body_mode: BodyMode, + pub request_headers_to_remove: Vec, + pub request_headers_to_set: Vec<(HeaderName, HeaderValue)>, + pub request_start: Instant, + pub response_body_bytes: u64, + pub response_body_mode: BodyMode, + pub response_header: Option<&'a mut Response>, + pub response_headers_modified: bool, + pub rewritten_path: Option, + pub selected_endpoint_index: Option, + pub upstream: Option, + // Internal pipeline tracking fields omitted. +} +``` + +## TcpFilterContext + +Per-connection state for TCP filters: + +```rust +pub struct TcpFilterContext<'a> { + pub remote_addr: &'a str, + pub local_addr: &'a str, + pub sni: Option<&'a str>, + pub upstream_addr: Cow<'a, str>, + pub connect_time: Instant, + pub bytes_in: u64, + pub bytes_out: u64, +} +``` + +The `sni` field is populated by the TCP proxy when it peeks +at the first bytes of a TLS connection and extracts the SNI +hostname from the ClientHello. Filters like `sni_router` use +this to select an upstream. The `upstream_addr` field is a +`Cow` so filters can replace it with an owned value without +requiring the listener config to provide a static upstream. + +## AnyFilter + +The `AnyFilter` enum wraps both filter variants for storage +in a unified registry and pipeline: + +```rust +pub enum AnyFilter { + Http(Box), + Tcp(Box), +} +``` + +Each variant reports its `protocol_level()` as +`ProtocolKind::Http` or `ProtocolKind::Tcp`. + +## Body Access (HTTP only) + +Filters see headers only by default. Opt in: + +```rust +fn request_body_access(&self) -> BodyAccess { + BodyAccess::ReadOnly // or ReadWrite +} +``` + +| Access | Hooks? | Modify? | +| ---------------- | ------ | ------- | +| `None` (default) | No | No | +| `ReadOnly` | Yes | No | +| `ReadWrite` | Yes | Yes | + +### Body Mode + +| Mode | Behavior | Use case | +| ----------------------------- | --------------- | ------------------------- | +| `Stream` (default) | Per chunk | Logging, transforms | +| `StreamBuffer { max_bytes }` | Deferred stream | Inspection before forward | +| `SizeLimit { max_bytes }` | Stream + ceiling | Global size enforcement | + +If any filter requests `StreamBuffer`, the pipeline +defers upstream forwarding until release. `SizeLimit` +streams chunks without buffering but enforces a byte +ceiling, returning 413 on overflow. It is used when no +filter needs body access but a global size limit is +configured. Precedence: `StreamBuffer` > `SizeLimit` > +`Stream`. + +### StreamBuffer Mode + +`StreamBuffer` combines streaming inspection with deferred +forwarding. Filters see each chunk as it arrives (like +`Stream`) but the protocol layer accumulates them and does +not forward to upstream until a filter returns +`FilterAction::Release` or end-of-stream is reached. + +```rust +fn request_body_mode(&self) -> BodyMode { + // No limit (default): + BodyMode::StreamBuffer { max_bytes: None } + + // With a limit (413 on overflow): + // BodyMode::StreamBuffer { max_bytes: Some(1_048_576) } +} +``` + +A filter signals release by returning +`FilterAction::Release` from `on_request_body` or +`on_response_body`. After release, remaining chunks flow +through in stream mode. + +When `max_bytes` is `None` (default), StreamBuffer +accumulates without limit. When `Some(n)`, requests +exceeding `n` bytes receive 413. + +This mode is useful for: + +- **AI inference proxies**: inspect prompt content for + routing, token counting, or content policy before + forwarding +- **Security gateways**: scan payloads for malware + signatures, PII, or injection attacks with early + rejection +- **Body-based routing**: peek at request body content + (e.g. JSON model field) to select a cluster, then + release and forward + +### Body Hooks + +```rust +// Async +async fn on_request_body( + &self, ctx: &mut HttpFilterContext<'_>, + body: &mut Option, + end_of_stream: bool, +) -> Result; + +// Sync (upstream constraint) +fn on_response_body( + &self, ctx: &mut HttpFilterContext<'_>, + body: &mut Option, + end_of_stream: bool, +) -> Result; +``` + +Override `needs_request_context() -> true` to access request +headers in body hooks. + +## Conditional Execution + +Add `conditions` to any filter chain entry. Fields within a +condition are ANDed; all conditions must pass. + +| Field | Matches when | +| ------------- | ---------------------------- | +| `path` | URI exactly equals value | +| `path_prefix` | URI starts with value | +| `methods` | Method in list | +| `headers` | All listed headers match | + +```yaml +filter_chains: + - name: main + filters: + - filter: headers + conditions: + - when: + path_prefix: "/api" + - unless: + headers: + x-internal: "true" + request_add: + - name: "X-Api-Version" + value: "v2" +``` + +Use `path` for exact matching (e.g., health checks on `/`): + +```yaml +- filter: static_response + conditions: + - when: + path: "/" + status: 200 + body: "ok" +``` + +Skipped on request = skipped on response. + +### Response Conditions + +Use `response_conditions` to gate `on_response` execution. +Response predicates: `status` (list of status codes), +`headers`. + +```yaml +- filter: headers + response_conditions: + - when: + status: [200, 201] + response_set: + - name: "Cache-Control" + value: "public, max-age=60" +``` + +A filter can have both `conditions` (request phase) and +`response_conditions` (response phase). + +## Built-in Filters + +| Filter | Category | Protocol | Key config | +| --- | --- | --- | --- | +| `router` | Traffic Management | HTTP | `routes[].path_prefix`, `.host`, `.cluster` | +| `load_balancer` | Traffic Management | HTTP | `clusters[].endpoints`, `.load_balancer_strategy` | +| `timeout` | Traffic Management | HTTP | `timeout_ms` (504 on exceed) | +| `static_response` | Traffic Management | HTTP | `status` (required), `headers`, `body` | +| `rate_limit` | Traffic Management | HTTP | `mode`, `rate`, `burst`; token bucket with per-IP and global modes | +| `circuit_breaker` | Traffic Management | HTTP | `clusters[].consecutive_failures`, `.recovery_window_secs`; per-cluster circuit breaking | +| `headers` | Transformation | HTTP | `request_add`, `response_add/set/remove` | +| `request_id` | Observability | HTTP | Propagates/generates `X-Request-ID` | +| `access_log` | Observability | HTTP | Structured JSON logging; optional `sample_rate` | +| `sni_router` | Traffic Management | TCP | `routes[].server_names`, `.upstream`, `default_upstream` | +| `tcp_load_balancer` | Traffic Management | TCP | Cluster-backed TCP endpoint selection (round-robin, least-connections, consistent-hash) | +| `tcp_access_log` | Observability | TCP | Structured JSON connection logging | +| `forwarded_headers` | Security | HTTP | `trusted_proxies` (CIDR list) | +| `guardrails` | Security | HTTP | Reject requests matching header/body string or regex rules | +| `ip_acl` | Security | HTTP | `allow` or `deny` (CIDR lists, mutually exclusive); 403 on denial | +| `credential_injection` | Security | HTTP | Per-cluster API key injection with client credential stripping. Literal `value` fields are redacted in `--dump` output. | +| `a2a` | Payload Processing | HTTP | A2A protocol classifier: extract method, family, task ID, streaming detection, and version for routing | +| `json_body_field` | Payload Processing | HTTP | Extract a JSON body field and promote to header | +| `json_rpc` | AI / Agentic | HTTP | Parse JSON-RPC 2.0 envelopes and extract method/id/kind for routing | +| `mcp` | AI / Agentic | HTTP | MCP protocol classifier: extract method, tool/resource/prompt name, and session metadata for routing | +| `compression` | Payload Processing | HTTP | Gzip, brotli, and zstd response compression | +| `cors` | Security | HTTP | CORS preflight handling, origin validation, credential support | +| `csrf` | Security | HTTP | Origin-based CSRF protection with gradual rollout and Sec-Fetch-Site support | +| `redirect` | Traffic Management | HTTP | `status` (301/302/307/308), `location` template with `${path}`/`${query}` | +| `path_rewrite` | Transformation | HTTP | `strip_prefix`, `add_prefix`, or `replace` (regex) on request path | +| `url_rewrite` | Transformation | HTTP | `operations[]`: `regex_replace`, `strip_query_params`, `add_query_params` | +| `model_to_header` | AI / Inference | HTTP | Extract JSON "model" field and promote to X-Model header. Requires `ai-inference` feature. | +| `prompt_enrich` | AI / Inference | HTTP | Inject messages into OpenAI-compatible chat completion request bodies. Requires `ai-inference` feature. | + +For detailed configuration of each built-in filter, see +[Configuration](/docs/configuration/overview). + +### Security Filter Restrictions + +Security-critical filters (`ip_acl`, `forwarded_headers`) +reject `failure_mode: open` by default. Open failure mode +on these filters means runtime errors would bypass security +enforcement. To override this check, set +`insecure_options.allow_open_security_filters: true`, which +demotes the error to a warning. + +### Rewrite and Routing Interaction + +Both `path_rewrite` and `url_rewrite` set +`ctx.rewritten_path`. The router checks `rewritten_path` +before the original URI, enabling "rewrite then route" +pipelines. If both rewrite filters appear in the same +pipeline, only the last one takes effect. Validation +rejects this by default; set `allow_rewrite_override: true` +on the later filter to permit it. + +## Custom Filters + +### HTTP Filter Example + +Create a crate for your filter(s): + +```toml +[dependencies] +praxis-filter = { git = "https://github.com/praxis-proxy/praxis" } +async-trait = "0.1.89" +serde = { version = "1.0.228", features = ["derive"] } +serde_yaml = "0.9.34" +``` + +```rust +// my_filters/src/lib.rs +use async_trait::async_trait; +use praxis_filter::{ + HttpFilter, FilterAction, HttpFilterContext, + FilterError, Rejection, +}; +use serde::Deserialize; + +pub struct ApiKeyFilter { valid_keys: Vec } + +#[derive(Deserialize)] +struct Config { keys: Vec } + +impl ApiKeyFilter { + pub fn from_config( + config: &serde_yaml::Value, + ) -> Result, FilterError> { + let cfg: Config = + serde_yaml::from_value(config.clone())?; + Ok(Box::new(Self { valid_keys: cfg.keys })) + } +} + +#[async_trait] +impl HttpFilter for ApiKeyFilter { + fn name(&self) -> &'static str { "api_key" } + + async fn on_request( + &self, ctx: &mut HttpFilterContext<'_>, + ) -> Result { + let key = ctx.request.headers + .get("x-api-key") + .and_then(|v| v.to_str().ok()); + match key { + Some(k) + if self.valid_keys.iter().any(|v| v == k) + => { + Ok(FilterAction::Continue) + } + _ => Ok(FilterAction::Reject( + Rejection::status(401), + )), + } + } +} +``` + +Factory signature: +`fn(&serde_yaml::Value) -> Result, FilterError>`. +Filters are created once at startup, must be `Send + Sync`. + +### TCP Filter Example + +```rust +use async_trait::async_trait; +use praxis_filter::{ + TcpFilter, TcpFilterContext, FilterAction, FilterError, +}; + +pub struct ConnectionLogger; + +#[async_trait] +impl TcpFilter for ConnectionLogger { + fn name(&self) -> &'static str { "connection_logger" } + + async fn on_connect( + &self, ctx: &mut TcpFilterContext<'_>, + ) -> Result { + tracing::info!( + remote = ctx.remote_addr, + "new connection" + ); + Ok(FilterAction::Continue) + } + + async fn on_disconnect( + &self, ctx: &mut TcpFilterContext<'_>, + ) -> Result<(), FilterError> { + tracing::info!( + remote = ctx.remote_addr, + "connection closed" + ); + Ok(()) + } +} +``` + +### Registration + +The `register_filters!` macro uses `http "name" => factory` +syntax. TCP filters use `tcp "name" => factory`. + +```rust +use my_filters::ApiKeyFilter; +use praxis_filter::register_filters; + +register_filters! { + http "api_key" => ApiKeyFilter::from_config, +} +``` + +The macro generates a `custom_registry()` function that +returns a `FilterRegistry` with both built-in and custom +filters. Use it with the test utilities +(`start_proxy_with_registry`) or build your own server +bootstrap from the workspace crates (`praxis-core`, +`praxis-filter`, `praxis-protocol`). + +### YAML Config + +```yaml +filter_chains: + - name: main + filters: + - filter: api_key + keys: ["secret-key-1", "secret-key-2"] # use env/secrets in production + - filter: router + routes: + - path_prefix: "/" + cluster: backend +``` + +The YAML block under `filter: api_key` is passed as-is to +`from_config`. Conditions work with custom filters with no +extra code. + +For detailed configuration of individual built-in filters, +see [Configuration](/docs/configuration/overview). For best +practices when writing custom filters, see +[Custom Filters](custom-filters). diff --git a/docs/getting-started/_category_.json b/docs/getting-started/_category_.json new file mode 100644 index 0000000000..3562d433d7 --- /dev/null +++ b/docs/getting-started/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Getting Started", + "position": 1 +} diff --git a/docs/features.md b/docs/getting-started/features.md similarity index 96% rename from docs/features.md rename to docs/getting-started/features.md index 99bec14659..63f2a721ec 100644 --- a/docs/features.md +++ b/docs/getting-started/features.md @@ -1,3 +1,8 @@ +--- +sidebar_position: 4 +title: Features +--- + # Features ## Core Architecture @@ -84,14 +89,14 @@ - **Payload size limits**: global hard ceilings on request and response payload size. -[payload-processing]:./architecture/payload-processing.md +[payload-processing]:../architecture/system-design#payload-processing ## Security Security is a primary design constraint. Praxis ships with secure defaults and fails closed on ambiguous configuration. See the -[Security Hardening Guide](operating/security-hardening.md) for +[Security Hardening Guide](../security/hardening) for deployment guidance. **Build-level guarantees:** @@ -197,10 +202,10 @@ deployment guidance. server instance. See [Protocol Abstraction][protocol-abstraction]. -[http-lifecycle]:./architecture/connection-lifecycle.md#http-connection-lifecycle -[tcp-lifecycle]:./architecture/connection-lifecycle.md#tcp-connection-lifecycle -[protocol-abstraction]:./architecture/overview.md#protocol-adapters -[tls-docs]:./operating/tls.md +[http-lifecycle]:../architecture/system-design#http-connection-lifecycle +[tcp-lifecycle]:../architecture/system-design#tcp-connection-lifecycle +[protocol-abstraction]:../architecture/system-design#protocol-adapters +[tls-docs]:../protocols/tls ## AI Inference @@ -316,4 +321,4 @@ cargo build -p praxis --no-default-features zero overhead via the `HttpFilter`/`TcpFilter` traits and `register_filters!` macro. -[filters]:./filters/README.md +[filters]:../filters/filter-model diff --git a/docs/getting-started/installation.md b/docs/getting-started/installation.md new file mode 100644 index 0000000000..89a1c3d870 --- /dev/null +++ b/docs/getting-started/installation.md @@ -0,0 +1,78 @@ +--- +sidebar_position: 3 +title: Installation +--- + +# Installation + +## Prerequisites + +- **Rust** stable 1.94 or later +- **CMake** 3.31 or later (required for building some native dependencies) + +## Building from Source + +Clone the repository and build the release binary: + +```console +git clone https://github.com/praxis-proxy/praxis.git +cd praxis +make release +``` + +The binary will be at `./target/release/praxis`. + +To verify the build: + +```console +./target/release/praxis --version +``` + +## Docker + +Pull and run the official container image: + +```console +docker pull ghcr.io/praxis-proxy/praxis:latest +docker run -p 8080:8080 ghcr.io/praxis-proxy/praxis:latest +``` + +To run with a custom configuration file: + +```console +docker run -p 8080:8080 \ + -v /path/to/praxis.yaml:/etc/praxis/praxis.yaml:ro \ + ghcr.io/praxis-proxy/praxis:latest \ + -c /etc/praxis/praxis.yaml +``` + +### Building the Container Image + +To build the container image locally: + +```console +make container +``` + +## Development Setup + +For development, you will also need: + +- **Rust nightly** (for `rustfmt`) +- **Docker** 29.3.0+ or Podman (for container builds and comparison benchmarks) + +```console +# Install Rust nightly for formatting +rustup install nightly + +# Build in debug mode (faster compilation) +make build + +# Run all tests +make test + +# Check formatting and lints +make lint +``` + +See the [Testing](/docs/development/testing) guide for more development commands. diff --git a/docs/getting-started/introduction.md b/docs/getting-started/introduction.md new file mode 100644 index 0000000000..e2e4f63016 --- /dev/null +++ b/docs/getting-started/introduction.md @@ -0,0 +1,34 @@ +--- +sidebar_position: 1 +title: Introduction +--- + +# Praxis + +Praxis is a high-performance and security-first proxy server and framework for AI and cloud-native workloads. + +## Getting Started + +- [Quickstart](quickstart) +- [Example configs](https://github.com/praxis-proxy/praxis/tree/main/examples) + +## Documentation + +- [Configuration](/docs/configuration/overview) +- [Filters](/docs/filters/filter-model) +- [Custom Filters](/docs/filters/custom-filters) +- [TLS & mTLS](/docs/protocols/tls) +- [Security Hardening](/docs/security/hardening) + +## Contributing + +[Issues](https://github.com/praxis-proxy/praxis/issues/new) and [pull requests](https://github.com/praxis-proxy/praxis/compare) are welcome. Familiarize yourself +with the following documentation first: + +- [Architecture](/docs/architecture/system-design) +- [Contributing](/docs/development/contributing) +- [Testing](/docs/development/testing) +- [Benchmarks](/docs/development/benchmarks) + +For larger changes, open a [discussion](https://github.com/praxis-proxy/praxis/discussions) and follow the +[proposal process](/docs/development/proposals). diff --git a/docs/quickstart.md b/docs/getting-started/quickstart.md similarity index 73% rename from docs/quickstart.md rename to docs/getting-started/quickstart.md index 14b2bb44f6..ec86c650bc 100644 --- a/docs/quickstart.md +++ b/docs/getting-started/quickstart.md @@ -1,3 +1,8 @@ +--- +sidebar_position: 2 +title: Quickstart +--- + # Quickstart Build the release binary: @@ -62,9 +67,9 @@ curl http://127.0.0.1:8080/ ## Next steps -- [Configuration](operating/configuration.md): filter - chains, routing, load balancing, TLS, and all options. -- [Example configs](../examples/configs/): working YAML +- [Configuration](/docs/configuration/overview): filter chains, + routing, load balancing, TLS, and all options. +- [Example configs](https://github.com/praxis-proxy/praxis/tree/main/examples/configs): working YAML for every feature. -- [Filters](filters/README.md): built-in filters and - how to write your own. +- [Filters](/docs/filters/filter-model): built-in filters and how to + write your own. diff --git a/docs/protocols/_category_.json b/docs/protocols/_category_.json new file mode 100644 index 0000000000..a58e2b3511 --- /dev/null +++ b/docs/protocols/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Protocols", + "position": 5 +} diff --git a/docs/protocols/tls.md b/docs/protocols/tls.md new file mode 100644 index 0000000000..4fdc99a691 --- /dev/null +++ b/docs/protocols/tls.md @@ -0,0 +1,172 @@ +--- +sidebar_position: 3 +title: TLS & mTLS +--- + +# TLS + +Working example configs for every TLS scenario live in +[`examples/configs/protocols/`](https://github.com/praxis-proxy/praxis/tree/main/examples/configs/protocols): + +| Example | Scenario | +| ------- | -------- | +| [tls-termination](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/protocols/tls-termination.yaml) | HTTPS listener, plain HTTP upstream | +| [tls-http-reencrypt](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/protocols/tls-http-reencrypt.yaml) | HTTPS listener, TLS upstream | +| [tls-multi-cert](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/protocols/tls-multi-cert.yaml) | SNI with multiple certificates | +| [tls-version-constraint](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/protocols/tls-version-constraint.yaml) | TLS 1.3 only | +| [tls-mtls-listener](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/protocols/tls-mtls-listener.yaml) | Require client certificate | +| [tls-mtls-listener-request](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/protocols/tls-mtls-listener-request.yaml) | Request (optional) client cert | +| [tls-mtls-upstream](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/protocols/tls-mtls-upstream.yaml) | Client cert to upstream | +| [tls-mtls-both](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/protocols/tls-mtls-both.yaml) | mTLS on both sides | +| [tls-verify-disabled](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/protocols/tls-verify-disabled.yaml) | Skip upstream cert verify (dev) | +| [upstream-tls](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/protocols/upstream-tls.yaml) | Plain listener, TLS upstream | +| [upstream-ca-file](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/protocols/upstream-ca-file.yaml) | Global CA for all upstreams | +| [tcp-tls-termination](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/protocols/tcp-tls-termination.yaml) | TLS on TCP listener | +| [tcp-tls-mtls](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/protocols/tcp-tls-mtls.yaml) | mTLS on TCP listener | + +## Listener TLS + +Add `tls` to any listener. PEM format; the cert file +may include the full chain. See [tls-termination](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/protocols/tls-termination.yaml) for +a complete example. + +```yaml +tls: + certificates: + - cert_path: /etc/praxis/tls/cert.pem + key_path: /etc/praxis/tls/key.pem +``` + +### SNI and Multiple Certificates + +Multiple certificates on a single listener enable +SNI-based selection. Entries with `server_names` match +those hostnames; wildcard entries like `*.example.com` +match single-level subdomains. Mark exactly one entry with +`default: true` to serve as the fallback for unmatched +SNI. An entry without `server_names` that is not marked +`default: true` is rejected as ambiguous. If no entry +has `default: true`, unmatched SNI is rejected (no +fallback). See [tls-multi-cert](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/protocols/tls-multi-cert.yaml). + +### Certificate Hot-Reload + +Certificate hot-reload is enabled by default. Cert and +key files are watched for changes. When modified (e.g. by +certbot, cert-manager, or Vault PKI), the proxy atomically +picks up the new certificate within 500ms. Existing +connections are unaffected; only new TLS handshakes use the +rotated certificate. + +To explicitly disable hot-reload, set `hot_reload: false`. +Multi-cert SNI configs auto-disable hot-reload. + +**Constraints:** + +- Hot-reload applies only to single-cert listeners. + Multi-cert SNI configs are automatically excluded. +- If the new certificate fails to parse, the proxy logs + a warning and continues serving the previous valid + certificate. Consecutive failures trigger exponential + backoff (up to 60s) to avoid log spam. + +**Debounce behavior:** filesystem events are debounced by +500ms to handle atomic rename patterns used by Kubernetes +secret mounts, certbot, and cert-manager. A cert-manager +rotation that writes a temp file and then renames it over +the original triggers a single reload after the rename +completes. + +**Alternative: graceful restart.** Pingora supports +graceful restart via SIGHUP with FD passing. This reloads +all configuration including certificates, but drains +in-flight connections. Use graceful restart when +hot-reload is not needed or for config changes beyond +certificate rotation. + +### Minimum TLS Version + +`min_version` restricts the minimum protocol version: +`tls12` (default) or `tls13`. See +[tls-version-constraint](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/protocols/tls-version-constraint.yaml). + +### Listener mTLS + +Require or request client certificates with +`client_ca` and `client_cert_mode`. + +| Mode | Behavior | +| ---- | -------- | +| `none` | Do not request a client certificate (default) | +| `request` | Ask for a cert but allow connections without one | +| `require` | Reject connections without a valid client cert | + +`client_ca` is required when mode is `request` or +`require`. See [tls-mtls-listener](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/protocols/tls-mtls-listener.yaml) and +[tls-mtls-listener-request](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/protocols/tls-mtls-listener-request.yaml). + +### Local dev with mkcert + +```console +mkcert -install +mkcert localhost 127.0.0.1 +``` + +Point `cert_path` and `key_path` at the generated files. + +## Cluster TLS + +Add `tls:` to a cluster to TLS-connect to endpoints. +`sni` sets the backend SNI hostname. `verify` controls +certificate verification (default: `true`). See +[upstream-tls](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/protocols/upstream-tls.yaml) and [tls-verify-disabled](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/protocols/tls-verify-disabled.yaml). + +### Upstream mTLS (Client Certificate) + +Present a client certificate to upstream servers. +See [tls-mtls-upstream](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/protocols/tls-mtls-upstream.yaml) and [tls-mtls-both](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/protocols/tls-mtls-both.yaml). + +## CA Trust + +Three levels of CA trust, evaluated in order: + +1. **Per-cluster CA** (`tls.ca.ca_path`): applies to + one cluster only. +2. **Global CA** (`runtime.upstream_ca_file`): applies + to all clusters without their own `tls.ca`. +3. **System trust store**: used when neither of the + above is set. + +The global CA **replaces** the system trust store (not +additive). If backends use both a private CA and +public CAs, create a combined PEM bundle. See +[upstream-ca-file](https://github.com/praxis-proxy/praxis/blob/main/examples/configs/protocols/upstream-ca-file.yaml). + +## Timeouts + +Pingora enforces a 60-second TLS handshake timeout +(hardcoded). For total connection budgets (TCP + TLS), +use `total_connection_timeout_ms` on the cluster. See +[Configuration](/docs/configuration/overview) for details. + +## Certificate and Key Security + +Private keys should have restrictive file permissions. +Praxis warns at startup if keys are group or world +readable. + +```console +chmod 600 /etc/praxis/tls/key.pem +chown praxis:praxis /etc/praxis/tls/key.pem +``` + +Don't store private keys in version control or +unencrypted on disk. Use a secrets manager or +encrypted storage solution. + +## Ciphers and Protocol + +Praxis uses rustls, which supports TLS 1.2 and 1.3 +only. No weak cipher suites are available. The cipher +selection follows rustls defaults and is not +configurable at this time. diff --git a/docs/security/_category_.json b/docs/security/_category_.json new file mode 100644 index 0000000000..92fc73946e --- /dev/null +++ b/docs/security/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Security", + "position": 6 +} diff --git a/docs/security/hardening.md b/docs/security/hardening.md new file mode 100644 index 0000000000..2e1611cf02 --- /dev/null +++ b/docs/security/hardening.md @@ -0,0 +1,125 @@ +--- +sidebar_position: 1 +title: Hardening Guide +--- + +# Security Hardening Guide + +Security is a primary motivation of Praxis, not an +afterthought. This guide covers the secure defaults +and operational hardening for production deployments. + +## Default Security Posture + +Praxis ships secure by default and fails closed on +ambiguous configuration: + +- Listeners bind to `127.0.0.1` unless explicitly + configured otherwise. +- TLS certificate verification is enabled by default + for upstream connections. +- Admin endpoints are restricted to localhost; public + binding is a validation error. +- `unsafe_code = "deny"` in workspace lints; no unsafe + Rust in the Praxis codebase. +- Rustls for TLS (no OpenSSL, no C FFI in the TLS + path). +- TLS certificate and key paths reject directory + traversal (`..`). +- Health check targets reject loopback, link-local, + and cloud metadata addresses (SSRF protection). +- Root execution (UID 0) rejected by default. +- Supply chain audited via `cargo audit` and + `cargo deny`. +- Reserved internal headers (`x-praxis-*`, + `x-mcp-*`, `x-a2a-*`) are rejected from client + requests, stripped before forwarding to backends, + and stripped from backend responses before reaching + clients. +- `--dump` redacts credential injection literal + values as `[REDACTED]` to prevent accidental secret + exposure in config dumps. + +## Network Security + +- Bind public-facing listeners to specific interfaces + rather than `0.0.0.0`. +- Place Praxis behind a firewall. Expose only the + ports your listeners require. +- Use separate listeners for public traffic and + internal admin or health-check endpoints. +- Restrict admin and metrics endpoints to internal + networks or loopback addresses. +- Restrict admin endpoints (including KV store API) to + internal networks or loopback addresses. The KV admin + API allows runtime modification of routing and + transformation data. + +## TLS Best Practices + +- Set certificate and key file permissions to `0600`, + owned by the Praxis process user. +- Use `min_version: "1.3"` in TLS configuration. + TLS 1.2 can be used if required, but TLS 1.0 and 1.1 + are deprecated and Praxis will not negotiate them. +- Rotate certificates before expiration. Single-cert + listeners hot-reload certificates automatically + (see [TLS & mTLS](/docs/protocols/tls)). Multi-cert listeners require + a restart. +- Use separate certificate entries with `server_names` + for multi-domain deployments (SNI routing). + +## Access Control + +- **IP ACLs**: Use the `ip_acl` filter to restrict + access by source IP. Use either `allow` or `deny`, + not both (mutually exclusive). An allow-list + implicitly denies all non-matching IPs. +- **Rate Limiting**: Configure `rate_limit` filters + to bound request volume per client or globally. + Tune limits based on expected traffic patterns. +- **CORS**: Use the `cors` filter with explicit + `allow_origins` rather than wildcards. Restrict + `allow_methods` and `allow_headers` to what + your application requires. + +## Deployment + +### Container Security + +- Run the container as a non-root user. The official + image uses a dedicated `praxis` user. +- Mount the filesystem read-only where possible. + Configuration and TLS materials can be mounted as + read-only volumes. +- Drop all Linux capabilities except those required + for binding to privileged ports (if needed). +- Use a minimal base image to reduce attack surface. + +### Kubernetes + +- Set `runAsNonRoot: true` and + `readOnlyRootFilesystem: true` in the pod security + context. +- Use `NetworkPolicy` to restrict traffic. +- Store TLS certificates in Kubernetes `Secret` + objects and mount them read-only. +- Set resource limits to prevent resource exhaustion. + +## Insecure Configuration Options + +The following options weaken security. Use them only +in development: + +- **`verify: false`** on upstream TLS: Disables + certificate verification. Acceptable only for + local development with self-signed certs. +- **Binding to `0.0.0.0`**: Exposes the listener on + all interfaces. Use specific addresses in + production. +- **Wildcard CORS origins (`"*"`)**: Allows any + origin. Use explicit origin lists in production. +- **Empty IP ACL allowlists**: An empty allowlist + permits all traffic. When possible, use principle + of least privilege and only allow access from the + networks that require it. diff --git a/website/.gitignore b/website/.gitignore new file mode 100644 index 0000000000..b2d6de3062 --- /dev/null +++ b/website/.gitignore @@ -0,0 +1,20 @@ +# Dependencies +/node_modules + +# Production +/build + +# Generated files +.docusaurus +.cache-loader + +# Misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/website/README.md b/website/README.md new file mode 100644 index 0000000000..b28211a9bb --- /dev/null +++ b/website/README.md @@ -0,0 +1,41 @@ +# Website + +This website is built using [Docusaurus](https://docusaurus.io/), a modern static website generator. + +## Installation + +```bash +yarn +``` + +## Local Development + +```bash +yarn start +``` + +This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. + +## Build + +```bash +yarn build +``` + +This command generates static content into the `build` directory and can be served using any static contents hosting service. + +## Deployment + +Using SSH: + +```bash +USE_SSH=true yarn deploy +``` + +Not using SSH: + +```bash +GIT_USER= yarn deploy +``` + +If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch. diff --git a/website/blog/2026-06-02-welcome.md b/website/blog/2026-06-02-welcome.md new file mode 100644 index 0000000000..5bd3f1f873 --- /dev/null +++ b/website/blog/2026-06-02-welcome.md @@ -0,0 +1,21 @@ +--- +slug: welcome +title: Welcome to the Praxis Blog +date: 2026-06-02 +authors: + - name: Praxis Team +tags: [announcement] +--- + +Welcome to the Praxis project blog. We'll use this space for release announcements, technical deep-dives, and project updates. + +{/* truncate */} + +Praxis is a high-performance, security-first HTTP proxy and framework for AI and cloud-native workloads. + +Stay tuned for upcoming posts about: + +- Release notes and changelog highlights +- Architecture deep-dives into the filter pipeline +- Guides for building custom filters +- Performance benchmarks and comparisons diff --git a/website/docusaurus.config.ts b/website/docusaurus.config.ts new file mode 100644 index 0000000000..eaadd6d0e1 --- /dev/null +++ b/website/docusaurus.config.ts @@ -0,0 +1,166 @@ +import {themes} from 'prism-react-renderer'; +import type {Config} from '@docusaurus/types'; +import type * as Preset from '@docusaurus/preset-classic'; + +const config: Config = { + title: 'Praxis', + tagline: 'The proxy built for AI infrastructure', + favicon: 'img/favicon.ico', + + future: { + v4: true, + }, + + url: 'https://praxis.fast', + baseUrl: '/', + organizationName: 'praxis-proxy', + projectName: 'praxis', + onBrokenLinks: 'throw', + + markdown: { + hooks: { + onBrokenMarkdownLinks: 'throw', + }, + }, + + i18n: { + defaultLocale: 'en', + locales: ['en'], + }, + + headTags: [ + { + tagName: 'link', + attributes: { + rel: 'preconnect', + href: 'https://fonts.googleapis.com', + }, + }, + { + tagName: 'link', + attributes: { + rel: 'preconnect', + href: 'https://fonts.gstatic.com', + crossorigin: 'anonymous', + }, + }, + { + tagName: 'link', + attributes: { + rel: 'stylesheet', + href: 'https://fonts.googleapis.com/css2?family=Rajdhani:wght@400;500;600;700&family=Hanken+Grotesk:wght@300;400;500;600;700&display=swap', + }, + }, + ], + + presets: [ + [ + 'classic', + { + docs: { + path: '../docs', + sidebarPath: './sidebars.ts', + editUrl: 'https://github.com/praxis-proxy/praxis/tree/main/', + exclude: ['proposals/**', 'superpowers/**'], + }, + blog: { + showReadingTime: true, + onInlineAuthors: 'ignore', + editUrl: 'https://github.com/praxis-proxy/praxis/tree/main/website/', + }, + theme: { + customCss: './src/css/custom.css', + }, + } satisfies Preset.Options, + ], + ], + + themes: [ + [ + '@easyops-cn/docusaurus-search-local', + { + hashed: true, + indexBlog: true, + indexDocs: true, + docsDir: '../docs', + docsRouteBasePath: '/docs', + highlightSearchTermsOnTargetPage: true, + }, + ], + ], + + themeConfig: { + colorMode: { + defaultMode: 'dark', + disableSwitch: true, + respectPrefersColorScheme: false, + }, + navbar: { + title: 'Praxis', + items: [ + { + type: 'docSidebar', + sidebarId: 'docs', + position: 'left', + label: 'Docs', + }, + {to: '/examples', label: 'Examples', position: 'left'}, + {to: '/blog', label: 'Blog', position: 'left'}, + { + href: 'https://github.com/praxis-proxy/praxis', + label: 'GitHub', + position: 'right', + }, + ], + }, + footer: { + style: 'dark', + links: [ + { + title: 'Getting Started', + items: [ + {label: 'Introduction', to: '/docs/getting-started/introduction'}, + {label: 'Quick Start', to: '/docs/getting-started/quickstart'}, + {label: 'Installation', to: '/docs/getting-started/installation'}, + {label: 'Examples', to: '/examples'}, + ], + }, + { + title: 'Documentation', + items: [ + {label: 'Architecture', to: '/docs/architecture/system-design'}, + {label: 'Configuration', to: '/docs/configuration/overview'}, + {label: 'Filters', to: '/docs/filters/filter-model'}, + {label: 'Protocols', to: '/docs/protocols/tls'}, + {label: 'Security', to: '/docs/security/hardening'}, + ], + }, + { + title: 'Community', + items: [ + {label: 'GitHub', href: 'https://github.com/praxis-proxy/praxis'}, + {label: 'Discussions', href: 'https://github.com/praxis-proxy/praxis/discussions'}, + {label: 'Issues', href: 'https://github.com/praxis-proxy/praxis/issues'}, + {label: 'Contributing', to: '/docs/development/contributing'}, + ], + }, + { + title: 'Resources', + items: [ + {label: 'Blog', to: '/blog'}, + {label: 'Benchmarks', to: '/docs/development/benchmarks'}, + {label: 'Releases', href: 'https://github.com/praxis-proxy/praxis/releases'}, + ], + }, + ], + copyright: `Copyright © ${new Date().getFullYear()} Praxis Contributors. MIT License.`, + }, + prism: { + theme: themes.vsDark, + darkTheme: themes.vsDark, + additionalLanguages: ['bash', 'yaml', 'toml', 'rust', 'json'], + }, + } satisfies Preset.ThemeConfig, +}; + +export default config; diff --git a/website/package-lock.json b/website/package-lock.json new file mode 100644 index 0000000000..dcee4198d3 --- /dev/null +++ b/website/package-lock.json @@ -0,0 +1,19950 @@ +{ + "name": "website", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "website", + "version": "0.0.0", + "dependencies": { + "@docusaurus/core": "3.10.1", + "@docusaurus/faster": "3.10.1", + "@docusaurus/preset-classic": "3.10.1", + "@easyops-cn/docusaurus-search-local": "^0.55.1", + "@mdx-js/react": "^3.0.0", + "clsx": "^2.0.0", + "prism-react-renderer": "^2.3.0", + "react": "^19.0.0", + "react-dom": "^19.0.0" + }, + "devDependencies": { + "@docusaurus/module-type-aliases": "3.10.1", + "@docusaurus/tsconfig": "3.10.1", + "@docusaurus/types": "3.10.1", + "@types/react": "^19.0.0", + "typescript": "~6.0.2" + }, + "engines": { + "node": ">=20.0" + } + }, + "node_modules/@algolia/abtesting": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.18.1.tgz", + "integrity": "sha512-aehCadlWOGvrT91KUIZpC0MbB8KBW9yUuvTJFd2xesR7le/IsT4nJUnjCCZ4ZqZCeTcPHPV5mo//fZ5oxcSVYw==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.52.1", + "@algolia/requester-browser-xhr": "5.52.1", + "@algolia/requester-fetch": "5.52.1", + "@algolia/requester-node-http": "5.52.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/autocomplete-core": { + "version": "1.19.8", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.19.8.tgz", + "integrity": "sha512-3YEorYg44niXcm7gkft3nXYItHd44e8tmh4D33CTszPgP0QWkaLEaFywiNyJBo7UL/mqObA/G9RYuU7R8tN1IA==", + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-plugin-algolia-insights": "1.19.8", + "@algolia/autocomplete-shared": "1.19.8" + } + }, + "node_modules/@algolia/autocomplete-plugin-algolia-insights": { + "version": "1.19.8", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.19.8.tgz", + "integrity": "sha512-ZvJWO8ZZJDpc1LNM2TTBdmQsZBLMR4rU5iNR2OYvEeFBiaf/0ESnRSSLQbryarJY4SVxtoz6A2ZtDMNM+iQEAA==", + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-shared": "1.19.8" + }, + "peerDependencies": { + "search-insights": ">= 1 < 3" + } + }, + "node_modules/@algolia/autocomplete-shared": { + "version": "1.19.8", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.19.8.tgz", + "integrity": "sha512-h5hf2t8ejF6vlOgvLaZzQbWs5SyH2z4PAWygNAvvD/2RI29hdQ54ldUGwqVuj9Srs+n8XUKTPUqb7fvhBhQrnQ==", + "license": "MIT", + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@algolia/client-abtesting": { + "version": "5.52.1", + "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.52.1.tgz", + "integrity": "sha512-HmXOGBOAOJPounpBzBpuY0zDYeiCpxgHnQmuA7JO6ScukcBdGp3/XM9zJk5pJx/xNGD68mbPGXWpDxGtl6BwDQ==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.52.1", + "@algolia/requester-browser-xhr": "5.52.1", + "@algolia/requester-fetch": "5.52.1", + "@algolia/requester-node-http": "5.52.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-analytics": { + "version": "5.52.1", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.52.1.tgz", + "integrity": "sha512-5oo4+I8iixie9vXhCyNFCzeIr8pqA3FQ//VsLHTDvZAV4ttYOPGvYHGQq5NSalrLx5Jc3dRro/5uDOlnUMcBJg==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.52.1", + "@algolia/requester-browser-xhr": "5.52.1", + "@algolia/requester-fetch": "5.52.1", + "@algolia/requester-node-http": "5.52.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-common": { + "version": "5.52.1", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.52.1.tgz", + "integrity": "sha512-qCDoZfx5MpX7XQzvQ3bC4tSEMkQWQMaF/ABtLuoze03Y/flR563CCSws02qIJ23oX7lxl92LsilZjINVyTdtLw==", + "license": "MIT", + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-insights": { + "version": "5.52.1", + "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.52.1.tgz", + "integrity": "sha512-hnGs0/lsFJ2PWDxNBz7pxreXo/Xz7gxYRcfePBUjsH26ad0kU/sgnVZd9LwWBpsQv65z2jlb5dkyaB9WE9M9FQ==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.52.1", + "@algolia/requester-browser-xhr": "5.52.1", + "@algolia/requester-fetch": "5.52.1", + "@algolia/requester-node-http": "5.52.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-personalization": { + "version": "5.52.1", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.52.1.tgz", + "integrity": "sha512-2VxxNc/uBysyKvGeBdSM5n9eIDKH8kWD7wd9/yqbJAiVwU4Yv6tU1LSJusHKrXV/aCu1KW7t9Gug9QyeEmtn/Q==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.52.1", + "@algolia/requester-browser-xhr": "5.52.1", + "@algolia/requester-fetch": "5.52.1", + "@algolia/requester-node-http": "5.52.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-query-suggestions": { + "version": "5.52.1", + "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.52.1.tgz", + "integrity": "sha512-O6mPtsw3xEfNOe6gWFpYLeAZAIljNa4Hgna3bq15PwyN7nbjTY0wXJFRbzs/0YVf75Br+SbOQUmjKxXYjDiSiQ==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.52.1", + "@algolia/requester-browser-xhr": "5.52.1", + "@algolia/requester-fetch": "5.52.1", + "@algolia/requester-node-http": "5.52.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-search": { + "version": "5.52.1", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.52.1.tgz", + "integrity": "sha512-gA8oJOV1LnQQkDf91iebNnFInHuW0gRPEgLSOQ7EfipCEjYTHm5swm1DlH9H5RaRw4RrHuzHBegnlzc0MAstcg==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.52.1", + "@algolia/requester-browser-xhr": "5.52.1", + "@algolia/requester-fetch": "5.52.1", + "@algolia/requester-node-http": "5.52.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/events": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@algolia/events/-/events-4.0.1.tgz", + "integrity": "sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ==", + "license": "MIT" + }, + "node_modules/@algolia/ingestion": { + "version": "1.52.1", + "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.52.1.tgz", + "integrity": "sha512-U9zZfc5xIu9wRxZkt+HceJUAD4VKHKbAyLSloJdEyMRmphXeibfrY9cxqIXBcmPeZzGhn3Imb35Dq8l19PkJhw==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.52.1", + "@algolia/requester-browser-xhr": "5.52.1", + "@algolia/requester-fetch": "5.52.1", + "@algolia/requester-node-http": "5.52.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/monitoring": { + "version": "1.52.1", + "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.52.1.tgz", + "integrity": "sha512-a3SGNceHmkQfq77iG8Ka+w1pvwfZa/0lzEIgse30fL0kD+yKnd/dg0dQvSfFPAEt2f21DMcGkDSSeJlO3KdQjQ==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.52.1", + "@algolia/requester-browser-xhr": "5.52.1", + "@algolia/requester-fetch": "5.52.1", + "@algolia/requester-node-http": "5.52.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/recommend": { + "version": "5.52.1", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.52.1.tgz", + "integrity": "sha512-z98QEguCFDpxb4S/PyrUK1igqF8tPsdbqOUUO6ON91vJ58w+Gwa6ncrI0oNXSFcrkxA5EqPKPQ2A1PBCn08TYQ==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.52.1", + "@algolia/requester-browser-xhr": "5.52.1", + "@algolia/requester-fetch": "5.52.1", + "@algolia/requester-node-http": "5.52.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-browser-xhr": { + "version": "5.52.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.52.1.tgz", + "integrity": "sha512-CI7+/0I11QeZM59Uc8whd2or0kqzFVjpaPn9Qpwll/krHcBAxk24WkAQ6WX+IwDVMfpont4YGbKwAmCre3vE8Q==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.52.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-fetch": { + "version": "5.52.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.52.1.tgz", + "integrity": "sha512-S6bDuw9byfOvm3T71cgdoZgrgnZq6hpdMLkx52Louh57nUAmvGQESz2aojOynQHjbTiV55smvAFbgn0qT4tJrg==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.52.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-node-http": { + "version": "5.52.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.52.1.tgz", + "integrity": "sha512-tqZXM+54rWo4mk5jL5Z/flE11nPmNEdXwFBM5py9DkOmbjeCNemfVd45FyM97XdzfZ0dl9uOJC6PYn1FpkeyQg==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.52.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.3", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.3.tgz", + "integrity": "sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.29.3", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.29.3.tgz", + "integrity": "sha512-RpLYy2sb51oNLjuu1iD3bwBqCBWUzjO0ocp+iaCP/lJtb2CPLcnC2Fftw+4sAzaMELGeWTgExSKADbdo0GFVzA==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-member-expression-to-functions": "^7.28.5", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/helper-replace-supers": "^7.28.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/traverse": "^7.29.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.28.5.tgz", + "integrity": "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "regexpu-core": "^6.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.8.tgz", + "integrity": "sha512-47UwBLPpQi1NoWzLuHNjRoHlYXMwIJoBf7MFou6viC/sIHWYygpvr0B6IAyh5sBdA2nr2LPIRww8lfaUVQINBA==", + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "debug": "^4.4.3", + "lodash.debounce": "^4.0.8", + "resolve": "^1.22.11" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz", + "integrity": "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", + "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", + "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-wrap-function": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.28.6.tgz", + "integrity": "sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==", + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.28.5", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", + "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.28.6.tgz", + "integrity": "sha512-z+PwLziMNBeSQJonizz2AGnndLsP2DeGHIxDAn+wdHOGuo4Fo1x1HBPPXeE9TAOPHNNWQKCSlA2VZyYyyibDnQ==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", + "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.3.tgz", + "integrity": "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.28.5.tgz", + "integrity": "sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz", + "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz", + "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": { + "version": "7.29.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-rest-destructuring-rhs-array/-/plugin-bugfix-safari-rest-destructuring-rhs-array-7.29.3.tgz", + "integrity": "sha512-SRS46DFR4HqzUzCVgi90/xMoL+zeBDBvWdKYXSEzh79kXswNFEglUpMKxR04//dPqwYXWUBJ3mpUd933ru9Kmg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", + "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.6.tgz", + "integrity": "sha512-a0aBScVTlNaiUe35UtfxAN7A/tehvvG4/ByO6+46VPKTRSlfnAFsgKy0FUh+qAkQrDTmhDkT+IBOKlOoMUxQ0g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.28.6.tgz", + "integrity": "sha512-pSJUpFHdx9z5nqTSirOCMtYVP2wFgoWhP0p3g8ONK/4IHhLIBd0B9NYqAvIUAhq+OkhO4VM1tENCt0cjlsNShw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz", + "integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz", + "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz", + "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", + "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.29.0.tgz", + "integrity": "sha512-va0VdWro4zlBr2JsXC+ofCPB2iG12wPtVGTWFx2WLDOM3nYQZZIGP82qku2eW/JR83sD+k2k+CsNtyEbUqhU6w==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-remap-async-to-generator": "^7.27.1", + "@babel/traverse": "^7.29.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.28.6.tgz", + "integrity": "sha512-ilTRcmbuXjsMmcZ3HASTe4caH5Tpo93PkTxF9oG2VZsSWsahydmcEHhix9Ik122RcTnZnUzPbmux4wh1swfv7g==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-remap-async-to-generator": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", + "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.6.tgz", + "integrity": "sha512-tt/7wOtBmwHPNMPu7ax4pdPz6shjFrmHDghvNC+FG9Qvj7D6mJcoRQIF5dy4njmxR941l6rgtvfSB2zX3VlUIw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.28.6.tgz", + "integrity": "sha512-dY2wS3I2G7D697VHndN91TJr8/AAfXQNt5ynCTI/MpxMsSzHp+52uNivYT5wCPax3whc47DR8Ba7cmlQMg24bw==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.6.tgz", + "integrity": "sha512-rfQ++ghVwTWTqQ7w8qyDxL1XGihjBss4CmTgGRCTAC9RIbhVpyp4fOeZtta0Lbf+dTNIVJer6ych2ibHwkZqsQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.6.tgz", + "integrity": "sha512-EF5KONAqC5zAqT783iMGuM2ZtmEBy+mJMOKl2BCvPZ2lVrwvXnB6o+OBWCS+CoeCCpVRF2sA2RBKUxvT8tQT5Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-globals": "^7.28.0", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-replace-supers": "^7.28.6", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.28.6.tgz", + "integrity": "sha512-bcc3k0ijhHbc2lEfpFHgx7eYw9KNXqOerKWfzbxEHUGKnS3sz9C4CNL9OiFN1297bDNfUiSO7DaLzbvHQQQ1BQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/template": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.5.tgz", + "integrity": "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.28.6.tgz", + "integrity": "sha512-SljjowuNKB7q5Oayv4FoPzeB74g3QgLt8IVJw9ADvWy3QnUb/01aw8I4AVv8wYnPvQz2GDDZ/g3GhcNyDBI4Bg==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", + "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.29.0.tgz", + "integrity": "sha512-zBPcW2lFGxdiD8PUnPwJjag2J9otbcLQzvbiOzDxpYXyCuYX9agOwMPGn1prVH0a4qzhCKu24rlH4c1f7yA8rw==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz", + "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-explicit-resource-management": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.6.tgz", + "integrity": "sha512-Iao5Konzx2b6g7EPqTy40UZbcdXE126tTxVFr/nAIj+WItNxjKSYTEw3RC+A2/ZetmdJsgueL1KhaMCQHkLPIg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/plugin-transform-destructuring": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.6.tgz", + "integrity": "sha512-WitabqiGjV/vJ0aPOLSFfNY1u9U3R7W36B03r5I2KoNix+a3sOhJ3pKFB3R5It9/UiK78NiO0KE9P21cMhlPkw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz", + "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", + "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", + "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.28.6.tgz", + "integrity": "sha512-Nr+hEN+0geQkzhbdgQVPoqr47lZbm+5fCUmO70722xJZd0Mvb59+33QLImGj6F+DkK3xgDi1YVysP8whD6FQAw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", + "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.6.tgz", + "integrity": "sha512-+anKKair6gpi8VsM/95kmomGNMD0eLz1NQ8+Pfw5sAwWH9fGYXT50E55ZpV0pHUHWf6IUTWPM+f/7AAff+wr9A==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", + "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", + "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.28.6.tgz", + "integrity": "sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.29.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.4.tgz", + "integrity": "sha512-N7QmZ0xRZfjHOfZeQLJjwgX2zS9pdGHSVl/cjSGlo4dXMqvurfxXDMKY4RqEKzPozV78VMcd0lxyG13mlbKc4w==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.29.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", + "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.29.0.tgz", + "integrity": "sha512-1CZQA5KNAD6ZYQLPw7oi5ewtDNxH/2vuCh+6SmvgDfhumForvs8a1o9n0UrEoBD8HU4djO2yWngTQlXl1NDVEQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", + "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.28.6.tgz", + "integrity": "sha512-3wKbRgmzYbw24mDJXT7N+ADXw8BC/imU9yo9c9X9NKaLF1fW+e5H1U5QjMUBe4Qo4Ox/o++IyUkl1sVCLgevKg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.28.6.tgz", + "integrity": "sha512-SJR8hPynj8outz+SlStQSwvziMN4+Bq99it4tMIf5/Caq+3iOc0JtKyse8puvyXkk3eFRIA5ID/XfunGgO5i6w==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.6.tgz", + "integrity": "sha512-5rh+JR4JBC4pGkXLAcYdLHZjXudVxWMXbB6u6+E9lRL5TrGVbHt1TjxGbZ8CkmYw9zjkB7jutzOROArsqtncEA==", + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/plugin-transform-destructuring": "^7.28.5", + "@babel/plugin-transform-parameters": "^7.27.7", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", + "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.28.6.tgz", + "integrity": "sha512-R8ja/Pyrv0OGAvAXQhSTmWyPJPml+0TMqXlO5w+AsMEiwb2fg3WkOvob7UxFSL3OIttFSGSRFKQsOhJ/X6HQdQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.6.tgz", + "integrity": "sha512-A4zobikRGJTsX9uqVFdafzGkqD30t26ck2LmOzAuLL8b2x6k3TIqRiT2xVvA9fNmFeTX484VpsdgmKNA0bS23w==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.27.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz", + "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.28.6.tgz", + "integrity": "sha512-piiuapX9CRv7+0st8lmuUlRSmX6mBcVeNQ1b4AYzJxfCMuBfB0vBXDiGSmm03pKJw1v6cZ8KSeM+oUnM6yAExg==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.28.6.tgz", + "integrity": "sha512-b97jvNSOb5+ehyQmBpmhOCiUC5oVK4PMnpRvO7+ymFBoqYjeDHIU9jnrNUuwHOiL9RpGDoKBpSViarV+BU+eVA==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", + "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-constant-elements": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.27.1.tgz", + "integrity": "sha512-edoidOjl/ZxvYo4lSBOQGDSyToYVkTAwyVoa2tkuYTSmjrB1+uAedoL5iROVLXkxH+vRgA7uP4tMg2pUJpZ3Ug==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.28.0.tgz", + "integrity": "sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.28.6.tgz", + "integrity": "sha512-61bxqhiRfAACulXSLd/GxqmAedUSrRZIu/cbaT18T1CetkTmtDN15it7i80ru4DVqRK1WMxQhXs+Lf9kajm5Ow==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/plugin-syntax-jsx": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.27.1.tgz", + "integrity": "sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q==", + "license": "MIT", + "dependencies": { + "@babel/plugin-transform-react-jsx": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-pure-annotations": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.27.1.tgz", + "integrity": "sha512-JfuinvDOsD9FVMTHpzA/pBLisxpv1aSf+OIV8lgH3MuWrks19R27e6a6DipIg4aX1Zm9Wpb04p8wljfKrVSnPA==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.29.0.tgz", + "integrity": "sha512-FijqlqMA7DmRdg/aINBSs04y8XNTYw/lr1gJ2WsmBnnaNw1iS43EPkJW+zK7z65auG3AWRFXWj+NcTQwYptUog==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regexp-modifiers": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.28.6.tgz", + "integrity": "sha512-QGWAepm9qxpaIs7UM9FvUSnCGlb8Ua1RhyM4/veAxLwt3gMat/LSGrZixyuj4I6+Kn9iwvqCyPTtbdxanYoWYg==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", + "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.29.0.tgz", + "integrity": "sha512-jlaRT5dJtMaMCV6fAuLbsQMSwz/QkvaHOHOSXRitGGwSpR1blCY4KUKoyP2tYO8vJcqYe8cEj96cqSztv3uF9w==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "babel-plugin-polyfill-corejs2": "^0.4.14", + "babel-plugin-polyfill-corejs3": "^0.13.0", + "babel-plugin-polyfill-regenerator": "^0.6.5", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", + "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.28.6.tgz", + "integrity": "sha512-9U4QObUC0FtJl05AsUcodau/RWDytrU6uKgkxu09mLR9HLDAtUMoPuuskm5huQsoktmsYpI+bGmq+iapDcriKA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", + "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", + "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", + "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.6.tgz", + "integrity": "sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", + "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.28.6.tgz", + "integrity": "sha512-4Wlbdl/sIZjzi/8St0evF0gEZrgOswVO6aOzqxh1kDZOl9WmLrHq2HtGhnOJZmHZYKP8WZ1MDLCt5DAWwRo57A==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", + "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.28.6.tgz", + "integrity": "sha512-/wHc/paTUmsDYN7SZkpWxogTOBNnlx7nBQYfy6JJlCT7G3mVhltk3e++N7zV0XfgGsrqBxd4rJQt9H16I21Y1Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.29.5", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.29.5.tgz", + "integrity": "sha512-/69t2aEzGKHD76DyLbHysF/QH2LJOB8iFnYO37unDTKBTubzcMRv0f3H5EiN1Q6ajOd/eB7dAInF0qdFVS06kA==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.3", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", + "@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": "^7.29.3", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.6", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-import-assertions": "^7.28.6", + "@babel/plugin-syntax-import-attributes": "^7.28.6", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.27.1", + "@babel/plugin-transform-async-generator-functions": "^7.29.0", + "@babel/plugin-transform-async-to-generator": "^7.28.6", + "@babel/plugin-transform-block-scoped-functions": "^7.27.1", + "@babel/plugin-transform-block-scoping": "^7.28.6", + "@babel/plugin-transform-class-properties": "^7.28.6", + "@babel/plugin-transform-class-static-block": "^7.28.6", + "@babel/plugin-transform-classes": "^7.28.6", + "@babel/plugin-transform-computed-properties": "^7.28.6", + "@babel/plugin-transform-destructuring": "^7.28.5", + "@babel/plugin-transform-dotall-regex": "^7.28.6", + "@babel/plugin-transform-duplicate-keys": "^7.27.1", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.29.0", + "@babel/plugin-transform-dynamic-import": "^7.27.1", + "@babel/plugin-transform-explicit-resource-management": "^7.28.6", + "@babel/plugin-transform-exponentiation-operator": "^7.28.6", + "@babel/plugin-transform-export-namespace-from": "^7.27.1", + "@babel/plugin-transform-for-of": "^7.27.1", + "@babel/plugin-transform-function-name": "^7.27.1", + "@babel/plugin-transform-json-strings": "^7.28.6", + "@babel/plugin-transform-literals": "^7.27.1", + "@babel/plugin-transform-logical-assignment-operators": "^7.28.6", + "@babel/plugin-transform-member-expression-literals": "^7.27.1", + "@babel/plugin-transform-modules-amd": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.28.6", + "@babel/plugin-transform-modules-systemjs": "^7.29.4", + "@babel/plugin-transform-modules-umd": "^7.27.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.29.0", + "@babel/plugin-transform-new-target": "^7.27.1", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.28.6", + "@babel/plugin-transform-numeric-separator": "^7.28.6", + "@babel/plugin-transform-object-rest-spread": "^7.28.6", + "@babel/plugin-transform-object-super": "^7.27.1", + "@babel/plugin-transform-optional-catch-binding": "^7.28.6", + "@babel/plugin-transform-optional-chaining": "^7.28.6", + "@babel/plugin-transform-parameters": "^7.27.7", + "@babel/plugin-transform-private-methods": "^7.28.6", + "@babel/plugin-transform-private-property-in-object": "^7.28.6", + "@babel/plugin-transform-property-literals": "^7.27.1", + "@babel/plugin-transform-regenerator": "^7.29.0", + "@babel/plugin-transform-regexp-modifiers": "^7.28.6", + "@babel/plugin-transform-reserved-words": "^7.27.1", + "@babel/plugin-transform-shorthand-properties": "^7.27.1", + "@babel/plugin-transform-spread": "^7.28.6", + "@babel/plugin-transform-sticky-regex": "^7.27.1", + "@babel/plugin-transform-template-literals": "^7.27.1", + "@babel/plugin-transform-typeof-symbol": "^7.27.1", + "@babel/plugin-transform-unicode-escapes": "^7.27.1", + "@babel/plugin-transform-unicode-property-regex": "^7.28.6", + "@babel/plugin-transform-unicode-regex": "^7.27.1", + "@babel/plugin-transform-unicode-sets-regex": "^7.28.6", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.15", + "babel-plugin-polyfill-corejs3": "^0.14.0", + "babel-plugin-polyfill-regenerator": "^0.6.6", + "core-js-compat": "^3.48.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.2.tgz", + "integrity": "sha512-coWpDLJ410R781Npmn/SIBZEsAetR4xVi0SxLMXPaMO4lSf1MwnkGYMtkFxew0Dn8B3/CpbpYxN0JCgg8mn67g==", + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.8", + "core-js-compat": "^3.48.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-react": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.28.5.tgz", + "integrity": "sha512-Z3J8vhRq7CeLjdC58jLv4lnZ5RKFUJWqH5emvxmv9Hv3BD1T9R/Im713R4MTKwvFaV74ejZ3sM01LyEKk4ugNQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-transform-react-display-name": "^7.28.0", + "@babel/plugin-transform-react-jsx": "^7.27.1", + "@babel/plugin-transform-react-jsx-development": "^7.27.1", + "@babel/plugin-transform-react-pure-annotations": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.28.5.tgz", + "integrity": "sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-typescript": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", + "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@csstools/cascade-layer-name-parser": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@csstools/cascade-layer-name-parser/-/cascade-layer-name-parser-2.0.5.tgz", + "integrity": "sha512-p1ko5eHgV+MgXFVa4STPKpvPxr6ReS8oS2jzTukjR74i5zJNyWO1ZM1m8YKBXnzDKWfBN1ztLYlHxbVemDD88A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/color-helpers": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", + "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/css-calc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", + "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", + "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^5.1.0", + "@csstools/css-calc": "^2.1.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", + "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", + "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/media-query-list-parser": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-4.0.3.tgz", + "integrity": "sha512-HAYH7d3TLRHDOUQK4mZKf9k9Ph/m8Akstg66ywKR4SFAigjs3yBiUeZtFxywiTm5moZMAp/5W/ZuFnNXXYLuuQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/postcss-alpha-function": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-alpha-function/-/postcss-alpha-function-1.0.1.tgz", + "integrity": "sha512-isfLLwksH3yHkFXfCI2Gcaqg7wGGHZZwunoJzEZk0yKYIokgre6hYVFibKL3SYAoR1kBXova8LB+JoO5vZzi9w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-cascade-layers": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-5.0.2.tgz", + "integrity": "sha512-nWBE08nhO8uWl6kSAeCx4im7QfVko3zLrtgWZY4/bP87zrSPpSyN/3W3TDqz1jJuH+kbKOHXg5rJnK+ZVYcFFg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/selector-specificity": "^5.0.0", + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-cascade-layers/node_modules/@csstools/selector-specificity": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", + "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } + }, + "node_modules/@csstools/postcss-cascade-layers/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@csstools/postcss-color-function": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function/-/postcss-color-function-4.0.12.tgz", + "integrity": "sha512-yx3cljQKRaSBc2hfh8rMZFZzChaFgwmO2JfFgFr1vMcF3C/uyy5I4RFIBOIWGq1D+XbKCG789CGkG6zzkLpagA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-color-function-display-p3-linear": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function-display-p3-linear/-/postcss-color-function-display-p3-linear-1.0.1.tgz", + "integrity": "sha512-E5qusdzhlmO1TztYzDIi8XPdPoYOjoTY6HBYBCYSj+Gn4gQRBlvjgPQXzfzuPQqt8EhkC/SzPKObg4Mbn8/xMg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-color-mix-function": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-mix-function/-/postcss-color-mix-function-3.0.12.tgz", + "integrity": "sha512-4STERZfCP5Jcs13P1U5pTvI9SkgLgfMUMhdXW8IlJWkzOOOqhZIjcNhWtNJZes2nkBDsIKJ0CJtFtuaZ00moag==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-color-mix-variadic-function-arguments": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-mix-variadic-function-arguments/-/postcss-color-mix-variadic-function-arguments-1.0.2.tgz", + "integrity": "sha512-rM67Gp9lRAkTo+X31DUqMEq+iK+EFqsidfecmhrteErxJZb6tUoJBVQca1Vn1GpDql1s1rD1pKcuYzMsg7Z1KQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-content-alt-text": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@csstools/postcss-content-alt-text/-/postcss-content-alt-text-2.0.8.tgz", + "integrity": "sha512-9SfEW9QCxEpTlNMnpSqFaHyzsiRpZ5J5+KqCu1u5/eEJAWsMhzT40qf0FIbeeglEvrGRMdDzAxMIz3wqoGSb+Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-contrast-color-function": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/@csstools/postcss-contrast-color-function/-/postcss-contrast-color-function-2.0.12.tgz", + "integrity": "sha512-YbwWckjK3qwKjeYz/CijgcS7WDUCtKTd8ShLztm3/i5dhh4NaqzsbYnhm4bjrpFpnLZ31jVcbK8YL77z3GBPzA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-exponential-functions": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@csstools/postcss-exponential-functions/-/postcss-exponential-functions-2.0.9.tgz", + "integrity": "sha512-abg2W/PI3HXwS/CZshSa79kNWNZHdJPMBXeZNyPQFbbj8sKO3jXxOt/wF7juJVjyDTc6JrvaUZYFcSBZBhaxjw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-calc": "^2.1.4", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-font-format-keywords": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-4.0.0.tgz", + "integrity": "sha512-usBzw9aCRDvchpok6C+4TXC57btc4bJtmKQWOHQxOVKen1ZfVqBUuCZ/wuqdX5GHsD0NRSr9XTP+5ID1ZZQBXw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-gamut-mapping": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@csstools/postcss-gamut-mapping/-/postcss-gamut-mapping-2.0.11.tgz", + "integrity": "sha512-fCpCUgZNE2piVJKC76zFsgVW1apF6dpYsqGyH8SIeCcM4pTEsRTWTLCaJIMKFEundsCKwY1rwfhtrio04RJ4Dw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-gradients-interpolation-method": { + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/@csstools/postcss-gradients-interpolation-method/-/postcss-gradients-interpolation-method-5.0.12.tgz", + "integrity": "sha512-jugzjwkUY0wtNrZlFeyXzimUL3hN4xMvoPnIXxoZqxDvjZRiSh+itgHcVUWzJ2VwD/VAMEgCLvtaJHX+4Vj3Ow==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-hwb-function": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/@csstools/postcss-hwb-function/-/postcss-hwb-function-4.0.12.tgz", + "integrity": "sha512-mL/+88Z53KrE4JdePYFJAQWFrcADEqsLprExCM04GDNgHIztwFzj0Mbhd/yxMBngq0NIlz58VVxjt5abNs1VhA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-ic-unit": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@csstools/postcss-ic-unit/-/postcss-ic-unit-4.0.4.tgz", + "integrity": "sha512-yQ4VmossuOAql65sCPppVO1yfb7hDscf4GseF0VCA/DTDaBc0Wtf8MTqVPfjGYlT5+2buokG0Gp7y0atYZpwjg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-initial": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-initial/-/postcss-initial-2.0.1.tgz", + "integrity": "sha512-L1wLVMSAZ4wovznquK0xmC7QSctzO4D0Is590bxpGqhqjboLXYA16dWZpfwImkdOgACdQ9PqXsuRroW6qPlEsg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-is-pseudo-class": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-5.0.3.tgz", + "integrity": "sha512-jS/TY4SpG4gszAtIg7Qnf3AS2pjcUM5SzxpApOrlndMeGhIbaTzWBzzP/IApXoNWEW7OhcjkRT48jnAUIFXhAQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/selector-specificity": "^5.0.0", + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-is-pseudo-class/node_modules/@csstools/selector-specificity": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", + "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } + }, + "node_modules/@csstools/postcss-is-pseudo-class/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@csstools/postcss-light-dark-function": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@csstools/postcss-light-dark-function/-/postcss-light-dark-function-2.0.11.tgz", + "integrity": "sha512-fNJcKXJdPM3Lyrbmgw2OBbaioU7yuKZtiXClf4sGdQttitijYlZMD5K7HrC/eF83VRWRrYq6OZ0Lx92leV2LFA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-logical-float-and-clear": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-float-and-clear/-/postcss-logical-float-and-clear-3.0.0.tgz", + "integrity": "sha512-SEmaHMszwakI2rqKRJgE+8rpotFfne1ZS6bZqBoQIicFyV+xT1UF42eORPxJkVJVrH9C0ctUgwMSn3BLOIZldQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-logical-overflow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-overflow/-/postcss-logical-overflow-2.0.0.tgz", + "integrity": "sha512-spzR1MInxPuXKEX2csMamshR4LRaSZ3UXVaRGjeQxl70ySxOhMpP2252RAFsg8QyyBXBzuVOOdx1+bVO5bPIzA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-logical-overscroll-behavior": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-overscroll-behavior/-/postcss-logical-overscroll-behavior-2.0.0.tgz", + "integrity": "sha512-e/webMjoGOSYfqLunyzByZj5KKe5oyVg/YSbie99VEaSDE2kimFm0q1f6t/6Jo+VVCQ/jbe2Xy+uX+C4xzWs4w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-logical-resize": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-resize/-/postcss-logical-resize-3.0.0.tgz", + "integrity": "sha512-DFbHQOFW/+I+MY4Ycd/QN6Dg4Hcbb50elIJCfnwkRTCX05G11SwViI5BbBlg9iHRl4ytB7pmY5ieAFk3ws7yyg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-logical-viewport-units": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-viewport-units/-/postcss-logical-viewport-units-3.0.4.tgz", + "integrity": "sha512-q+eHV1haXA4w9xBwZLKjVKAWn3W2CMqmpNpZUk5kRprvSiBEGMgrNH3/sJZ8UA3JgyHaOt3jwT9uFa4wLX4EqQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-media-minmax": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@csstools/postcss-media-minmax/-/postcss-media-minmax-2.0.9.tgz", + "integrity": "sha512-af9Qw3uS3JhYLnCbqtZ9crTvvkR+0Se+bBqSr7ykAnl9yKhk6895z9rf+2F4dClIDJWxgn0iZZ1PSdkhrbs2ig==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/css-calc": "^2.1.4", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/media-query-list-parser": "^4.0.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-media-queries-aspect-ratio-number-values": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/postcss-media-queries-aspect-ratio-number-values/-/postcss-media-queries-aspect-ratio-number-values-3.0.5.tgz", + "integrity": "sha512-zhAe31xaaXOY2Px8IYfoVTB3wglbJUVigGphFLj6exb7cjZRH9A6adyE22XfFK3P2PzwRk0VDeTJmaxpluyrDg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/media-query-list-parser": "^4.0.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-nested-calc": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-nested-calc/-/postcss-nested-calc-4.0.0.tgz", + "integrity": "sha512-jMYDdqrQQxE7k9+KjstC3NbsmC063n1FTPLCgCRS2/qHUbHM0mNy9pIn4QIiQGs9I/Bg98vMqw7mJXBxa0N88A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-normalize-display-values": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.1.tgz", + "integrity": "sha512-TQUGBuRvxdc7TgNSTevYqrL8oItxiwPDixk20qCB5me/W8uF7BPbhRrAvFuhEoywQp/woRsUZ6SJ+sU5idZAIA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-oklab-function": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/@csstools/postcss-oklab-function/-/postcss-oklab-function-4.0.12.tgz", + "integrity": "sha512-HhlSmnE1NKBhXsTnNGjxvhryKtO7tJd1w42DKOGFD6jSHtYOrsJTQDKPMwvOfrzUAk8t7GcpIfRyM7ssqHpFjg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-position-area-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-position-area-property/-/postcss-position-area-property-1.0.0.tgz", + "integrity": "sha512-fUP6KR8qV2NuUZV3Cw8itx0Ep90aRjAZxAEzC3vrl6yjFv+pFsQbR18UuQctEKmA72K9O27CoYiKEgXxkqjg8Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-progressive-custom-properties": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-4.2.1.tgz", + "integrity": "sha512-uPiiXf7IEKtUQXsxu6uWtOlRMXd2QWWy5fhxHDnPdXKCQckPP3E34ZgDoZ62r2iT+UOgWsSbM4NvHE5m3mAEdw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-property-rule-prelude-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-property-rule-prelude-list/-/postcss-property-rule-prelude-list-1.0.0.tgz", + "integrity": "sha512-IxuQjUXq19fobgmSSvUDO7fVwijDJaZMvWQugxfEUxmjBeDCVaDuMpsZ31MsTm5xbnhA+ElDi0+rQ7sQQGisFA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-random-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-random-function/-/postcss-random-function-2.0.1.tgz", + "integrity": "sha512-q+FQaNiRBhnoSNo+GzqGOIBKoHQ43lYz0ICrV+UudfWnEF6ksS6DsBIJSISKQT2Bvu3g4k6r7t0zYrk5pDlo8w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-calc": "^2.1.4", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-relative-color-syntax": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/@csstools/postcss-relative-color-syntax/-/postcss-relative-color-syntax-3.0.12.tgz", + "integrity": "sha512-0RLIeONxu/mtxRtf3o41Lq2ghLimw0w9ByLWnnEVuy89exmEEq8bynveBxNW3nyHqLAFEeNtVEmC1QK9MZ8Huw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-scope-pseudo-class": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-scope-pseudo-class/-/postcss-scope-pseudo-class-4.0.1.tgz", + "integrity": "sha512-IMi9FwtH6LMNuLea1bjVMQAsUhFxJnyLSgOp/cpv5hrzWmrUYU5fm0EguNDIIOHUqzXode8F/1qkC/tEo/qN8Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-scope-pseudo-class/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@csstools/postcss-sign-functions": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@csstools/postcss-sign-functions/-/postcss-sign-functions-1.1.4.tgz", + "integrity": "sha512-P97h1XqRPcfcJndFdG95Gv/6ZzxUBBISem0IDqPZ7WMvc/wlO+yU0c5D/OCpZ5TJoTt63Ok3knGk64N+o6L2Pg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-calc": "^2.1.4", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-stepped-value-functions": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-4.0.9.tgz", + "integrity": "sha512-h9btycWrsex4dNLeQfyU3y3w40LMQooJWFMm/SK9lrKguHDcFl4VMkncKKoXi2z5rM9YGWbUQABI8BT2UydIcA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-calc": "^2.1.4", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-syntax-descriptor-syntax-production": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-syntax-descriptor-syntax-production/-/postcss-syntax-descriptor-syntax-production-1.0.1.tgz", + "integrity": "sha512-GneqQWefjM//f4hJ/Kbox0C6f2T7+pi4/fqTqOFGTL3EjnvOReTqO1qUQ30CaUjkwjYq9qZ41hzarrAxCc4gow==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-tokenizer": "^3.0.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-system-ui-font-family": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-system-ui-font-family/-/postcss-system-ui-font-family-1.0.0.tgz", + "integrity": "sha512-s3xdBvfWYfoPSBsikDXbuorcMG1nN1M6GdU0qBsGfcmNR0A/qhloQZpTxjA3Xsyrk1VJvwb2pOfiOT3at/DuIQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-text-decoration-shorthand": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-4.0.3.tgz", + "integrity": "sha512-KSkGgZfx0kQjRIYnpsD7X2Om9BUXX/Kii77VBifQW9Ih929hK0KNjVngHDH0bFB9GmfWcR9vJYJJRvw/NQjkrA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/color-helpers": "^5.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-trigonometric-functions": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-4.0.9.tgz", + "integrity": "sha512-Hnh5zJUdpNrJqK9v1/E3BbrQhaDTj5YiX7P61TOvUhoDHnUmsNNxcDAgkQ32RrcWx9GVUvfUNPcUkn8R3vIX6A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-calc": "^2.1.4", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-unset-value": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-unset-value/-/postcss-unset-value-4.0.0.tgz", + "integrity": "sha512-cBz3tOCI5Fw6NIFEwU3RiwK6mn3nKegjpJuzCndoGq3BZPkUjnsq7uQmIeMNeMbMk7YD2MfKcgCpZwX5jyXqCA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/utilities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@csstools/utilities/-/utilities-2.0.0.tgz", + "integrity": "sha512-5VdOr0Z71u+Yp3ozOx8T11N703wIFGVRgOWbOZMKgglPJsWA54MRIoMNVMa7shUToIhx5J8vX4sOZgD2XiihiQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@docsearch/core": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/@docsearch/core/-/core-4.6.3.tgz", + "integrity": "sha512-rUOujwIpxJRgD7+kicVsI3D5sqBvdiRTquzWBpTEXZs8ZXfGbfzpus5HqumaNYTppN2HvH8E2yNuRwYdHJeOlA==", + "license": "MIT", + "peerDependencies": { + "@types/react": ">= 16.8.0 < 20.0.0", + "react": ">= 16.8.0 < 20.0.0", + "react-dom": ">= 16.8.0 < 20.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@docsearch/css": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-4.6.3.tgz", + "integrity": "sha512-nlOwcXcsNAptQl4vlL4MA78qNJKO0Qlds5GuBjCoePgkebTXLSf8Qt1oyZ3YBshYupKXG9VRGEsk1zr23d+bzQ==", + "license": "MIT" + }, + "node_modules/@docsearch/react": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-4.6.3.tgz", + "integrity": "sha512-Bg2wdDsoQVlNCcEKuEJAU04tvHCqgx8rIu+uIoM4pRtcx3TBKJuXutJik3LTA8LRc9YEyHkrYUrmcC0D7BYf+g==", + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-core": "1.19.2", + "@docsearch/core": "4.6.3", + "@docsearch/css": "4.6.3" + }, + "peerDependencies": { + "@types/react": ">= 16.8.0 < 20.0.0", + "react": ">= 16.8.0 < 20.0.0", + "react-dom": ">= 16.8.0 < 20.0.0", + "search-insights": ">= 1 < 3" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "search-insights": { + "optional": true + } + } + }, + "node_modules/@docsearch/react/node_modules/@algolia/autocomplete-core": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.19.2.tgz", + "integrity": "sha512-mKv7RyuAzXvwmq+0XRK8HqZXt9iZ5Kkm2huLjgn5JoCPtDy+oh9yxUMfDDaVCw0oyzZ1isdJBc7l9nuCyyR7Nw==", + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-plugin-algolia-insights": "1.19.2", + "@algolia/autocomplete-shared": "1.19.2" + } + }, + "node_modules/@docsearch/react/node_modules/@algolia/autocomplete-plugin-algolia-insights": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.19.2.tgz", + "integrity": "sha512-TjxbcC/r4vwmnZaPwrHtkXNeqvlpdyR+oR9Wi2XyfORkiGkLTVhX2j+O9SaCCINbKoDfc+c2PB8NjfOnz7+oKg==", + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-shared": "1.19.2" + }, + "peerDependencies": { + "search-insights": ">= 1 < 3" + } + }, + "node_modules/@docsearch/react/node_modules/@algolia/autocomplete-shared": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.19.2.tgz", + "integrity": "sha512-jEazxZTVD2nLrC+wYlVHQgpBoBB5KPStrJxLzsIFl6Kqd1AlG9sIAGl39V5tECLpIQzB3Qa2T6ZPJ1ChkwMK/w==", + "license": "MIT", + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@docusaurus/babel": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/babel/-/babel-3.10.1.tgz", + "integrity": "sha512-DZzFO1K3v/GoEt1fx1DiYHF4en+PuhtQf1AkQJa5zu3CoeKSpr5cpQRUlz3jr0m44wyzmSXu9bVpfir+N4+8bg==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.9", + "@babel/generator": "^7.25.9", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-transform-runtime": "^7.25.9", + "@babel/preset-env": "^7.25.9", + "@babel/preset-react": "^7.25.9", + "@babel/preset-typescript": "^7.25.9", + "@babel/runtime": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@docusaurus/logger": "3.10.1", + "@docusaurus/utils": "3.10.1", + "babel-plugin-dynamic-import-node": "^2.3.3", + "fs-extra": "^11.1.1", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + } + }, + "node_modules/@docusaurus/bundler": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/bundler/-/bundler-3.10.1.tgz", + "integrity": "sha512-HIqQPvbqnnQRe4NsBd1774KRarjXqS6wHsWELtyuSs1gCfvixJO2jUGH/OEBtr1Gvzpw+ze5CjGMvSJ8UE1KUw==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.9", + "@docusaurus/babel": "3.10.1", + "@docusaurus/cssnano-preset": "3.10.1", + "@docusaurus/logger": "3.10.1", + "@docusaurus/types": "3.10.1", + "@docusaurus/utils": "3.10.1", + "babel-loader": "^9.2.1", + "clean-css": "^5.3.3", + "copy-webpack-plugin": "^11.0.0", + "css-loader": "^6.11.0", + "css-minimizer-webpack-plugin": "^5.0.1", + "cssnano": "^6.1.2", + "file-loader": "^6.2.0", + "html-minifier-terser": "^7.2.0", + "mini-css-extract-plugin": "^2.9.2", + "null-loader": "^4.0.1", + "postcss": "^8.5.4", + "postcss-loader": "^7.3.4", + "postcss-preset-env": "^10.2.1", + "terser-webpack-plugin": "^5.3.9", + "tslib": "^2.6.0", + "url-loader": "^4.1.1", + "webpack": "^5.95.0", + "webpackbar": "^7.0.0" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "@docusaurus/faster": "*" + }, + "peerDependenciesMeta": { + "@docusaurus/faster": { + "optional": true + } + } + }, + "node_modules/@docusaurus/core": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-3.10.1.tgz", + "integrity": "sha512-3pf2fXXw0eVk8WnC3T4LIigRDupcpvngpKo9Vy7mYyBhuddc0klDUuZAIfzMoK6z05pdlk6EFC/vBSX43+1O5w==", + "license": "MIT", + "dependencies": { + "@docusaurus/babel": "3.10.1", + "@docusaurus/bundler": "3.10.1", + "@docusaurus/logger": "3.10.1", + "@docusaurus/mdx-loader": "3.10.1", + "@docusaurus/utils": "3.10.1", + "@docusaurus/utils-common": "3.10.1", + "@docusaurus/utils-validation": "3.10.1", + "boxen": "^6.2.1", + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "cli-table3": "^0.6.3", + "combine-promises": "^1.1.0", + "commander": "^5.1.0", + "core-js": "^3.31.1", + "detect-port": "^1.5.1", + "escape-html": "^1.0.3", + "eta": "^2.2.0", + "eval": "^0.1.8", + "execa": "^5.1.1", + "fs-extra": "^11.1.1", + "html-tags": "^3.3.1", + "html-webpack-plugin": "^5.6.0", + "leven": "^3.1.0", + "lodash": "^4.17.21", + "open": "^8.4.0", + "p-map": "^4.0.0", + "prompts": "^2.4.2", + "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", + "react-loadable": "npm:@docusaurus/react-loadable@6.0.0", + "react-loadable-ssr-addon-v5-slorber": "^1.0.3", + "react-router": "^5.3.4", + "react-router-config": "^5.1.1", + "react-router-dom": "^5.3.4", + "semver": "^7.5.4", + "serve-handler": "^6.1.7", + "tinypool": "^1.0.2", + "tslib": "^2.6.0", + "update-notifier": "^6.0.2", + "webpack": "^5.95.0", + "webpack-bundle-analyzer": "^4.10.2", + "webpack-dev-server": "^5.2.2", + "webpack-merge": "^6.0.1" + }, + "bin": { + "docusaurus": "bin/docusaurus.mjs" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "@docusaurus/faster": "*", + "@mdx-js/react": "^3.0.0", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@docusaurus/faster": { + "optional": true + } + } + }, + "node_modules/@docusaurus/cssnano-preset": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.10.1.tgz", + "integrity": "sha512-eNfHGcTKCSq6xmcavAkX3RRclHaE2xRCMParlDXLdXVP01/a2e/jKXMj/0ULnLFQSNwwuI62L0Ge8J+nZsR7UQ==", + "license": "MIT", + "dependencies": { + "cssnano-preset-advanced": "^6.1.2", + "postcss": "^8.5.4", + "postcss-sort-media-queries": "^5.2.0", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + } + }, + "node_modules/@docusaurus/faster": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/faster/-/faster-3.10.1.tgz", + "integrity": "sha512-XTZhE5C1gZ/DaYYMlSk02dwP5vhpQON5QHVz1s3892mSESAywgWanURpXEDAvt4GvGuq7s+XP8rTWHZvfaJmdQ==", + "license": "MIT", + "dependencies": { + "@docusaurus/types": "3.10.1", + "@rspack/core": "^1.7.10", + "@swc/core": "^1.7.39", + "@swc/html": "^1.13.5", + "browserslist": "^4.24.2", + "lightningcss": "^1.27.0", + "semver": "^7.5.4", + "swc-loader": "^0.2.6", + "tslib": "^2.6.0", + "webpack": "^5.95.0" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "@docusaurus/types": "*" + } + }, + "node_modules/@docusaurus/logger": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-3.10.1.tgz", + "integrity": "sha512-oPjNFnfJsRCkePVjkGrxWGq4MvJKRQT0r9jOP0eRBTZ7Wr9FAbzdP/Gjs0I2Ss6YRkPoEgygKG112OkE6skvJw==", + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + } + }, + "node_modules/@docusaurus/mdx-loader": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.10.1.tgz", + "integrity": "sha512-GRmeb/wQ+iXRrFwcHBfgQhrJxGElgCsoTWZYDhccjsZVne1p8MK/EpQVIloXttz76TCe78kKD5AEG9n1xc1oxQ==", + "license": "MIT", + "dependencies": { + "@docusaurus/logger": "3.10.1", + "@docusaurus/utils": "3.10.1", + "@docusaurus/utils-validation": "3.10.1", + "@mdx-js/mdx": "^3.0.0", + "@slorber/remark-comment": "^1.0.0", + "escape-html": "^1.0.3", + "estree-util-value-to-estree": "^3.0.1", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "image-size": "^2.0.2", + "mdast-util-mdx": "^3.0.0", + "mdast-util-to-string": "^4.0.0", + "rehype-raw": "^7.0.0", + "remark-directive": "^3.0.0", + "remark-emoji": "^4.0.0", + "remark-frontmatter": "^5.0.0", + "remark-gfm": "^4.0.0", + "stringify-object": "^3.3.0", + "tslib": "^2.6.0", + "unified": "^11.0.3", + "unist-util-visit": "^5.0.0", + "url-loader": "^4.1.1", + "vfile": "^6.0.1", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/module-type-aliases": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.10.1.tgz", + "integrity": "sha512-YoOZKUdGlp8xSYhuAkGdSo5Ydkbq4V4eK3sD8v0a2hloxCWdQbNBhkc+Ko9QyjpESc0BYcIGM5iHVAy5hdFV6w==", + "license": "MIT", + "dependencies": { + "@docusaurus/types": "3.10.1", + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router-config": "*", + "@types/react-router-dom": "*", + "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", + "react-loadable": "npm:@docusaurus/react-loadable@6.0.0" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, + "node_modules/@docusaurus/plugin-content-blog": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.10.1.tgz", + "integrity": "sha512-mmkgE6Q2+K74tnkou7tXlpDLvoCU/qkSa2GSQ3XUiHWvcebCoDQzS670RR3tO8PmaWlIyWWISYWzZLuMfxunRA==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.10.1", + "@docusaurus/logger": "3.10.1", + "@docusaurus/mdx-loader": "3.10.1", + "@docusaurus/theme-common": "3.10.1", + "@docusaurus/types": "3.10.1", + "@docusaurus/utils": "3.10.1", + "@docusaurus/utils-common": "3.10.1", + "@docusaurus/utils-validation": "3.10.1", + "cheerio": "1.0.0-rc.12", + "combine-promises": "^1.1.0", + "feed": "^4.2.2", + "fs-extra": "^11.1.1", + "lodash": "^4.17.21", + "schema-dts": "^1.1.2", + "srcset": "^4.0.0", + "tslib": "^2.6.0", + "unist-util-visit": "^5.0.0", + "utility-types": "^3.10.0", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "@docusaurus/plugin-content-docs": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/plugin-content-docs": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.10.1.tgz", + "integrity": "sha512-2jRVrtzjf8LClGTHQlwlwuD3wQXRx3WEoF7XUarJ8Ou+0onV+SLtejsyfY9JLpfUh9hPhXM4pbBGkyAY4Bi3HQ==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.10.1", + "@docusaurus/logger": "3.10.1", + "@docusaurus/mdx-loader": "3.10.1", + "@docusaurus/module-type-aliases": "3.10.1", + "@docusaurus/theme-common": "3.10.1", + "@docusaurus/types": "3.10.1", + "@docusaurus/utils": "3.10.1", + "@docusaurus/utils-common": "3.10.1", + "@docusaurus/utils-validation": "3.10.1", + "@types/react-router-config": "^5.0.7", + "combine-promises": "^1.1.0", + "fs-extra": "^11.1.1", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "schema-dts": "^1.1.2", + "tslib": "^2.6.0", + "utility-types": "^3.10.0", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/plugin-content-pages": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.10.1.tgz", + "integrity": "sha512-huJpaRPMl42nsFwuCXvV8bVDj2MazuwRJIUylI/RSlmZeJssVoZXeCjVf1y+1Drtpa9SKcdGn8yoJ76IRJijtw==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.10.1", + "@docusaurus/mdx-loader": "3.10.1", + "@docusaurus/types": "3.10.1", + "@docusaurus/utils": "3.10.1", + "@docusaurus/utils-validation": "3.10.1", + "fs-extra": "^11.1.1", + "tslib": "^2.6.0", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/plugin-css-cascade-layers": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-css-cascade-layers/-/plugin-css-cascade-layers-3.10.1.tgz", + "integrity": "sha512-r//fn+MNHkE1wCof8T29VAQezt1enGCpsFxoziBbvLgBM4JfXN2P3rxrBaavHmvLvm7lYkpJeitcDthwnmWCTw==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.10.1", + "@docusaurus/types": "3.10.1", + "@docusaurus/utils": "3.10.1", + "@docusaurus/utils-validation": "3.10.1", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + } + }, + "node_modules/@docusaurus/plugin-debug": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-3.10.1.tgz", + "integrity": "sha512-9KqOpKNfAyqGZykRb9LhIT/vyRF6sm/ykhjj/39JvaJahDS+jZJE0Z1Wfz9q3DUNDTMNN0Q7u/kk4rKKU+IJuA==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.10.1", + "@docusaurus/types": "3.10.1", + "@docusaurus/utils": "3.10.1", + "fs-extra": "^11.1.1", + "react-json-view-lite": "^2.3.0", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/plugin-google-analytics": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.10.1.tgz", + "integrity": "sha512-8o0P1KtmgdYQHH+oInitPpRWI0Of5XednAX4+DMhQNSmGSRNrsEEHg1ebv35m9AgRClfAytCJ5jA9KvcASTyuA==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.10.1", + "@docusaurus/types": "3.10.1", + "@docusaurus/utils-validation": "3.10.1", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/plugin-google-gtag": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.10.1.tgz", + "integrity": "sha512-pu3xIUo5o/zCMLfUY9BO5KOwSH0zIsAGyFRPvXHayFSA5XIhCU/SFuB0g0ZNjFn9niZLCaNvoeAuOGFJZq0fdw==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.10.1", + "@docusaurus/types": "3.10.1", + "@docusaurus/utils-validation": "3.10.1", + "@types/gtag.js": "^0.0.20", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/plugin-google-tag-manager": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.10.1.tgz", + "integrity": "sha512-f6fyGHiCm7kJHBtAisGQS5oNBnpnMTYQZxDXeVrnw/3zWU+LMA22pr6UHGYkBKDbN+qPC5QHG3NuOfzQLq3+Lw==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.10.1", + "@docusaurus/types": "3.10.1", + "@docusaurus/utils-validation": "3.10.1", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/plugin-sitemap": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.10.1.tgz", + "integrity": "sha512-C26MbmmqgdjkDq1htaZ3aD7LzEDKFWXfpyQpt0EOUThuq5nV77zDaedV20yHcVo9p+3ey9aZ4pbHA0D3QcZTzg==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.10.1", + "@docusaurus/logger": "3.10.1", + "@docusaurus/types": "3.10.1", + "@docusaurus/utils": "3.10.1", + "@docusaurus/utils-common": "3.10.1", + "@docusaurus/utils-validation": "3.10.1", + "fs-extra": "^11.1.1", + "sitemap": "^7.1.1", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/plugin-svgr": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-svgr/-/plugin-svgr-3.10.1.tgz", + "integrity": "sha512-6SFxsmjWFkVLDmBUvFK6i72QjUwqyQFe4Ovz+SUJophJjOyVG3ZZG5IQpBC/kX/Gfv1yWeU9nWauH6F6Q7QX/Q==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.10.1", + "@docusaurus/types": "3.10.1", + "@docusaurus/utils": "3.10.1", + "@docusaurus/utils-validation": "3.10.1", + "@svgr/core": "8.1.0", + "@svgr/webpack": "^8.1.0", + "tslib": "^2.6.0", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/preset-classic": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-3.10.1.tgz", + "integrity": "sha512-YO/FL8v1zmbxoTso6mjMz/RDjhaTJxb1UpFFTDdY5847LLDCeyYiYlrhyTbgN1RIN3xnkLKZ9Lj1x8hUzI4JOg==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.10.1", + "@docusaurus/plugin-content-blog": "3.10.1", + "@docusaurus/plugin-content-docs": "3.10.1", + "@docusaurus/plugin-content-pages": "3.10.1", + "@docusaurus/plugin-css-cascade-layers": "3.10.1", + "@docusaurus/plugin-debug": "3.10.1", + "@docusaurus/plugin-google-analytics": "3.10.1", + "@docusaurus/plugin-google-gtag": "3.10.1", + "@docusaurus/plugin-google-tag-manager": "3.10.1", + "@docusaurus/plugin-sitemap": "3.10.1", + "@docusaurus/plugin-svgr": "3.10.1", + "@docusaurus/theme-classic": "3.10.1", + "@docusaurus/theme-common": "3.10.1", + "@docusaurus/theme-search-algolia": "3.10.1", + "@docusaurus/types": "3.10.1" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/theme-classic": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-3.10.1.tgz", + "integrity": "sha512-VU1RK0qb2pab0si4r7HFK37cYco8VzqLj3u1PspVipSr/z/GPVKHO4/HXbnePqHoWDk8urjyGSeatH0NIMBM1A==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.10.1", + "@docusaurus/logger": "3.10.1", + "@docusaurus/mdx-loader": "3.10.1", + "@docusaurus/module-type-aliases": "3.10.1", + "@docusaurus/plugin-content-blog": "3.10.1", + "@docusaurus/plugin-content-docs": "3.10.1", + "@docusaurus/plugin-content-pages": "3.10.1", + "@docusaurus/theme-common": "3.10.1", + "@docusaurus/theme-translations": "3.10.1", + "@docusaurus/types": "3.10.1", + "@docusaurus/utils": "3.10.1", + "@docusaurus/utils-common": "3.10.1", + "@docusaurus/utils-validation": "3.10.1", + "@mdx-js/react": "^3.0.0", + "clsx": "^2.0.0", + "copy-text-to-clipboard": "^3.2.0", + "infima": "0.2.0-alpha.45", + "lodash": "^4.17.21", + "nprogress": "^0.2.0", + "postcss": "^8.5.4", + "prism-react-renderer": "^2.3.0", + "prismjs": "^1.29.0", + "react-router-dom": "^5.3.4", + "rtlcss": "^4.1.0", + "tslib": "^2.6.0", + "utility-types": "^3.10.0" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/theme-common": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-3.10.1.tgz", + "integrity": "sha512-0YtmIeoNo1fIw65LO8+/1dPgmDV86UmhMkow37gzjytuiCSQm9xob6PJy0L4kuQEMTLfUOGvkXvZr7GPrHquMA==", + "license": "MIT", + "dependencies": { + "@docusaurus/mdx-loader": "3.10.1", + "@docusaurus/module-type-aliases": "3.10.1", + "@docusaurus/utils": "3.10.1", + "@docusaurus/utils-common": "3.10.1", + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router-config": "*", + "clsx": "^2.0.0", + "parse-numeric-range": "^1.3.0", + "prism-react-renderer": "^2.3.0", + "tslib": "^2.6.0", + "utility-types": "^3.10.0" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "@docusaurus/plugin-content-docs": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/theme-search-algolia": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.10.1.tgz", + "integrity": "sha512-OTaARARVZj2GvkJQjB+1jOIxntRaXea+G+fMsNqrZBAU1O1vJKDW22R7kECOHW27oJCLFN9HKaZeRrfAUyviug==", + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-core": "^1.19.2", + "@docsearch/react": "^3.9.0 || ^4.3.2", + "@docusaurus/core": "3.10.1", + "@docusaurus/logger": "3.10.1", + "@docusaurus/plugin-content-docs": "3.10.1", + "@docusaurus/theme-common": "3.10.1", + "@docusaurus/theme-translations": "3.10.1", + "@docusaurus/utils": "3.10.1", + "@docusaurus/utils-validation": "3.10.1", + "algoliasearch": "^5.37.0", + "algoliasearch-helper": "^3.26.0", + "clsx": "^2.0.0", + "eta": "^2.2.0", + "fs-extra": "^11.1.1", + "lodash": "^4.17.21", + "tslib": "^2.6.0", + "utility-types": "^3.10.0" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/theme-translations": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-3.10.1.tgz", + "integrity": "sha512-cLMyaKivjBVWKMJuWqyFVVgtqe8DPJNPkog0bn8W1MDVAKcPdxRFycBfC1We1RaNp7Rdk513bmtW78RR6OBxBw==", + "license": "MIT", + "dependencies": { + "fs-extra": "^11.1.1", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + } + }, + "node_modules/@docusaurus/tsconfig": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/tsconfig/-/tsconfig-3.10.1.tgz", + "integrity": "sha512-rYvB7yqkdqWIpAbDzQljGfM4cDBkLTbhmagZBEcsyj6oPUsz47lmW2pYdN1j+7sGFgltbAmQH62xfbrij4Eh6Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@docusaurus/types": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.10.1.tgz", + "integrity": "sha512-XYMK8k1szDCFMw2V+Xyen0g7Kee1sP3dtFnl7vkGkZOkeAJ/oPDQPL8iz4HBKOo/cwU8QeV6onVjMqtP+tFzsw==", + "license": "MIT", + "dependencies": { + "@mdx-js/mdx": "^3.0.0", + "@types/history": "^4.7.11", + "@types/mdast": "^4.0.2", + "@types/react": "*", + "commander": "^5.1.0", + "joi": "^17.9.2", + "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", + "utility-types": "^3.10.0", + "webpack": "^5.95.0", + "webpack-merge": "^5.9.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/types/node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@docusaurus/utils": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.10.1.tgz", + "integrity": "sha512-3ojeJry9xBYdJO6qoyyzqeJFSJBVx2mXhyDzSdjwL2+URFQMf+h25gG38iswGImicK0ELjTd1EL2xzk8hf3QPw==", + "license": "MIT", + "dependencies": { + "@docusaurus/logger": "3.10.1", + "@docusaurus/types": "3.10.1", + "@docusaurus/utils-common": "3.10.1", + "escape-string-regexp": "^4.0.0", + "execa": "^5.1.1", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "github-slugger": "^1.5.0", + "globby": "^11.1.0", + "gray-matter": "^4.0.3", + "jiti": "^1.20.0", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "micromatch": "^4.0.5", + "p-queue": "^6.6.2", + "prompts": "^2.4.2", + "resolve-pathname": "^3.0.0", + "tslib": "^2.6.0", + "url-loader": "^4.1.1", + "utility-types": "^3.10.0", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=20.0" + } + }, + "node_modules/@docusaurus/utils-common": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.10.1.tgz", + "integrity": "sha512-5mFSgEADtnFxFH7RLw02QA5MpU5JVUCj0MPeIvi/aF4Fi45tQRIuTwXoXDqJ+1VfQJuYJGz3SI63wmGz4HvXzA==", + "license": "MIT", + "dependencies": { + "@docusaurus/types": "3.10.1", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + } + }, + "node_modules/@docusaurus/utils-validation": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-3.10.1.tgz", + "integrity": "sha512-cRv1X69jwaWv47waglllgZVWzeBFLhl53XT/XED/83BerVBTC5FTP8WTcVl8Z6sZOegDSwitu/wpCSPCDOT6lg==", + "license": "MIT", + "dependencies": { + "@docusaurus/logger": "3.10.1", + "@docusaurus/utils": "3.10.1", + "@docusaurus/utils-common": "3.10.1", + "fs-extra": "^11.2.0", + "joi": "^17.9.2", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + } + }, + "node_modules/@easyops-cn/autocomplete.js": { + "version": "0.38.1", + "resolved": "https://registry.npmjs.org/@easyops-cn/autocomplete.js/-/autocomplete.js-0.38.1.tgz", + "integrity": "sha512-drg76jS6syilOUmVNkyo1c7ZEBPcPuK+aJA7AksM5ZIIbV57DMHCywiCr+uHyv8BE5jUTU98j/H7gVrkHrWW3Q==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "immediate": "^3.2.3" + } + }, + "node_modules/@easyops-cn/docusaurus-search-local": { + "version": "0.55.1", + "resolved": "https://registry.npmjs.org/@easyops-cn/docusaurus-search-local/-/docusaurus-search-local-0.55.1.tgz", + "integrity": "sha512-jmBKj1J+tajqNrCvECwKCQYTWwHVZDGApy8lLOYEPe+Dm0/f3Ccdw8BP5/OHNpltr7WDNY2roQXn+TWn2f1kig==", + "license": "MIT", + "dependencies": { + "@docusaurus/plugin-content-docs": "^2 || ^3", + "@docusaurus/theme-translations": "^2 || ^3", + "@docusaurus/utils": "^2 || ^3", + "@docusaurus/utils-common": "^2 || ^3", + "@docusaurus/utils-validation": "^2 || ^3", + "@easyops-cn/autocomplete.js": "^0.38.1", + "@node-rs/jieba": "^1.6.0", + "cheerio": "^1.0.0", + "clsx": "^2.1.1", + "comlink": "^4.4.2", + "debug": "^4.2.0", + "fs-extra": "^10.0.0", + "klaw-sync": "^6.0.0", + "lunr": "^2.3.9", + "lunr-languages": "^1.4.0", + "mark.js": "^8.11.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "@docusaurus/theme-common": "^2 || ^3", + "open-ask-ai": "^0.7.3", + "react": "^16.14.0 || ^17 || ^18 || ^19", + "react-dom": "^16.14.0 || 17 || ^18 || ^19" + }, + "peerDependenciesMeta": { + "open-ask-ai": { + "optional": true + } + } + }, + "node_modules/@easyops-cn/docusaurus-search-local/node_modules/cheerio": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.2.0.tgz", + "integrity": "sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg==", + "license": "MIT", + "dependencies": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.2", + "encoding-sniffer": "^0.2.1", + "htmlparser2": "^10.1.0", + "parse5": "^7.3.0", + "parse5-htmlparser2-tree-adapter": "^7.1.0", + "parse5-parser-stream": "^7.1.2", + "undici": "^7.19.0", + "whatwg-mimetype": "^4.0.0" + }, + "engines": { + "node": ">=20.18.1" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/@easyops-cn/docusaurus-search-local/node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/@easyops-cn/docusaurus-search-local/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@easyops-cn/docusaurus-search-local/node_modules/htmlparser2": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.1.0.tgz", + "integrity": "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.2", + "entities": "^7.0.1" + } + }, + "node_modules/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@jsonjoy.com/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/buffers": { + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/buffers/-/buffers-17.67.0.tgz", + "integrity": "sha512-tfExRpYxBvi32vPs9ZHaTjSP4fHAfzSmcahOfNxtvGHcyJel+aibkPlGeBB+7AoC6hL7lXIE++8okecBxx7lcw==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/codegen": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/codegen/-/codegen-1.0.0.tgz", + "integrity": "sha512-E8Oy+08cmCf0EK/NMxpaJZmOxPqM+6iSe2S4nlSBrPZOORoDJILxtbSUEDKQyTamm/BVAhIGllOBNU79/dwf0g==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-core": { + "version": "4.57.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-core/-/fs-core-4.57.2.tgz", + "integrity": "sha512-SVjwklkpIV5wrynpYtuYnfYH1QF4/nDuLBX7VXdb+3miglcAgBVZb/5y0cOsehRV/9Vb+3UqhkMq3/NR3ztdkQ==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/fs-node-builtins": "4.57.2", + "@jsonjoy.com/fs-node-utils": "4.57.2", + "thingies": "^2.5.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-fsa": { + "version": "4.57.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-fsa/-/fs-fsa-4.57.2.tgz", + "integrity": "sha512-fhO8+iR2I+OCw668ISDJdn1aArc9zx033sWejIyzQ8RBeXa9bDSaUeA3ix0poYOfrj1KdOzytmYNv2/uLDfV6g==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/fs-core": "4.57.2", + "@jsonjoy.com/fs-node-builtins": "4.57.2", + "@jsonjoy.com/fs-node-utils": "4.57.2", + "thingies": "^2.5.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-node": { + "version": "4.57.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node/-/fs-node-4.57.2.tgz", + "integrity": "sha512-nX2AdL6cOFwLdju9G4/nbRnYevmCJbh7N7hvR3gGm97Cs60uEjyd0rpR+YBS7cTg175zzl22pGKXR5USaQMvKg==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/fs-core": "4.57.2", + "@jsonjoy.com/fs-node-builtins": "4.57.2", + "@jsonjoy.com/fs-node-utils": "4.57.2", + "@jsonjoy.com/fs-print": "4.57.2", + "@jsonjoy.com/fs-snapshot": "4.57.2", + "glob-to-regex.js": "^1.0.0", + "thingies": "^2.5.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-node-builtins": { + "version": "4.57.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node-builtins/-/fs-node-builtins-4.57.2.tgz", + "integrity": "sha512-xhiegylRmhw43Ki2HO1ZBL7DQ5ja/qpRsL29VtQ2xuUHiuDGbgf2uD4p9Qd8hJI5P6RCtGYD50IXHXVq/Ocjcg==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-node-to-fsa": { + "version": "4.57.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node-to-fsa/-/fs-node-to-fsa-4.57.2.tgz", + "integrity": "sha512-18LmWTSONhoAPW+IWRuf8w/+zRolPFGPeGwMxlAhhfY11EKzX+5XHDBPAw67dBF5dxDErHJbl40U+3IXSDRXSQ==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/fs-fsa": "4.57.2", + "@jsonjoy.com/fs-node-builtins": "4.57.2", + "@jsonjoy.com/fs-node-utils": "4.57.2" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-node-utils": { + "version": "4.57.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node-utils/-/fs-node-utils-4.57.2.tgz", + "integrity": "sha512-rsPSJgekz43IlNbLyAM/Ab+ouYLWGp5DDBfYBNNEqDaSpsbXfthBn29Q4muFA9L0F+Z3mKo+CWlgSCXrf+mOyQ==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/fs-node-builtins": "4.57.2" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-print": { + "version": "4.57.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-print/-/fs-print-4.57.2.tgz", + "integrity": "sha512-wK9NSow48i4DbDl9F1CQE5TqnyZOJ04elU3WFG5aJ76p+YxO/ulyBBQvKsessPxdo381Bc2pcEoyPujMOhcRqQ==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/fs-node-utils": "4.57.2", + "tree-dump": "^1.1.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-snapshot": { + "version": "4.57.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-snapshot/-/fs-snapshot-4.57.2.tgz", + "integrity": "sha512-GdduDZuoP5V/QCgJkx9+BZ6SC0EZ/smXAdTS7PfMqgMTGXLlt/bH/FqMYaqB9JmLf05sJPtO0XRbAwwkEEPbVw==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/buffers": "^17.65.0", + "@jsonjoy.com/fs-node-utils": "4.57.2", + "@jsonjoy.com/json-pack": "^17.65.0", + "@jsonjoy.com/util": "^17.65.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/base64": { + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-17.67.0.tgz", + "integrity": "sha512-5SEsJGsm15aP8TQGkDfJvz9axgPwAEm98S5DxOuYe8e1EbfajcDmgeXXzccEjh+mLnjqEKrkBdjHWS5vFNwDdw==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/codegen": { + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/codegen/-/codegen-17.67.0.tgz", + "integrity": "sha512-idnkUplROpdBOV0HMcwhsCUS5TRUi9poagdGs70A6S4ux9+/aPuKbh8+UYRTLYQHtXvAdNfQWXDqZEx5k4Dj2Q==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/json-pack": { + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-17.67.0.tgz", + "integrity": "sha512-t0ejURcGaZsn1ClbJ/3kFqSOjlryd92eQY465IYrezsXmPcfHPE/av4twRSxf6WE+TkZgLY+71vCZbiIiFKA/w==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/base64": "17.67.0", + "@jsonjoy.com/buffers": "17.67.0", + "@jsonjoy.com/codegen": "17.67.0", + "@jsonjoy.com/json-pointer": "17.67.0", + "@jsonjoy.com/util": "17.67.0", + "hyperdyperid": "^1.2.0", + "thingies": "^2.5.0", + "tree-dump": "^1.1.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/json-pointer": { + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pointer/-/json-pointer-17.67.0.tgz", + "integrity": "sha512-+iqOFInH+QZGmSuaybBUNdh7yvNrXvqR+h3wjXm0N/3JK1EyyFAeGJvqnmQL61d1ARLlk/wJdFKSL+LHJ1eaUA==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/util": "17.67.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/util": { + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-17.67.0.tgz", + "integrity": "sha512-6+8xBaz1rLSohlGh68D1pdw3AwDi9xydm8QNlAFkvnavCJYSze+pxoW2VKP8p308jtlMRLs5NTHfPlZLd4w7ew==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/buffers": "17.67.0", + "@jsonjoy.com/codegen": "17.67.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/json-pack": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.21.0.tgz", + "integrity": "sha512-+AKG+R2cfZMShzrF2uQw34v3zbeDYUqnQ+jg7ORic3BGtfw9p/+N6RJbq/kkV8JmYZaINknaEQ2m0/f693ZPpg==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/base64": "^1.1.2", + "@jsonjoy.com/buffers": "^1.2.0", + "@jsonjoy.com/codegen": "^1.0.0", + "@jsonjoy.com/json-pointer": "^1.0.2", + "@jsonjoy.com/util": "^1.9.0", + "hyperdyperid": "^1.2.0", + "thingies": "^2.5.0", + "tree-dump": "^1.1.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/json-pack/node_modules/@jsonjoy.com/buffers": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/buffers/-/buffers-1.2.1.tgz", + "integrity": "sha512-12cdlDwX4RUM3QxmUbVJWqZ/mrK6dFQH4Zxq6+r1YXKXYBNgZXndx2qbCJwh3+WWkCSn67IjnlG3XYTvmvYtgA==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/json-pointer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pointer/-/json-pointer-1.0.2.tgz", + "integrity": "sha512-Fsn6wM2zlDzY1U+v4Nc8bo3bVqgfNTGcn6dMgs6FjrEnt4ZCe60o6ByKRjOGlI2gow0aE/Q41QOigdTqkyK5fg==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/codegen": "^1.0.0", + "@jsonjoy.com/util": "^1.9.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/util": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.9.0.tgz", + "integrity": "sha512-pLuQo+VPRnN8hfPqUTLTHk126wuYdXVxE6aDmjSeV4NCAgyxWbiOIeNJVtID3h1Vzpoi9m4jXezf73I6LgabgQ==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/buffers": "^1.0.0", + "@jsonjoy.com/codegen": "^1.0.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/util/node_modules/@jsonjoy.com/buffers": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/buffers/-/buffers-1.2.1.tgz", + "integrity": "sha512-12cdlDwX4RUM3QxmUbVJWqZ/mrK6dFQH4Zxq6+r1YXKXYBNgZXndx2qbCJwh3+WWkCSn67IjnlG3XYTvmvYtgA==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "license": "MIT" + }, + "node_modules/@mdx-js/mdx": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.1.1.tgz", + "integrity": "sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdx": "^2.0.0", + "acorn": "^8.0.0", + "collapse-white-space": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-util-scope": "^1.0.0", + "estree-walker": "^3.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "markdown-extensions": "^2.0.0", + "recma-build-jsx": "^1.0.0", + "recma-jsx": "^1.0.0", + "recma-stringify": "^1.0.0", + "rehype-recma": "^1.0.0", + "remark-mdx": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "source-map": "^0.7.0", + "unified": "^11.0.0", + "unist-util-position-from-estree": "^2.0.0", + "unist-util-stringify-position": "^4.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/react": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.1.1.tgz", + "integrity": "sha512-f++rKLQgUVYDAtECQ6fn/is15GkEH9+nZPM3MS0RcxVqoTfawHvDlSCH7JbMhAM6uJ32v3eXLvLmLvjGu7PTQw==", + "license": "MIT", + "dependencies": { + "@types/mdx": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=16", + "react": ">=16" + } + }, + "node_modules/@module-federation/error-codes": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@module-federation/error-codes/-/error-codes-0.22.0.tgz", + "integrity": "sha512-xF9SjnEy7vTdx+xekjPCV5cIHOGCkdn3pIxo9vU7gEZMIw0SvAEdsy6Uh17xaCpm8V0FWvR0SZoK9Ik6jGOaug==", + "license": "MIT" + }, + "node_modules/@module-federation/runtime": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@module-federation/runtime/-/runtime-0.22.0.tgz", + "integrity": "sha512-38g5iPju2tPC3KHMPxRKmy4k4onNp6ypFPS1eKGsNLUkXgHsPMBFqAjDw96iEcjri91BrahG4XcdyKi97xZzlA==", + "license": "MIT", + "dependencies": { + "@module-federation/error-codes": "0.22.0", + "@module-federation/runtime-core": "0.22.0", + "@module-federation/sdk": "0.22.0" + } + }, + "node_modules/@module-federation/runtime-core": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@module-federation/runtime-core/-/runtime-core-0.22.0.tgz", + "integrity": "sha512-GR1TcD6/s7zqItfhC87zAp30PqzvceoeDGYTgF3Vx2TXvsfDrhP6Qw9T4vudDQL3uJRne6t7CzdT29YyVxlgIA==", + "license": "MIT", + "dependencies": { + "@module-federation/error-codes": "0.22.0", + "@module-federation/sdk": "0.22.0" + } + }, + "node_modules/@module-federation/runtime-tools": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@module-federation/runtime-tools/-/runtime-tools-0.22.0.tgz", + "integrity": "sha512-4ScUJ/aUfEernb+4PbLdhM/c60VHl698Gn1gY21m9vyC1Ucn69fPCA1y2EwcCB7IItseRMoNhdcWQnzt/OPCNA==", + "license": "MIT", + "dependencies": { + "@module-federation/runtime": "0.22.0", + "@module-federation/webpack-bundler-runtime": "0.22.0" + } + }, + "node_modules/@module-federation/sdk": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@module-federation/sdk/-/sdk-0.22.0.tgz", + "integrity": "sha512-x4aFNBKn2KVQRuNVC5A7SnrSCSqyfIWmm1DvubjbO9iKFe7ith5niw8dqSFBekYBg2Fwy+eMg4sEFNVvCAdo6g==", + "license": "MIT" + }, + "node_modules/@module-federation/webpack-bundler-runtime": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@module-federation/webpack-bundler-runtime/-/webpack-bundler-runtime-0.22.0.tgz", + "integrity": "sha512-aM8gCqXu+/4wBmJtVeMeeMN5guw3chf+2i6HajKtQv7SJfxV/f4IyNQJUeUQu9HfiAZHjqtMV5Lvq/Lvh8LdyA==", + "license": "MIT", + "dependencies": { + "@module-federation/runtime": "0.22.0", + "@module-federation/sdk": "0.22.0" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.0.7.tgz", + "integrity": "sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw==", + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.5.0", + "@emnapi/runtime": "^1.5.0", + "@tybys/wasm-util": "^0.10.1" + } + }, + "node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@node-rs/jieba": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@node-rs/jieba/-/jieba-1.10.4.tgz", + "integrity": "sha512-GvDgi8MnBiyWd6tksojej8anIx18244NmIOc1ovEw8WKNUejcccLfyu8vj66LWSuoZuKILVtNsOy4jvg3aoxIw==", + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "optionalDependencies": { + "@node-rs/jieba-android-arm-eabi": "1.10.4", + "@node-rs/jieba-android-arm64": "1.10.4", + "@node-rs/jieba-darwin-arm64": "1.10.4", + "@node-rs/jieba-darwin-x64": "1.10.4", + "@node-rs/jieba-freebsd-x64": "1.10.4", + "@node-rs/jieba-linux-arm-gnueabihf": "1.10.4", + "@node-rs/jieba-linux-arm64-gnu": "1.10.4", + "@node-rs/jieba-linux-arm64-musl": "1.10.4", + "@node-rs/jieba-linux-x64-gnu": "1.10.4", + "@node-rs/jieba-linux-x64-musl": "1.10.4", + "@node-rs/jieba-wasm32-wasi": "1.10.4", + "@node-rs/jieba-win32-arm64-msvc": "1.10.4", + "@node-rs/jieba-win32-ia32-msvc": "1.10.4", + "@node-rs/jieba-win32-x64-msvc": "1.10.4" + } + }, + "node_modules/@node-rs/jieba-android-arm-eabi": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-android-arm-eabi/-/jieba-android-arm-eabi-1.10.4.tgz", + "integrity": "sha512-MhyvW5N3Fwcp385d0rxbCWH42kqDBatQTyP8XbnYbju2+0BO/eTeCCLYj7Agws4pwxn2LtdldXRSKavT7WdzNA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/jieba-android-arm64": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-android-arm64/-/jieba-android-arm64-1.10.4.tgz", + "integrity": "sha512-XyDwq5+rQ+Tk55A+FGi6PtJbzf974oqnpyCcCPzwU3QVXJCa2Rr4Lci+fx8oOpU4plT3GuD+chXMYLsXipMgJA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/jieba-darwin-arm64": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-darwin-arm64/-/jieba-darwin-arm64-1.10.4.tgz", + "integrity": "sha512-G++RYEJ2jo0rxF9626KUy90wp06TRUjAsvY/BrIzEOX/ingQYV/HjwQzNPRR1P1o32a6/U8RGo7zEBhfdybL6w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/jieba-darwin-x64": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-darwin-x64/-/jieba-darwin-x64-1.10.4.tgz", + "integrity": "sha512-MmDNeOb2TXIZCPyWCi2upQnZpPjAxw5ZGEj6R8kNsPXVFALHIKMa6ZZ15LCOkSTsKXVC17j2t4h+hSuyYb6qfQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/jieba-freebsd-x64": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-freebsd-x64/-/jieba-freebsd-x64-1.10.4.tgz", + "integrity": "sha512-/x7aVQ8nqUWhpXU92RZqd333cq639i/olNpd9Z5hdlyyV5/B65LLy+Je2B2bfs62PVVm5QXRpeBcZqaHelp/bg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/jieba-linux-arm-gnueabihf": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-linux-arm-gnueabihf/-/jieba-linux-arm-gnueabihf-1.10.4.tgz", + "integrity": "sha512-crd2M35oJBRLkoESs0O6QO3BBbhpv+tqXuKsqhIG94B1d02RVxtRIvSDwO33QurxqSdvN9IeSnVpHbDGkuXm3g==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/jieba-linux-arm64-gnu": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-linux-arm64-gnu/-/jieba-linux-arm64-gnu-1.10.4.tgz", + "integrity": "sha512-omIzNX1psUzPcsdnUhGU6oHeOaTCuCjUgOA/v/DGkvWC1jLcnfXe4vdYbtXMh4XOCuIgS1UCcvZEc8vQLXFbXQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/jieba-linux-arm64-musl": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-linux-arm64-musl/-/jieba-linux-arm64-musl-1.10.4.tgz", + "integrity": "sha512-Y/tiJ1+HeS5nnmLbZOE+66LbsPOHZ/PUckAYVeLlQfpygLEpLYdlh0aPpS5uiaWMjAXYZYdFkpZHhxDmSLpwpw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/jieba-linux-x64-gnu": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-linux-x64-gnu/-/jieba-linux-x64-gnu-1.10.4.tgz", + "integrity": "sha512-WZO8ykRJpWGE9MHuZpy1lu3nJluPoeB+fIJJn5CWZ9YTVhNDWoCF4i/7nxz1ntulINYGQ8VVuCU9LD86Mek97g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/jieba-linux-x64-musl": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-linux-x64-musl/-/jieba-linux-x64-musl-1.10.4.tgz", + "integrity": "sha512-uBBD4S1rGKcgCyAk6VCKatEVQb6EDD5I40v/DxODi5CuZVCANi9m5oee/MQbAoaX7RydA2f0OSCE9/tcwXEwUg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/jieba-wasm32-wasi": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-wasm32-wasi/-/jieba-wasm32-wasi-1.10.4.tgz", + "integrity": "sha512-Y2umiKHjuIJy0uulNDz9SDYHdfq5Hmy7jY5nORO99B4pySKkcrMjpeVrmWXJLIsEKLJwcCXHxz8tjwU5/uhz0A==", + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^0.2.3" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@node-rs/jieba-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", + "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@tybys/wasm-util": "^0.10.0" + } + }, + "node_modules/@node-rs/jieba-win32-arm64-msvc": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-win32-arm64-msvc/-/jieba-win32-arm64-msvc-1.10.4.tgz", + "integrity": "sha512-nwMtViFm4hjqhz1it/juQnxpXgqlGltCuWJ02bw70YUDMDlbyTy3grCJPpQQpueeETcALUnTxda8pZuVrLRcBA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/jieba-win32-ia32-msvc": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-win32-ia32-msvc/-/jieba-win32-ia32-msvc-1.10.4.tgz", + "integrity": "sha512-DCAvLx7Z+W4z5oKS+7vUowAJr0uw9JBw8x1Y23Xs/xMA4Em+OOSiaF5/tCJqZUCJ8uC4QeImmgDFiBqGNwxlyA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/jieba-win32-x64-msvc": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-win32-x64-msvc/-/jieba-win32-x64-msvc-1.10.4.tgz", + "integrity": "sha512-+sqemSfS1jjb+Tt7InNbNzrRh1Ua3vProVvC4BZRPg010/leCbGFFiQHpzcPRfpxAXZrzG5Y0YBTsPzN/I4yHQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@peculiar/asn1-cms": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-cms/-/asn1-cms-2.7.0.tgz", + "integrity": "sha512-hew63shtzzvBcSHbhm+cyAmKe6AIfinT9hzEqSPjDC6opTTMKmTkQ0gHuN2KsWlvqiKw1S/fS94fhag/FJkioQ==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.7.0", + "@peculiar/asn1-x509": "^2.7.0", + "@peculiar/asn1-x509-attr": "^2.7.0", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-csr": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-csr/-/asn1-csr-2.7.0.tgz", + "integrity": "sha512-VVsAyGqErT9D1SY4aEqozThXMVI+ssVRiv2DDeYuvpBKLIgZ3hYs3Ay3u/VSoKq6ESFi9cf6rf3IOOzfwh7oMA==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.7.0", + "@peculiar/asn1-x509": "^2.7.0", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-ecc": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-ecc/-/asn1-ecc-2.7.0.tgz", + "integrity": "sha512-n7KEs/Q/wrB415cxy4fHOBhegp4NdJ15fkJPwcB/3/8iNBQC2L/N7SChJPKDJPZGYH0jD4Tg4/0vnHmwghnbKw==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.7.0", + "@peculiar/asn1-x509": "^2.7.0", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-pfx": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pfx/-/asn1-pfx-2.7.0.tgz", + "integrity": "sha512-V/nrlQVmhg7lYAsM7E13UDL5erAwFv6kCIVFqNaMIHSVi7dngcT839JkRTkQBqznMG98l2XjxYk74ZztAohZzA==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-cms": "^2.7.0", + "@peculiar/asn1-pkcs8": "^2.7.0", + "@peculiar/asn1-rsa": "^2.7.0", + "@peculiar/asn1-schema": "^2.7.0", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-pkcs8": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs8/-/asn1-pkcs8-2.7.0.tgz", + "integrity": "sha512-9GTl1nE8Mx1kTZ+7QyYatDyKsm34QcWRBFkY1iPvWC3X4Dona5s/tlLiQsx5WzVdZqiMBZNYT0buyw4/vbhnjw==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.7.0", + "@peculiar/asn1-x509": "^2.7.0", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-pkcs9": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs9/-/asn1-pkcs9-2.7.0.tgz", + "integrity": "sha512-Bh7m+OuIaSEllPQcSd9OSp93F4ROWH7sbITWV8MI+8dwsjE5111/87VxiWVvYFKyww3vp39geLv9ENqhwWHcew==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-cms": "^2.7.0", + "@peculiar/asn1-pfx": "^2.7.0", + "@peculiar/asn1-pkcs8": "^2.7.0", + "@peculiar/asn1-schema": "^2.7.0", + "@peculiar/asn1-x509": "^2.7.0", + "@peculiar/asn1-x509-attr": "^2.7.0", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-rsa": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-rsa/-/asn1-rsa-2.7.0.tgz", + "integrity": "sha512-/qvENQrXyTZURjMqSeofHul0JJt2sNSzSwk36pl2olkHbaioMQgrASDZAlHXl0xUlnVbHj0uGgOrBMTb5x2aJQ==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.7.0", + "@peculiar/asn1-x509": "^2.7.0", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-schema": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.7.0.tgz", + "integrity": "sha512-W8ZfWzLmQnrcky+eh3tni4IozMdqBDiHWU0N+vve/UGjMaUs8c0L7A2oEdkBXS8rTpWDpK/aoI3DG/L/hxmxPg==", + "license": "MIT", + "dependencies": { + "@peculiar/utils": "^2.0.2", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-x509": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.7.0.tgz", + "integrity": "sha512-mUn9RRrkGDnG4ALfunDmzyRW5dg+sWCj/pfnCCqEHYbkGxEpvUt6iVJv8Yw1cyp6SWZ26ZE5oSmI5SqEaen15g==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.7.0", + "@peculiar/utils": "^2.0.2", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-x509-attr": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509-attr/-/asn1-x509-attr-2.7.0.tgz", + "integrity": "sha512-NS8e7SOgXipkzUPLF/sce7ukpMpWjhxYsH0n6Y+bHYo4TTxOb95Zv7hqwSuL212mj5YxovjdOKQOgH1As3E94w==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.7.0", + "@peculiar/asn1-x509": "^2.7.0", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@peculiar/utils/-/utils-2.0.3.tgz", + "integrity": "sha512-+oL3HPFRIZ1St2K50lWCXiioIgSoxzz7R1J3uF6neO2yl1sgmpgY6XXJH4BdpoDkMWznQTeYF6oWNDZLCdQ4eQ==", + "license": "MIT", + "dependencies": { + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/x509": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/@peculiar/x509/-/x509-1.14.3.tgz", + "integrity": "sha512-C2Xj8FZ0uHWeCXXqX5B4/gVFQmtSkiuOolzAgutjTfseNOHT3pUjljDZsTSxXFGgio54bCzVFqmEOUrIVk8RDA==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-cms": "^2.6.0", + "@peculiar/asn1-csr": "^2.6.0", + "@peculiar/asn1-ecc": "^2.6.0", + "@peculiar/asn1-pkcs9": "^2.6.0", + "@peculiar/asn1-rsa": "^2.6.0", + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.0", + "pvtsutils": "^1.3.6", + "reflect-metadata": "^0.2.2", + "tslib": "^2.8.1", + "tsyringe": "^4.10.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@pnpm/config.env-replace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", + "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", + "license": "MIT", + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", + "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", + "license": "MIT", + "dependencies": { + "graceful-fs": "4.2.10" + }, + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file/node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "license": "ISC" + }, + "node_modules/@pnpm/npm-conf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-3.0.2.tgz", + "integrity": "sha512-h104Kh26rR8tm+a3Qkc5S4VLYint3FE48as7+/5oCEcKR2idC/pF1G6AhIXKI+eHPJa/3J9i5z0Al47IeGHPkA==", + "license": "MIT", + "dependencies": { + "@pnpm/config.env-replace": "^1.1.0", + "@pnpm/network.ca-file": "^1.0.1", + "config-chain": "^1.1.11" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "license": "MIT" + }, + "node_modules/@rspack/binding": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@rspack/binding/-/binding-1.7.11.tgz", + "integrity": "sha512-2MGdy2s2HimsDT444Bp5XnALzNRxuBNc7y0JzyuqKbHBywd4x2NeXyhWXXoxufaCFu5PBc9Qq9jyfjW2Aeh06Q==", + "license": "MIT", + "optionalDependencies": { + "@rspack/binding-darwin-arm64": "1.7.11", + "@rspack/binding-darwin-x64": "1.7.11", + "@rspack/binding-linux-arm64-gnu": "1.7.11", + "@rspack/binding-linux-arm64-musl": "1.7.11", + "@rspack/binding-linux-x64-gnu": "1.7.11", + "@rspack/binding-linux-x64-musl": "1.7.11", + "@rspack/binding-wasm32-wasi": "1.7.11", + "@rspack/binding-win32-arm64-msvc": "1.7.11", + "@rspack/binding-win32-ia32-msvc": "1.7.11", + "@rspack/binding-win32-x64-msvc": "1.7.11" + } + }, + "node_modules/@rspack/binding-darwin-arm64": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-arm64/-/binding-darwin-arm64-1.7.11.tgz", + "integrity": "sha512-oduECiZVqbO5zlVw+q7Vy65sJFth99fWPTyucwvLJJtJkPL5n17Uiql2cYP6Ijn0pkqtf1SXgK8WjiKLG5bIig==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rspack/binding-darwin-x64": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-x64/-/binding-darwin-x64-1.7.11.tgz", + "integrity": "sha512-a1+TtTE9ap6RalgFi7FGIgkJP6O4Vy6ctv+9WGJy53E4kuqHR0RygzaiVxCI/GMc/vBT9vY23hyrpWb3d1vtXA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rspack/binding-linux-arm64-gnu": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.7.11.tgz", + "integrity": "sha512-P0QrGRPbTWu6RKWfN0bDtbnEps3rXH0MWIMreZABoUrVmNQKtXR6e73J3ub6a+di5s2+K0M2LJ9Bh2/H4UsDUA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rspack/binding-linux-arm64-musl": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.7.11.tgz", + "integrity": "sha512-6ky7R43VMjWwmx3Yx7Jl7faLBBMAgMDt+/bN35RgwjiPgsIByz65EwytUVuW9rikB43BGHvA/eqlnjLrUzNBqw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rspack/binding-linux-x64-gnu": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.7.11.tgz", + "integrity": "sha512-cuOJMfCOvb2Wgsry5enXJ3iT1FGUjdPqtGUBVupQlEG4ntSYsQ2PtF4wIDVasR3wdxC5nQbipOrDiN/u6fYsdQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rspack/binding-linux-x64-musl": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-musl/-/binding-linux-x64-musl-1.7.11.tgz", + "integrity": "sha512-CoK37hva4AmHGh3VCsQXmGr40L36m1/AdnN5LEjUX6kx5rEH7/1nEBN6Ii72pejqDVvk9anEROmPDiPw10tpFg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rspack/binding-wasm32-wasi": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@rspack/binding-wasm32-wasi/-/binding-wasm32-wasi-1.7.11.tgz", + "integrity": "sha512-OtrmnPUVJMxjNa3eDMfHyPdtlLRmmp/aIm0fQHlAOATbZvlGm12q7rhPW5BXTu1yh+1rQ1/uqvz+SzKEZXuJaQ==", + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "1.0.7" + } + }, + "node_modules/@rspack/binding-win32-arm64-msvc": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@rspack/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.7.11.tgz", + "integrity": "sha512-lObFW6e5lCWNgTBNwT//yiEDbsxm9QG4BYUojqeXxothuzJ/L6ibXz6+gLMvbOvLGV3nKgkXmx8GvT9WDKR0mA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rspack/binding-win32-ia32-msvc": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@rspack/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.7.11.tgz", + "integrity": "sha512-0pYGnZd8PPqNR68zQ8skamqNAXEA1sUfXuAdYcknIIRq2wsbiwFzIc0Pov1cIfHYab37G7sSIPBiOUdOWF5Ivw==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rspack/binding-win32-x64-msvc": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@rspack/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.7.11.tgz", + "integrity": "sha512-EeQXayoQk/uBkI3pdoXfQBXNIUrADq56L3s/DFyM2pJeUDrWmhfIw2UFIGkYPTMSCo8F2JcdcGM32FGJrSnU0Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rspack/core": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@rspack/core/-/core-1.7.11.tgz", + "integrity": "sha512-rsD9b+Khmot5DwCMiB3cqTQo53ioPG3M/A7BySu8+0+RS7GCxKm+Z+mtsjtG/vsu4Tn2tcqCdZtA3pgLoJB+ew==", + "license": "MIT", + "dependencies": { + "@module-federation/runtime-tools": "0.22.0", + "@rspack/binding": "1.7.11", + "@rspack/lite-tapable": "1.1.0" + }, + "engines": { + "node": ">=18.12.0" + }, + "peerDependencies": { + "@swc/helpers": ">=0.5.1" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@rspack/lite-tapable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rspack/lite-tapable/-/lite-tapable-1.1.0.tgz", + "integrity": "sha512-E2B0JhYFmVAwdDiG14+DW0Di4Ze4Jg10Pc4/lILUrd5DRCaklduz2OvJ5HYQ6G+hd+WTzqQb3QnDNfK4yvAFYw==", + "license": "MIT" + }, + "node_modules/@sideway/address": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", + "integrity": "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==", + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@sideway/formula": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", + "license": "BSD-3-Clause" + }, + "node_modules/@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.10", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.10.tgz", + "integrity": "sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==", + "license": "MIT" + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@slorber/remark-comment": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@slorber/remark-comment/-/remark-comment-1.0.0.tgz", + "integrity": "sha512-RCE24n7jsOj1M0UPvIQCHTe7fI0sFL4S2nwKVWwHyVr/wI/H8GosgsJGyhnsZoGFnD/P2hLf1mSbrrgSLN93NA==", + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.1.0", + "micromark-util-symbol": "^1.0.1" + } + }, + "node_modules/@svgr/babel-plugin-add-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz", + "integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz", + "integrity": "sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-dynamic-title": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz", + "integrity": "sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-em-dimensions": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz", + "integrity": "sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-react-native-svg": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.1.0.tgz", + "integrity": "sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-svg-component": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz", + "integrity": "sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-preset": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-8.1.0.tgz", + "integrity": "sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==", + "license": "MIT", + "dependencies": { + "@svgr/babel-plugin-add-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "8.0.0", + "@svgr/babel-plugin-replace-jsx-attribute-value": "8.0.0", + "@svgr/babel-plugin-svg-dynamic-title": "8.0.0", + "@svgr/babel-plugin-svg-em-dimensions": "8.0.0", + "@svgr/babel-plugin-transform-react-native-svg": "8.1.0", + "@svgr/babel-plugin-transform-svg-component": "8.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/core": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", + "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "camelcase": "^6.2.0", + "cosmiconfig": "^8.1.3", + "snake-case": "^3.0.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/hast-util-to-babel-ast": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz", + "integrity": "sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.21.3", + "entities": "^4.4.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/plugin-jsx": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz", + "integrity": "sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "@svgr/hast-util-to-babel-ast": "8.0.0", + "svg-parser": "^2.0.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "*" + } + }, + "node_modules/@svgr/plugin-svgo": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-8.1.0.tgz", + "integrity": "sha512-Ywtl837OGO9pTLIN/onoWLmDQ4zFUycI1g76vuKGEz6evR/ZTJlJuz3G/fIkb6OVBJ2g0o6CGJzaEjfmEo3AHA==", + "license": "MIT", + "dependencies": { + "cosmiconfig": "^8.1.3", + "deepmerge": "^4.3.1", + "svgo": "^3.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "*" + } + }, + "node_modules/@svgr/webpack": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-8.1.0.tgz", + "integrity": "sha512-LnhVjMWyMQV9ZmeEy26maJk+8HTIbd59cH4F2MJ439k9DqejRisfFNGAPvRYlKETuh9LrImlS8aKsBgKjMA8WA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.21.3", + "@babel/plugin-transform-react-constant-elements": "^7.21.3", + "@babel/preset-env": "^7.20.2", + "@babel/preset-react": "^7.18.6", + "@babel/preset-typescript": "^7.21.0", + "@svgr/core": "8.1.0", + "@svgr/plugin-jsx": "8.1.0", + "@svgr/plugin-svgo": "8.1.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@swc/core": { + "version": "1.15.33", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.33.tgz", + "integrity": "sha512-jOlwnFV2xhuuZeAUILGFULeR6vDPfijEJ57evfocwznQldLU3w2cZ9bSDryY9ip+AsM3r1NJKzf47V2NXebkeQ==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.26" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.15.33", + "@swc/core-darwin-x64": "1.15.33", + "@swc/core-linux-arm-gnueabihf": "1.15.33", + "@swc/core-linux-arm64-gnu": "1.15.33", + "@swc/core-linux-arm64-musl": "1.15.33", + "@swc/core-linux-ppc64-gnu": "1.15.33", + "@swc/core-linux-s390x-gnu": "1.15.33", + "@swc/core-linux-x64-gnu": "1.15.33", + "@swc/core-linux-x64-musl": "1.15.33", + "@swc/core-win32-arm64-msvc": "1.15.33", + "@swc/core-win32-ia32-msvc": "1.15.33", + "@swc/core-win32-x64-msvc": "1.15.33" + }, + "peerDependencies": { + "@swc/helpers": ">=0.5.17" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.15.33", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.33.tgz", + "integrity": "sha512-N+L0uXhuO7FIfzqwgxmzv0zIpV0qEp8wPX3QQs2p4atjMoywup2JTeDlXPw+z9pWJGCae3JjM+tZ6myclI+2gA==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-darwin-x64": { + "version": "1.15.33", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.15.33.tgz", + "integrity": "sha512-/Il4QHSOhV4FekbsDtkrNmKbsX26oSysvgrRswa/RYOHXAkwXDbB4jaeKq6PsJLSPkzJ2KzQ061gtBnk0vNHfA==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.15.33", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.33.tgz", + "integrity": "sha512-C64hBnBxq4viOPQ8hlx+2lJ23bzZBGnjw7ryALmS+0Q3zHmwO8lw1/DArLENw4Q18/0w5wdEO1k3m1wWNtKGqQ==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.15.33", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.33.tgz", + "integrity": "sha512-TRJfnJbX3jqpxRDRoieMzRiCBS5jOmXNb3iQXmcgjFEHKLnAgK1RZRU8Cq1MsPqO4jAJp/ld1G4O3fXuxv85uw==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.15.33", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.33.tgz", + "integrity": "sha512-il7tYM+CpUNzieQbwAjFT1P8zqAhmGWNAGhQZBnxurXZ0aNn+5nqYFTEUKNZl7QibtT0uQXzTZrNGHCIj6Y1Og==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-ppc64-gnu": { + "version": "1.15.33", + "resolved": "https://registry.npmjs.org/@swc/core-linux-ppc64-gnu/-/core-linux-ppc64-gnu-1.15.33.tgz", + "integrity": "sha512-ZtNBwN0Z7CFj9Il0FcPaKdjgP7URyKu/3RfH46vq+0paOBqLj4NYldD6Qo//Duif/7IOtAraUfDOmp0PLAufog==", + "cpu": [ + "ppc64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-s390x-gnu": { + "version": "1.15.33", + "resolved": "https://registry.npmjs.org/@swc/core-linux-s390x-gnu/-/core-linux-s390x-gnu-1.15.33.tgz", + "integrity": "sha512-De1IyajoOmhOYYjw/lx66bKlyDpHZTueqwpDrWgf5O7T6d1ODeJJO9/OqMBmrBQc5C+dNnlmIufHsp4QVCWufA==", + "cpu": [ + "s390x" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.15.33", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.33.tgz", + "integrity": "sha512-mGTH0YxmUN+x6vRN/I6NOk5X0ogNktkwPnJ94IMvR7QjhRDwL0O8RXEDhyUM0YtwWrryBOqaJQBX4zruxEPRGw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.15.33", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.33.tgz", + "integrity": "sha512-hj628ZkSEJf6zMf5VMbYrG2O6QqyTIp2qwY6VlCjvIa9lAEZ5c2lfPblCLVGYubTeLJDxadLB/CxqQYOQABeEQ==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.15.33", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.33.tgz", + "integrity": "sha512-GV2oohtN2/5+KSccl86VULu3aT+LrISC8uzgSq0FRnikpD+Zwc+sBlXmoKQ+Db6jI57ITUOIB8jRkdGMABC29g==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.15.33", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.33.tgz", + "integrity": "sha512-gtyvzSNR8DHKfFEA2uqb8Ld1myqi6uEg2jyeUq3ikn5ytYs7H8RpZYC8mdy4NXr8hfcdJfCLXPlYaqqfBXpoEQ==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.15.33", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.33.tgz", + "integrity": "sha512-d6fRqQSkJI+kmMEBWaDQ7TMl8+YjLYbwRUPZQ9DY0ORBJeTzOrG0twvfvlZ2xgw6jA0ScQKgfBm4vHLSLl5Hqg==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "license": "Apache-2.0" + }, + "node_modules/@swc/html": { + "version": "1.15.33", + "resolved": "https://registry.npmjs.org/@swc/html/-/html-1.15.33.tgz", + "integrity": "sha512-PZIfmj5zYpAJ2eMptf0My2q9Bl8bkraW28+FD1pRnxOiYMrKrP5vL2tB2PdxMRjS0ziLFVM5HEuGFw8PxEDOaw==", + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3" + }, + "engines": { + "node": ">=14" + }, + "optionalDependencies": { + "@swc/html-darwin-arm64": "1.15.33", + "@swc/html-darwin-x64": "1.15.33", + "@swc/html-linux-arm-gnueabihf": "1.15.33", + "@swc/html-linux-arm64-gnu": "1.15.33", + "@swc/html-linux-arm64-musl": "1.15.33", + "@swc/html-linux-ppc64-gnu": "1.15.33", + "@swc/html-linux-s390x-gnu": "1.15.33", + "@swc/html-linux-x64-gnu": "1.15.33", + "@swc/html-linux-x64-musl": "1.15.33", + "@swc/html-win32-arm64-msvc": "1.15.33", + "@swc/html-win32-ia32-msvc": "1.15.33", + "@swc/html-win32-x64-msvc": "1.15.33" + } + }, + "node_modules/@swc/html-darwin-arm64": { + "version": "1.15.33", + "resolved": "https://registry.npmjs.org/@swc/html-darwin-arm64/-/html-darwin-arm64-1.15.33.tgz", + "integrity": "sha512-zyO6uMBfLyCh55wundAxKX+8P/f98ecuyir4VX6nTmn6y7x37ndB8f01LUrd9Tiq6eEAvDXLiqEUvuGjEc7Pmg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/html-darwin-x64": { + "version": "1.15.33", + "resolved": "https://registry.npmjs.org/@swc/html-darwin-x64/-/html-darwin-x64-1.15.33.tgz", + "integrity": "sha512-MaGunsY/J5l7Rb5OmoztEWh+ikooydT7nWkjiDovj7UfkB9HLk5sLr9O7ZdNGJ2u9dD6FX89SzMdA0Psm9NJrQ==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/html-linux-arm-gnueabihf": { + "version": "1.15.33", + "resolved": "https://registry.npmjs.org/@swc/html-linux-arm-gnueabihf/-/html-linux-arm-gnueabihf-1.15.33.tgz", + "integrity": "sha512-CrbUDjVl6/hQ1C5KPMiK4vxk/eOMjxkVELqwnOxsZ+aFVTv3L3YrGMaJ5H47vvIihkPhqiSOUPmMEFqxvqKmXg==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/html-linux-arm64-gnu": { + "version": "1.15.33", + "resolved": "https://registry.npmjs.org/@swc/html-linux-arm64-gnu/-/html-linux-arm64-gnu-1.15.33.tgz", + "integrity": "sha512-7tZ0IgmUslI9Extu/TpxJS0GjJoDx0j9zeq2cIidPdM/njSBpyRB7n4B292Q5WFVh7PcZl7WXqqqMczibQ27aA==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/html-linux-arm64-musl": { + "version": "1.15.33", + "resolved": "https://registry.npmjs.org/@swc/html-linux-arm64-musl/-/html-linux-arm64-musl-1.15.33.tgz", + "integrity": "sha512-gYi2ainYZV2z+jwjp9UKuPVOf3c5q+NkH3QRDjqDrIPLagqDsYNjobi8p5oajGcPGFLNTcVw08VTcubJGChReA==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/html-linux-ppc64-gnu": { + "version": "1.15.33", + "resolved": "https://registry.npmjs.org/@swc/html-linux-ppc64-gnu/-/html-linux-ppc64-gnu-1.15.33.tgz", + "integrity": "sha512-6CfzyVQSdD8ezFdxFve4J/b6qTgXIwYFWEvSdaJvXSgwTy976uUV5Ff1LOF86mt2zWMhZJX9DqmkGyIhepbyWw==", + "cpu": [ + "ppc64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/html-linux-s390x-gnu": { + "version": "1.15.33", + "resolved": "https://registry.npmjs.org/@swc/html-linux-s390x-gnu/-/html-linux-s390x-gnu-1.15.33.tgz", + "integrity": "sha512-Msx1eniw95lhMHUSe3D5FXweKHtkHtzJLsHJDj920uL4Dm7UHqzwaCuZdCmzbkHnO96YjjQvAm266djg8wupmQ==", + "cpu": [ + "s390x" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/html-linux-x64-gnu": { + "version": "1.15.33", + "resolved": "https://registry.npmjs.org/@swc/html-linux-x64-gnu/-/html-linux-x64-gnu-1.15.33.tgz", + "integrity": "sha512-JDNb4Uq+7g+23QuOtwWnP0/EqztWIHFFdQdeBIS5zx83YBG2dYRMdPAjnHJWh2YRZxdepd8q6S9MUIxpSrouAg==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/html-linux-x64-musl": { + "version": "1.15.33", + "resolved": "https://registry.npmjs.org/@swc/html-linux-x64-musl/-/html-linux-x64-musl-1.15.33.tgz", + "integrity": "sha512-NSpZdbz4dj0pu1A0Z9l68Bll5HAzEMtBAeMe6jc4GEVfpIw6eeafQHm2/yMUEh09tgl8t9LzM9DycfdTZDjM4g==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/html-win32-arm64-msvc": { + "version": "1.15.33", + "resolved": "https://registry.npmjs.org/@swc/html-win32-arm64-msvc/-/html-win32-arm64-msvc-1.15.33.tgz", + "integrity": "sha512-w7iho3/zS3lCDqgUZMDLMBO0ElX7j+KgvMb8BOrKqLDOSTDDj3lY/BClNJ7vBpAliI2kPQs/mUikdZyzi4MBjQ==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/html-win32-ia32-msvc": { + "version": "1.15.33", + "resolved": "https://registry.npmjs.org/@swc/html-win32-ia32-msvc/-/html-win32-ia32-msvc-1.15.33.tgz", + "integrity": "sha512-6hJ2pBweSfZ38trYHXmzTBDpRNvqJgFl2PkIWdy4IXbV/Fv0v9Dqe0t9Gi2ZVEBpgI7PD6pF42AT4HmrNTVFyQ==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/html-win32-x64-msvc": { + "version": "1.15.33", + "resolved": "https://registry.npmjs.org/@swc/html-win32-x64-msvc/-/html-win32-x64-msvc-1.15.33.tgz", + "integrity": "sha512-eaY/vNE7rkPKluJYjhOiQOA1tto5VbJOoD1C1xFTBmr9t7WsqYUfbQhYQy5A26/z83NNgtDwELM85rkMB+/vWA==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/types": { + "version": "0.1.26", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.26.tgz", + "integrity": "sha512-lyMwd7WGgG79RS7EERZV3T8wMdmPq3xwyg+1nmAM64kIhx5yl+juO2PYIHb7vTiPgPCj8LYjsNV2T5wiQHUEaw==", + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "license": "MIT", + "dependencies": { + "defer-to-connect": "^2.0.1" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", + "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", + "license": "MIT", + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/debug": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", + "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "license": "MIT" + }, + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.25", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.25.tgz", + "integrity": "sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==", + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "^1" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.8", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.8.tgz", + "integrity": "sha512-02S5fmqeoKzVZCHPZid4b8JH2eM5HzQLZWN2FohQEy/0eXTq8VXZfSN6Pcr3F6N9R/vNrj7cpgbhjie6m/1tCA==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/gtag.js": { + "version": "0.0.20", + "resolved": "https://registry.npmjs.org/@types/gtag.js/-/gtag.js-0.0.20.tgz", + "integrity": "sha512-wwAbk3SA2QeU67unN7zPxjEHmPmlXwZXZvQEpbEUQuMCRGgKyE1m6XDuTUA9b6pCGb/GqJmdfMOY5LuDjJSbbg==", + "license": "MIT" + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/history": { + "version": "4.7.11", + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", + "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==", + "license": "MIT" + }, + "node_modules/@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", + "license": "MIT" + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q==", + "license": "MIT" + }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "license": "MIT" + }, + "node_modules/@types/http-proxy": { + "version": "1.17.17", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.17.tgz", + "integrity": "sha512-ED6LB+Z1AVylNTu7hdzuBqOgMnvG/ld6wGCG8wFnAzKX5uyW2K3WD52v0gnLCTK/VLpXtKckgWuyScYK6cSPaw==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "license": "MIT" + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdx": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.13.tgz", + "integrity": "sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==", + "license": "MIT" + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "license": "MIT" + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "25.9.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.1.tgz", + "integrity": "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==", + "license": "MIT", + "dependencies": { + "undici-types": ">=7.24.0 <7.24.7" + } + }, + "node_modules/@types/prismjs": { + "version": "1.26.6", + "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.6.tgz", + "integrity": "sha512-vqlvI7qlMvcCBbVe0AKAb4f97//Hy0EBTaiW8AalRnG/xAN5zOiWWyrNqNXeq8+KAuvRewjCVY1+IPxk4RdNYw==", + "license": "MIT" + }, + "node_modules/@types/qs": { + "version": "6.15.1", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.15.1.tgz", + "integrity": "sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw==", + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "19.2.15", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.15.tgz", + "integrity": "sha512-eRwcGNHve+E8qtEQSSRl6urh+rFop4v8gm6O8rGv25CodbvFdLjA1vVQ1KkiFE0w0UPOnb8tDiFKL5lp0rtY5Q==", + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-router": { + "version": "5.1.20", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz", + "integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==", + "license": "MIT", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*" + } + }, + "node_modules/@types/react-router-config": { + "version": "5.0.11", + "resolved": "https://registry.npmjs.org/@types/react-router-config/-/react-router-config-5.0.11.tgz", + "integrity": "sha512-WmSAg7WgqW7m4x8Mt4N6ZyKz0BubSj/2tVUMsAHp+Yd2AMwcSbeFq9WympT19p5heCFmF97R9eD5uUR/t4HEqw==", + "license": "MIT", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "^5.1.0" + } + }, + "node_modules/@types/react-router-dom": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", + "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", + "license": "MIT", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "*" + } + }, + "node_modules/@types/retry": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", + "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", + "license": "MIT" + }, + "node_modules/@types/sax": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.7.tgz", + "integrity": "sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", + "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/serve-index": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.10.tgz", + "integrity": "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==", + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "<1" + } + }, + "node_modules/@types/serve-static/node_modules/@types/send": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.6.tgz", + "integrity": "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==", + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/sockjs": { + "version": "0.3.36", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/yargs": { + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", + "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "license": "MIT" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.1.tgz", + "integrity": "sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==", + "license": "ISC" + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", + "license": "MIT", + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", + "license": "Apache-2.0", + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "license": "BSD-3-Clause" + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "license": "Apache-2.0" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-phases": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", + "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", + "license": "MIT", + "engines": { + "node": ">=10.13.0" + }, + "peerDependencies": { + "acorn": "^8.14.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.5", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz", + "integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==", + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/address": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", + "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "license": "MIT", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/algoliasearch": { + "version": "5.52.1", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.52.1.tgz", + "integrity": "sha512-fHA8+kXTbjagw3jkLiaS7KKrH8qe2DyOsiUhGlN4cdT77PEsfqXZl7ewDk1hsg+pJnPlnE50XtLxjR91iJOpmg==", + "license": "MIT", + "dependencies": { + "@algolia/abtesting": "1.18.1", + "@algolia/client-abtesting": "5.52.1", + "@algolia/client-analytics": "5.52.1", + "@algolia/client-common": "5.52.1", + "@algolia/client-insights": "5.52.1", + "@algolia/client-personalization": "5.52.1", + "@algolia/client-query-suggestions": "5.52.1", + "@algolia/client-search": "5.52.1", + "@algolia/ingestion": "1.52.1", + "@algolia/monitoring": "1.52.1", + "@algolia/recommend": "5.52.1", + "@algolia/requester-browser-xhr": "5.52.1", + "@algolia/requester-fetch": "5.52.1", + "@algolia/requester-node-http": "5.52.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/algoliasearch-helper": { + "version": "3.29.1", + "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.29.1.tgz", + "integrity": "sha512-6ck2YFudF2Pje7szQoPBiRFTGfd+1I+0I/WfLPGn0bj1kvrFoOQmNyedNiDxTk3/r4IfSLDYk+RA4G7u8H6+yA==", + "license": "MIT", + "dependencies": { + "@algolia/events": "^4.0.1" + }, + "peerDependencies": { + "algoliasearch": ">= 3.1 < 6" + } + }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "license": "ISC", + "dependencies": { + "string-width": "^4.1.0" + } + }, + "node_modules/ansi-align/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/ansi-align/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "engines": [ + "node >= 0.8.0" + ], + "license": "Apache-2.0", + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ansis": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/ansis/-/ansis-3.17.0.tgz", + "integrity": "sha512-0qWUglt9JEqLFr3w1I1pbrChn1grhaiAR2ocX1PP/flRmxgtwTzPFFFnfIlD6aMOLQZgSuCRlidD70lvx8yhzg==", + "license": "ISC", + "engines": { + "node": ">=14" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/asn1js": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.10.tgz", + "integrity": "sha512-S2s3aOytiKdFRdulw2qPE51MzjzVOisppcVv7jVFR+Kw0kxwvFrDcYA0h7Ndqbmj0HkMIXYWaoj7fli8kgx1eg==", + "license": "BSD-3-Clause", + "dependencies": { + "pvtsutils": "^1.3.6", + "pvutils": "^1.1.5", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/astring": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/astring/-/astring-1.9.0.tgz", + "integrity": "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==", + "license": "MIT", + "bin": { + "astring": "bin/astring" + } + }, + "node_modules/autoprefixer": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.0.tgz", + "integrity": "sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.2", + "caniuse-lite": "^1.0.30001787", + "fraction.js": "^5.3.4", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/babel-loader": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.2.1.tgz", + "integrity": "sha512-fqe8naHt46e0yIdkjUZYqddSXfej3AHajX+CSO5X7oy0EmPc6o5Xh+RClNoHjnieWz9AW4kZxW9yyFMhVB1QLA==", + "license": "MIT", + "dependencies": { + "find-cache-dir": "^4.0.0", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0", + "webpack": ">=5" + } + }, + "node_modules/babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "license": "MIT", + "dependencies": { + "object.assign": "^4.1.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.17", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.17.tgz", + "integrity": "sha512-aTyf30K/rqAsNwN76zYrdtx8obu0E4KoUME29B1xj+B3WxgvWkp943vYQ+z8Mv3lw9xHXMHpvSPOBxzAkIa94w==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-define-polyfill-provider": "^0.6.8", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz", + "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==", + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.5", + "core-js-compat": "^3.43.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.8.tgz", + "integrity": "sha512-M762rNHfSF1EV3SLtnCJXFoQbbIIz0OyRwnCmV0KPC7qosSfCO0QLTSuJX3ayAebubhE6oYBAYPrBA5ljowaZg==", + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.8" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.31", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.31.tgz", + "integrity": "sha512-MujYO3eP72uvmSE0i4wltsodRfIpZATP3jvzRNRGGxgzId7aVocVJJV3nf01qnzzKFGxQVC9bpWxl5cjxTr/7Q==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "license": "MIT" + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/body-parser": { + "version": "1.20.5", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.5.tgz", + "integrity": "sha512-3grm+/2tUOvu2cjJkvsIxrv/wVpfXQW4PsQHYm7yk4vfpu7Ekl6nEsYBoJUL6qDwZUx8wUhQ8tR2qz+ad9c9OA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.15.1", + "raw-body": "~2.5.3", + "type-is": "~1.6.18", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/bonjour-service": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.3.0.tgz", + "integrity": "sha512-3YuAUiSkWykd+2Azjgyxei8OWf8thdn8AITIog2M4UICzoqfjlqr64WIjEXZllf/W6vK1goqleSR6brGomxQqA==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "license": "ISC" + }, + "node_modules/boxen": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-6.2.1.tgz", + "integrity": "sha512-H4PEsJXfFI/Pt8sjDWbHlQPx4zL/bvSQjcilJmaulGt5mLDorHOHpmdXAJcBcmru7PhYSp/cDMWRko4ZUMFkSw==", + "license": "MIT", + "dependencies": { + "ansi-align": "^3.0.1", + "camelcase": "^6.2.0", + "chalk": "^4.1.2", + "cli-boxes": "^3.0.0", + "string-width": "^5.0.1", + "type-fest": "^2.5.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.0.1" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/bytestreamjs": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/bytestreamjs/-/bytestreamjs-2.0.1.tgz", + "integrity": "sha512-U1Z/ob71V/bXfVABvNr/Kumf5VyeQRBEm6Txb0PQ6S7V5GpBM3w4Cbqz/xPDicR5tN0uvDifng8C+5qECeGwyQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/cacheable-lookup": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", + "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", + "license": "MIT", + "engines": { + "node": ">=14.16" + } + }, + "node_modules/cacheable-request": { + "version": "10.2.14", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz", + "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==", + "license": "MIT", + "dependencies": { + "@types/http-cache-semantics": "^4.0.2", + "get-stream": "^6.0.1", + "http-cache-semantics": "^4.1.1", + "keyv": "^4.5.3", + "mimic-response": "^4.0.0", + "normalize-url": "^8.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/call-bind": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz", + "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "get-intrinsic": "^1.3.0", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "license": "MIT", + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001793", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz", + "integrity": "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/cheerio": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", + "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", + "license": "MIT", + "dependencies": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "htmlparser2": "^8.0.1", + "parse5": "^7.0.0", + "parse5-htmlparser2-tree-adapter": "^7.0.0" + }, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "license": "MIT", + "engines": { + "node": ">=6.0" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/clean-css": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", + "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", + "license": "MIT", + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 10.0" + } + }, + "node_modules/clean-css/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-boxes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", + "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-table3": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz", + "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==", + "license": "MIT", + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/cli-table3/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/cli-table3/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/collapse-white-space": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-2.1.0.tgz", + "integrity": "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/colord": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", + "license": "MIT" + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "license": "MIT" + }, + "node_modules/combine-promises": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/combine-promises/-/combine-promises-1.2.0.tgz", + "integrity": "sha512-VcQB1ziGD0NXrhKxiwyNbCDmRzs/OShMs2GqW2DlU2A/Sd0nQxE1oWDAE5O0ygSx5mgQOn9eIFh7yKPgFRVkPQ==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/comlink": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/comlink/-/comlink-4.4.2.tgz", + "integrity": "sha512-OxGdvBmJuNKSCMO4NTl1L47VRp6xn2wG4F/2hYzB6tiCb709otOxtEYCSvK80PtjODfXXZu8ds+Nw5kVCjqd2g==", + "license": "Apache-2.0" + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", + "license": "ISC" + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "license": "MIT", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compressible/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", + "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "compressible": "~2.0.18", + "debug": "2.6.9", + "negotiator": "~0.6.4", + "on-headers": "~1.1.0", + "safe-buffer": "5.2.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" + }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "license": "MIT", + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/config-chain/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "license": "ISC" + }, + "node_modules/configstore": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-6.0.0.tgz", + "integrity": "sha512-cD31W1v3GqUlQvbBCGcXmd2Nj9SvLDOP1oQ0YFuLETufzSPaKp11rYBsSOm7rCsW3OnIRAFM3OxRhceaXNYHkA==", + "license": "BSD-2-Clause", + "dependencies": { + "dot-prop": "^6.0.1", + "graceful-fs": "^4.2.6", + "unique-string": "^3.0.0", + "write-file-atomic": "^3.0.3", + "xdg-basedir": "^5.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/yeoman/configstore?sponsor=1" + } + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", + "license": "MIT" + }, + "node_modules/copy-text-to-clipboard": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-3.2.2.tgz", + "integrity": "sha512-T6SqyLd1iLuqPA90J5N4cTalrtovCySh58iiZDGJ6FGznbclKh4UI+FGacQSgFzwKG77W7XT5gwbVEbd9cIH1A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/copy-webpack-plugin": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", + "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", + "license": "MIT", + "dependencies": { + "fast-glob": "^3.2.11", + "glob-parent": "^6.0.1", + "globby": "^13.1.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/globby": { + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", + "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", + "license": "MIT", + "dependencies": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.3.0", + "ignore": "^5.2.4", + "merge2": "^1.4.1", + "slash": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/copy-webpack-plugin/node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/core-js": { + "version": "3.49.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.49.0.tgz", + "integrity": "sha512-es1U2+YTtzpwkxVLwAFdSpaIMyQaq0PBgm3YD1W3Qpsn1NAmO3KSgZfu+oGSWVu6NvLHoHCV/aYcsE5wiB7ALg==", + "hasInstallScript": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat": { + "version": "3.49.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.49.0.tgz", + "integrity": "sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, + "node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "license": "MIT", + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-random-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", + "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", + "license": "MIT", + "dependencies": { + "type-fest": "^1.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/crypto-random-string/node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/css-blank-pseudo": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-7.0.1.tgz", + "integrity": "sha512-jf+twWGDf6LDoXDUode+nc7ZlrqfaNphrBIBrcmeP3D8yw1uPaix1gCC8LUQUGQ6CycuK2opkbFFWFuq/a94ag==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-blank-pseudo/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/css-declaration-sorter": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-7.4.0.tgz", + "integrity": "sha512-LTuzjPoyA2vMGKKcaOqKSp7Ub2eGrNfKiZH4LpezxpNrsICGCSFvsQOI29psISxNZtaXibkC2CXzrQ5enMeGGw==", + "license": "ISC", + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.0.9" + } + }, + "node_modules/css-has-pseudo": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-7.0.3.tgz", + "integrity": "sha512-oG+vKuGyqe/xvEMoxAQrhi7uY16deJR3i7wwhBerVrGQKSqUC5GiOVxTpM9F9B9hw0J+eKeOWLH7E9gZ1Dr5rA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/selector-specificity": "^5.0.0", + "postcss-selector-parser": "^7.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-has-pseudo/node_modules/@csstools/selector-specificity": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", + "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } + }, + "node_modules/css-has-pseudo/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/css-loader": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz", + "integrity": "sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==", + "license": "MIT", + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/css-minimizer-webpack-plugin": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-5.0.1.tgz", + "integrity": "sha512-3caImjKFQkS+ws1TGcFn0V1HyDJFq1Euy589JlD6/3rV2kj+w7r5G9WDMgSHvpvXHNZ2calVypZWuEDQd9wfLg==", + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "cssnano": "^6.0.1", + "jest-worker": "^29.4.3", + "postcss": "^8.4.24", + "schema-utils": "^4.0.1", + "serialize-javascript": "^6.0.1" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@parcel/css": { + "optional": true + }, + "@swc/css": { + "optional": true + }, + "clean-css": { + "optional": true + }, + "csso": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "lightningcss": { + "optional": true + } + } + }, + "node_modules/css-prefers-color-scheme": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-10.0.0.tgz", + "integrity": "sha512-VCtXZAWivRglTZditUfB4StnsWr6YVZ2PRtuxQLKTNRdtAf8tpzaVPE9zXIF3VaSc7O70iK/j1+NXxyQCqdPjQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-select": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", + "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css-what": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssdb": { + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-8.9.0.tgz", + "integrity": "sha512-J8jOU/hLjaXcO1LldOLraJSQpfLXRKof0I7mtbRyOy2AAXgqst0x9rlgi2qXeD6d0ou3ZLqcPAMqYVbpCbrxEw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + } + ], + "license": "MIT-0" + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssnano": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.1.2.tgz", + "integrity": "sha512-rYk5UeX7VAM/u0lNqewCdasdtPK81CgX8wJFLEIXHbV2oldWRgJAsZrdhRXkV1NJzA2g850KiFm9mMU2HxNxMA==", + "license": "MIT", + "dependencies": { + "cssnano-preset-default": "^6.1.2", + "lilconfig": "^3.1.1" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/cssnano" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/cssnano-preset-advanced": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/cssnano-preset-advanced/-/cssnano-preset-advanced-6.1.2.tgz", + "integrity": "sha512-Nhao7eD8ph2DoHolEzQs5CfRpiEP0xa1HBdnFZ82kvqdmbwVBUr2r1QuQ4t1pi+D1ZpqpcO4T+wy/7RxzJ/WPQ==", + "license": "MIT", + "dependencies": { + "autoprefixer": "^10.4.19", + "browserslist": "^4.23.0", + "cssnano-preset-default": "^6.1.2", + "postcss-discard-unused": "^6.0.5", + "postcss-merge-idents": "^6.0.3", + "postcss-reduce-idents": "^6.0.3", + "postcss-zindex": "^6.0.2" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/cssnano-preset-default": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.1.2.tgz", + "integrity": "sha512-1C0C+eNaeN8OcHQa193aRgYexyJtU8XwbdieEjClw+J9d94E41LwT6ivKH0WT+fYwYWB0Zp3I3IZ7tI/BbUbrg==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "css-declaration-sorter": "^7.2.0", + "cssnano-utils": "^4.0.2", + "postcss-calc": "^9.0.1", + "postcss-colormin": "^6.1.0", + "postcss-convert-values": "^6.1.0", + "postcss-discard-comments": "^6.0.2", + "postcss-discard-duplicates": "^6.0.3", + "postcss-discard-empty": "^6.0.3", + "postcss-discard-overridden": "^6.0.2", + "postcss-merge-longhand": "^6.0.5", + "postcss-merge-rules": "^6.1.1", + "postcss-minify-font-values": "^6.1.0", + "postcss-minify-gradients": "^6.0.3", + "postcss-minify-params": "^6.1.0", + "postcss-minify-selectors": "^6.0.4", + "postcss-normalize-charset": "^6.0.2", + "postcss-normalize-display-values": "^6.0.2", + "postcss-normalize-positions": "^6.0.2", + "postcss-normalize-repeat-style": "^6.0.2", + "postcss-normalize-string": "^6.0.2", + "postcss-normalize-timing-functions": "^6.0.2", + "postcss-normalize-unicode": "^6.1.0", + "postcss-normalize-url": "^6.0.2", + "postcss-normalize-whitespace": "^6.0.2", + "postcss-ordered-values": "^6.0.2", + "postcss-reduce-initial": "^6.1.0", + "postcss-reduce-transforms": "^6.0.2", + "postcss-svgo": "^6.0.3", + "postcss-unique-selectors": "^6.0.4" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/cssnano-utils": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-4.0.2.tgz", + "integrity": "sha512-ZR1jHg+wZ8o4c3zqf1SIUSTIvm/9mU343FMR6Obe/unskbvpGhZOo1J6d/r8D1pzkRQYuwbcH3hToOuoA2G7oQ==", + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/csso": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", + "license": "MIT", + "dependencies": { + "css-tree": "~2.2.0" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", + "license": "CC0-1.0" + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/debounce": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decode-named-character-reference": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", + "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-browser": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.0.tgz", + "integrity": "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==", + "license": "MIT", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "license": "MIT" + }, + "node_modules/detect-port": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.6.1.tgz", + "integrity": "sha512-CmnVc+Hek2egPx1PeTFVta2W78xy2K/9Rkf6cC4T59S50tVnzKj+tnx5mmx5lwvCkujZ4uRrpRSuV+IVs3f90Q==", + "license": "MIT", + "dependencies": { + "address": "^1.0.1", + "debug": "4" + }, + "bin": { + "detect": "bin/detect-port.js", + "detect-port": "bin/detect-port.js" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "license": "MIT", + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "license": "MIT", + "dependencies": { + "utila": "~0.4" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/dot-prop": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", + "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", + "license": "MIT", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/dot-prop/node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "license": "MIT" + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.360", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.360.tgz", + "integrity": "sha512-GkcBt6YYAw9SxFWn+xVar4cLVGlXVuswwtRLBozi2zp0GjXs4ZnOrqV4zbXzg35n7w81hCkyJNYicgXlVHAmBA==", + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, + "node_modules/emojilib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/emojilib/-/emojilib-2.4.0.tgz", + "integrity": "sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==", + "license": "MIT" + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/emoticon": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/emoticon/-/emoticon-4.1.0.tgz", + "integrity": "sha512-VWZfnxqwNcc51hIy/sbOdEem6D+cVtpPzEEtVAFdaas30+1dgkyaOQ4sQ6Bp0tOMqWO1v+HQfYaoodOkdhK6SQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/encoding-sniffer": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.1.tgz", + "integrity": "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==", + "license": "MIT", + "dependencies": { + "iconv-lite": "^0.6.3", + "whatwg-encoding": "^3.1.1" + }, + "funding": { + "url": "https://github.com/fb55/encoding-sniffer?sponsor=1" + } + }, + "node_modules/encoding-sniffer/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.21.6", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.21.6.tgz", + "integrity": "sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz", + "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==", + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esast-util-from-estree": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/esast-util-from-estree/-/esast-util-from-estree-2.0.0.tgz", + "integrity": "sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/esast-util-from-js": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esast-util-from-js/-/esast-util-from-js-2.0.1.tgz", + "integrity": "sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "acorn": "^8.0.0", + "esast-util-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-goat": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-4.0.0.tgz", + "integrity": "sha512-2Sd4ShcWxbx6OY1IHyla/CVNwvg7XwZVoXZHcSu9w9SReNP1EzzD5T8NWKIR38fIqEns9kDWKUQTXXAmlDrdPg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-util-attach-comments": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-attach-comments/-/estree-util-attach-comments-3.0.0.tgz", + "integrity": "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-build-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/estree-util-build-jsx/-/estree-util-build-jsx-3.0.1.tgz", + "integrity": "sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-walker": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-is-identifier-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-scope": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/estree-util-scope/-/estree-util-scope-1.0.0.tgz", + "integrity": "sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-to-js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-to-js/-/estree-util-to-js-2.0.0.tgz", + "integrity": "sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "astring": "^1.8.0", + "source-map": "^0.7.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-value-to-estree": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/estree-util-value-to-estree/-/estree-util-value-to-estree-3.5.0.tgz", + "integrity": "sha512-aMV56R27Gv3QmfmF1MY12GWkGzzeAezAX+UplqHVASfjc9wNzI/X6hC0S9oxq61WT4aQesLGslWP9tKk6ghRZQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/remcohaszing" + } + }, + "node_modules/estree-util-visit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-visit/-/estree-util-visit-2.0.0.tgz", + "integrity": "sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eta": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/eta/-/eta-2.2.0.tgz", + "integrity": "sha512-UVQ72Rqjy/ZKQalzV5dCCJP80GrmPrMxh6NlNf+erV6ObL0ZFkhCstWRawS85z3smdr3d2wXPsZEY7rDPfGd2g==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "url": "https://github.com/eta-dev/eta?sponsor=1" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eval": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eval/-/eval-0.1.8.tgz", + "integrity": "sha512-EzV94NYKoO09GLXGjXj9JIlXijVck4ONSr5wiCWDvhsvj5jxSrzTmRU/9C1DyB6uToszLs8aifA6NQ7lEQdvFw==", + "dependencies": { + "@types/node": "*", + "require-like": ">= 0.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "license": "MIT" + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/express": { + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.2.tgz", + "integrity": "sha512-IuL+Elrou2ZvCFHs18/CIzy2Nzvo25nZ1/D2eIZlz7c+QUayAcYoiM2BthCjs+EBHVpjYjcuLDAiCWgeIX3X1Q==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "~1.20.5", + "content-disposition": "~0.5.4", + "content-type": "~1.0.4", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "~0.1.12", + "proxy-addr": "~2.0.7", + "qs": "~6.15.1", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "~0.19.0", + "serve-static": "~1.16.2", + "setprototypeof": "1.2.0", + "statuses": "~2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express/node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/express/node_modules/path-to-regexp": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", + "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", + "license": "MIT" + }, + "node_modules/express/node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", + "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fault": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fault/-/fault-2.0.1.tgz", + "integrity": "sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==", + "license": "MIT", + "dependencies": { + "format": "^0.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "license": "Apache-2.0", + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/feed": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/feed/-/feed-4.2.2.tgz", + "integrity": "sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==", + "license": "MIT", + "dependencies": { + "xml-js": "^1.6.11" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/file-loader": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", + "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", + "license": "MIT", + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/file-loader/node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/file-loader/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/file-loader/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" + }, + "node_modules/file-loader/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", + "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "statuses": "~2.0.2", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/find-cache-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz", + "integrity": "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==", + "license": "MIT", + "dependencies": { + "common-path-prefix": "^3.0.0", + "pkg-dir": "^7.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "license": "MIT", + "dependencies": { + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/follow-redirects": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data-encoder": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", + "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", + "license": "MIT", + "engines": { + "node": ">= 14.17" + } + }, + "node_modules/format": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", + "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fraction.js": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", + "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.5.tgz", + "integrity": "sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-own-enumerable-property-symbols": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", + "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", + "license": "ISC" + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/github-slugger": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.5.0.tgz", + "integrity": "sha512-wIh+gKBI9Nshz2o46B0B3f5k/W+WI9ZAv6y5Dn5WJ5SK1t0TnDimB4WE5rmTD05ZAIn8HALCZVmCsvj0w0v0lw==", + "license": "ISC" + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-to-regex.js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/glob-to-regex.js/-/glob-to-regex.js-1.2.0.tgz", + "integrity": "sha512-QMwlOQKU/IzqMUOAZWubUOT8Qft+Y0KQWnX9nK3ch0CJg0tTp4TvGZsTfudYKv2NzoQSyPcnA6TYeIQ3jGichQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "license": "BSD-2-Clause" + }, + "node_modules/global-dirs": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", + "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", + "license": "MIT", + "dependencies": { + "ini": "2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/got": { + "version": "12.6.1", + "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", + "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==", + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^5.2.0", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^10.2.8", + "decompress-response": "^6.0.0", + "form-data-encoder": "^2.1.2", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/got/node_modules/@sindresorhus/is": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz", + "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/gray-matter": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", + "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", + "license": "MIT", + "dependencies": { + "js-yaml": "^3.13.1", + "kind-of": "^6.0.2", + "section-matter": "^1.0.0", + "strip-bom-string": "^1.0.0" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/gray-matter/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/gray-matter/node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/gzip-size": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", + "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "license": "MIT", + "dependencies": { + "duplexer": "^0.1.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-yarn": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-3.0.0.tgz", + "integrity": "sha512-IrsVwUHhEULx3R8f/aA8AHuEzAorplsab/v8HBzEiIukwq5i/EC+xmOW+HfP1OaDP+2JkgT1yILHN2O3UFIbcA==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hasown": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz", + "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hast-util-from-parse5": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz", + "integrity": "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "hastscript": "^9.0.0", + "property-information": "^7.0.0", + "vfile": "^6.0.0", + "vfile-location": "^5.0.0", + "web-namespaces": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-parse-selector": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", + "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-raw": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.1.0.tgz", + "integrity": "sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-from-parse5": "^8.0.0", + "hast-util-to-parse5": "^8.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "parse5": "^7.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-estree": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-3.1.3.tgz", + "integrity": "sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-attach-comments": "^3.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-jsx-runtime": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", + "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.1.tgz", + "integrity": "sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hastscript": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz", + "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^4.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/history": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", + "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.1.2", + "loose-envify": "^1.2.0", + "resolve-pathname": "^3.0.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0", + "value-equal": "^1.0.1" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "license": "BSD-3-Clause", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "license": "MIT" + }, + "node_modules/html-minifier-terser": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-7.2.0.tgz", + "integrity": "sha512-tXgn3QfqPIpGl9o+K5tpcj3/MN4SfLtsx2GWwBC3SSd0tXQGyF3gsSqad8loJgKZGM3ZxbYDd5yhiBIdWpmvLA==", + "license": "MIT", + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "~5.3.2", + "commander": "^10.0.0", + "entities": "^4.4.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.15.1" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": "^14.13.1 || >=16.0.0" + } + }, + "node_modules/html-minifier-terser/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/html-tags": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", + "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/html-webpack-plugin": { + "version": "5.6.7", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.7.tgz", + "integrity": "sha512-md+vXtdCAe60s1k6AU3dUyMJnDxUyQAwfwPKoLisvgUF1IXjtlLsk2se54+qfL9Mdm26bbwvjJybpNx48NKRLw==", + "license": "MIT", + "dependencies": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/html-webpack-plugin" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.20.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/html-webpack-plugin/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/html-webpack-plugin/node_modules/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "license": "MIT", + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", + "license": "BSD-2-Clause" + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "license": "MIT" + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz", + "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==", + "license": "MIT" + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "license": "MIT", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.9.tgz", + "integrity": "sha512-c1IyJYLYppU574+YI7R4QyX2ystMtVXZwIdzazUIPIJsHuWNd+mho2j+bKoHftndicGj9yh+xjd+l0yj7VeT1Q==", + "license": "MIT", + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/http-proxy-middleware/node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/http2-wrapper": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", + "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", + "license": "MIT", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/hyperdyperid": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", + "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", + "license": "MIT", + "engines": { + "node": ">=10.18" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "license": "ISC", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/image-size": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-2.0.2.tgz", + "integrity": "sha512-IRqXKlaXwgSMAMtpNzZa1ZAe8m+Sa1770Dhk8VkSsP9LS+iHD62Zd8FQKs8fbPiagBE7BzoFX23cxFnwshpV6w==", + "license": "MIT", + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=16.x" + } + }, + "node_modules/immediate": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.3.0.tgz", + "integrity": "sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q==", + "license": "MIT" + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-lazy": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", + "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/infima": { + "version": "0.2.0-alpha.45", + "resolved": "https://registry.npmjs.org/infima/-/infima-0.2.0-alpha.45.tgz", + "integrity": "sha512-uyH0zfr1erU1OohLk0fT4Rrb94AOhguWNOcD9uGrSpRvNB+6gZXUoJX5J0NtvzBO10YZ9PgvA4NFgt+fYg8ojw==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/inline-style-parser": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.7.tgz", + "integrity": "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==", + "license": "MIT" + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/ipaddr.js": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.4.0.tgz", + "integrity": "sha512-9VGk3HGanVE6JoZXHiCpnGy5X0jYDnN4EA4lntFPj+1vIWlFhIylq2CrrCOJH9EAhc5CYhq18F2Av2tgoAPsYQ==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "license": "MIT", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "license": "MIT" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-ci": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", + "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", + "license": "MIT", + "dependencies": { + "ci-info": "^3.2.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-inside-container/node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "license": "MIT", + "dependencies": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-network-error": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.3.2.tgz", + "integrity": "sha512-PhBY86zaxNZUuWP6h13Vu5oFe0XY6/UlKzQnYFELzGVHygP3MxmvTfYSG7GN3aIab/iWudSMgjSnG9Dq+nHrgA==", + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-npm": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-6.1.0.tgz", + "integrity": "sha512-O2z4/kNgyjhQwVR1Wpkbfc19JIhggF97NZNCpWTnjH7kVcZMUrnut9XSN7txI7VdyIYk5ZatOq3zvSuWpU8hoA==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "license": "MIT" + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-yarn-global": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.4.1.tgz", + "integrity": "sha512-/kppl+R+LO5VmhYSEWARUFjodS25D68gvj8W7z0I7OWhUla5xWu8KL6CtB2V0R6yqhnRgbcaREMr4EEM6htLPQ==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/joi": { + "version": "17.13.3", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.13.3.tgz", + "integrity": "sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==", + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^9.3.0", + "@hapi/topo": "^5.1.0", + "@sideway/address": "^4.1.5", + "@sideway/formula": "^3.0.1", + "@sideway/pinpoint": "^2.0.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/klaw-sync": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", + "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.11" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/latest-version": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz", + "integrity": "sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==", + "license": "MIT", + "dependencies": { + "package-json": "^8.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/launch-editor": { + "version": "2.13.2", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.13.2.tgz", + "integrity": "sha512-4VVDnbOpLXy/s8rdRCSXb+zfMeFR0WlJWpET1iA9CQdlZDfwyLjUuGQzXU4VeOoey6AicSAluWan7Etga6Kcmg==", + "license": "MIT", + "dependencies": { + "picocolors": "^1.1.1", + "shell-quote": "^1.8.3" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, + "node_modules/loader-runner": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.2.tgz", + "integrity": "sha512-DFEqQ3ihfS9blba08cLfYf1NRAIEm+dDjic073DRDc3/JspI/8wYmtDsHwd3+4hwvdxSK7PGaElfTmm0awWJ4w==", + "license": "MIT", + "engines": { + "node": ">=6.11.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "license": "MIT", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "license": "MIT", + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "license": "MIT" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "license": "MIT" + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "license": "MIT" + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "license": "MIT" + }, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", + "license": "MIT" + }, + "node_modules/lunr-languages": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/lunr-languages/-/lunr-languages-1.20.0.tgz", + "integrity": "sha512-3LVgE7ekWXt04NBci/hjm+NXJxXZeRXuyClL0kA0HONyBOjxhP3ZQkuWIM4Ok3pbeptUW/rj3XcJcJuJVPwPYA==", + "license": "MPL-1.1" + }, + "node_modules/mark.js": { + "version": "8.11.1", + "resolved": "https://registry.npmjs.org/mark.js/-/mark.js-8.11.1.tgz", + "integrity": "sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==", + "license": "MIT" + }, + "node_modules/markdown-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-2.0.0.tgz", + "integrity": "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==", + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/markdown-table": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", + "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mdast-util-directive": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-directive/-/mdast-util-directive-3.1.0.tgz", + "integrity": "sha512-I3fNFt+DHmpWCYAT7quoM6lHf9wuqtI+oCOfvILnoicNIqjh5E3dEJWiXuYME2gNe8vl1iMQwyUHa7bgFmak6Q==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", + "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.3.tgz", + "integrity": "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-from-markdown/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/mdast-util-frontmatter": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-frontmatter/-/mdast-util-frontmatter-2.0.1.tgz", + "integrity": "sha512-LRqI9+wdgC25P0URIJY9vwocIzCcksduHQ9OF2joxQoyTNVduwLAFUzjoopuRJbJAReaKrNQKAZKL3uCMugWJA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "escape-string-regexp": "^5.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-extension-frontmatter": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-frontmatter/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mdast-util-gfm": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", + "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", + "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-find-and-replace": "^3.0.0", + "micromark-util-character": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/mdast-util-gfm-autolink-literal/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/mdast-util-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-3.0.0.tgz", + "integrity": "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==", + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-expression": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", + "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-jsx": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", + "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdxjs-esm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", + "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", + "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", + "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdn-data": { + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", + "license": "CC0-1.0" + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "4.57.2", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.57.2.tgz", + "integrity": "sha512-2nWzSsJzrukurSDna4Z0WywuScK4Id3tSKejgu74u8KCdW4uNrseKRSIDg75C6Yw5ZRqBe0F0EtMNlTbUq8bAQ==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/fs-core": "4.57.2", + "@jsonjoy.com/fs-fsa": "4.57.2", + "@jsonjoy.com/fs-node": "4.57.2", + "@jsonjoy.com/fs-node-builtins": "4.57.2", + "@jsonjoy.com/fs-node-to-fsa": "4.57.2", + "@jsonjoy.com/fs-node-utils": "4.57.2", + "@jsonjoy.com/fs-print": "4.57.2", + "@jsonjoy.com/fs-snapshot": "4.57.2", + "@jsonjoy.com/json-pack": "^1.11.0", + "@jsonjoy.com/util": "^1.9.0", + "glob-to-regex.js": "^1.0.1", + "thingies": "^2.5.0", + "tree-dump": "^1.0.3", + "tslib": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromark": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-directive": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/micromark-extension-directive/-/micromark-extension-directive-3.0.2.tgz", + "integrity": "sha512-wjcXHgk+PPdmvR58Le9d7zQYWy+vKEU9Se44p2CrCDPiLr2FMyiT4Fyb5UFKFC66wGB3kPlgD7q3TnoqPS7SZA==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "parse-entities": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-directive/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-directive/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-directive/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-frontmatter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-frontmatter/-/micromark-extension-frontmatter-2.0.0.tgz", + "integrity": "sha512-C4AkuM3dA58cgZha7zVnuVxBhDsbttIMiytjgsM2XbHAB2faRVaHRle40558FBN+DJcrLNCoqG5mlrpdU4cRtg==", + "license": "MIT", + "dependencies": { + "fault": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-frontmatter/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-frontmatter/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", + "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", + "license": "MIT", + "dependencies": { + "micromark-extension-gfm-autolink-literal": "^2.0.0", + "micromark-extension-gfm-footnote": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-tagfilter": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", + "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", + "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-table/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-table/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", + "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", + "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-task-list-item/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-task-list-item/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-mdx-expression": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.1.tgz", + "integrity": "sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-expression/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-expression/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-expression/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-mdx-jsx": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.2.tgz", + "integrity": "sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdx-jsx/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-jsx/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-jsx/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-mdx-md": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-md/-/micromark-extension-mdx-md-2.0.0.tgz", + "integrity": "sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs/-/micromark-extension-mdxjs-3.0.0.tgz", + "integrity": "sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==", + "license": "MIT", + "dependencies": { + "acorn": "^8.0.0", + "acorn-jsx": "^5.0.0", + "micromark-extension-mdx-expression": "^3.0.0", + "micromark-extension-mdx-jsx": "^3.0.0", + "micromark-extension-mdx-md": "^2.0.0", + "micromark-extension-mdxjs-esm": "^3.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs-esm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-3.0.0.tgz", + "integrity": "sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs-esm/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdxjs-esm/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-destination/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-destination/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-factory-mdx-expression": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.3.tgz", + "integrity": "sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + } + }, + "node_modules/micromark-factory-mdx-expression/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-mdx-expression/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-mdx-expression/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-factory-space": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-1.1.0.tgz", + "integrity": "sha512-cRzEj7c0OL4Mw2v6nwzttyOZe8XY/Z8G0rzmWQZTBi/jjwyw/U4uqKtUORXQrR5bAZZnbTI/feRV/R7hc4jQYQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-factory-space/node_modules/micromark-util-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.1.0.tgz", + "integrity": "sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-character": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-1.2.0.tgz", + "integrity": "sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-character/node_modules/micromark-util-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.1.0.tgz", + "integrity": "sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-decode-string": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", + "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-events-to-acorn": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.3.tgz", + "integrity": "sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + } + }, + "node_modules/micromark-util-events-to-acorn/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-normalize-identifier/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-symbol": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-1.1.0.tgz", + "integrity": "sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", + "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "license": "MIT", + "dependencies": { + "mime-db": "~1.33.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/mimic-response": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", + "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mini-css-extract-plugin": { + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.10.2.tgz", + "integrity": "sha512-AOSS0IdEB95ayVkxn5oGzNQwqAi2J0Jb/kKm43t7H73s8+f5873g0yuj0PNvK4dO75mu5DHg4nlgp4k6Kga8eg==", + "license": "MIT", + "dependencies": { + "schema-utils": "^4.0.0", + "tapable": "^2.2.1" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "license": "ISC" + }, + "node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "license": "MIT", + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/nanoid": { + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "license": "MIT" + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "license": "MIT", + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/node-emoji": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-2.2.0.tgz", + "integrity": "sha512-Z3lTE9pLaJF47NyMhd4ww1yFTAP8YhYI8SleJiHzM46Fgpm5cnNzSl9XfzFNqbaz+VlJrIj3fXQ4DeN1Rjm6cw==", + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^4.6.0", + "char-regex": "^1.0.2", + "emojilib": "^2.4.0", + "skin-tone": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/node-releases": { + "version": "2.0.44", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.44.tgz", + "integrity": "sha512-5WUyunoPMsvvEhS8AxHtRzP+oA8UCkJ7YRxatWKjngndhDGLiqEVAQKWjFAiAiuL8zMRGzGSJxFnLetoa43qGQ==", + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.1.1.tgz", + "integrity": "sha512-JYc0DPlpGWB40kH5g07gGTrYuMqV653k3uBKY6uITPWds3M0ov3GaWGp9lbE3Bzngx8+XkfzgvASb9vk9JDFXQ==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nprogress": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz", + "integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==", + "license": "MIT" + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/null-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/null-loader/-/null-loader-4.0.1.tgz", + "integrity": "sha512-pxqVbi4U6N26lq+LmgIbB5XATP0VdZKOG25DhHi8btMmJJefGArFyDg1yc4U3hWCJbMqSrw0qyrz1UQX+qYXqg==", + "license": "MIT", + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/null-loader/node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/null-loader/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/null-loader/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" + }, + "node_modules/null-loader/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "license": "MIT" + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "license": "MIT", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "license": "(WTFPL OR MIT)", + "bin": { + "opener": "bin/opener-bin.js" + } + }, + "node_modules/p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "license": "MIT", + "engines": { + "node": ">=12.20" + } + }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "license": "MIT", + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "license": "MIT", + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-queue": { + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz", + "integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==", + "license": "MIT", + "dependencies": { + "eventemitter3": "^4.0.4", + "p-timeout": "^3.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-retry": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.1.tgz", + "integrity": "sha512-hEt02O4hUct5wtwg4H4KcWgDdm+l1bOaEy/hWzd8xtXB9BqxTWBBhb+2ImAtH4Cv4rPjV76xN3Zumqk3k3AhhQ==", + "license": "MIT", + "dependencies": { + "@types/retry": "0.12.2", + "is-network-error": "^1.0.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "license": "MIT", + "dependencies": { + "p-finally": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/package-json": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.1.tgz", + "integrity": "sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==", + "license": "MIT", + "dependencies": { + "got": "^12.1.0", + "registry-auth-token": "^5.0.1", + "registry-url": "^6.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "license": "MIT", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-entities": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-numeric-range": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/parse-numeric-range/-/parse-numeric-range-1.3.0.tgz", + "integrity": "sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==", + "license": "ISC" + }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz", + "integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==", + "license": "MIT", + "dependencies": { + "domhandler": "^5.0.3", + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-parser-stream": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz", + "integrity": "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==", + "license": "MIT", + "dependencies": { + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5/node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", + "license": "(WTFPL OR MIT)" + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/path-to-regexp": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.9.0.tgz", + "integrity": "sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g==", + "license": "MIT", + "dependencies": { + "isarray": "0.0.1" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-dir": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", + "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", + "license": "MIT", + "dependencies": { + "find-up": "^6.3.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkijs": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/pkijs/-/pkijs-3.4.0.tgz", + "integrity": "sha512-emEcLuomt2j03vxD54giVB4SxTjnsqkU692xZOZXHDVoYyypEm+b3jpiTcc+Cf+myooc+/Ly0z01jqeNHVgJGw==", + "license": "BSD-3-Clause", + "dependencies": { + "@noble/hashes": "1.4.0", + "asn1js": "^3.0.6", + "bytestreamjs": "^2.0.1", + "pvtsutils": "^1.3.6", + "pvutils": "^1.1.3", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/postcss": { + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.12", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-attribute-case-insensitive": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-7.0.1.tgz", + "integrity": "sha512-Uai+SupNSqzlschRyNx3kbCTWgY/2hcwtHEI/ej2LJWc9JJ77qKgGptd8DHwY1mXtZ7Aoh4z4yxfwMBue9eNgw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-attribute-case-insensitive/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-calc": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-9.0.1.tgz", + "integrity": "sha512-TipgjGyzP5QzEhsOZUaIkeO5mKeMFpebWzRogWG/ysonUlnHcq5aJe0jOjpfzUU8PeSaBQnrE8ehR0QA5vs8PQ==", + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.0.11", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.2" + } + }, + "node_modules/postcss-clamp": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-clamp/-/postcss-clamp-4.1.0.tgz", + "integrity": "sha512-ry4b1Llo/9zz+PKC+030KUnPITTJAHeOwjfAyyB60eT0AorGLdzp52s31OsPRHRf8NchkgFoG2y6fCfn1IV1Ow==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=7.6.0" + }, + "peerDependencies": { + "postcss": "^8.4.6" + } + }, + "node_modules/postcss-color-functional-notation": { + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-7.0.12.tgz", + "integrity": "sha512-TLCW9fN5kvO/u38/uesdpbx3e8AkTYhMvDZYa9JpmImWuTE99bDQ7GU7hdOADIZsiI9/zuxfAJxny/khknp1Zw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-color-hex-alpha": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-10.0.0.tgz", + "integrity": "sha512-1kervM2cnlgPs2a8Vt/Qbe5cQ++N7rkYo/2rz2BkqJZIHQwaVuJgQH38REHrAi4uM0b1fqxMkWYmese94iMp3w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-color-rebeccapurple": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-10.0.0.tgz", + "integrity": "sha512-JFta737jSP+hdAIEhk1Vs0q0YF5P8fFcj+09pweS8ktuGuZ8pPlykHsk6mPxZ8awDl4TrcxUqJo9l1IhVr/OjQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-colormin": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-6.1.0.tgz", + "integrity": "sha512-x9yX7DOxeMAR+BgGVnNSAxmAj98NX/YxEMNFP+SDCEeNLb2r3i6Hh1ksMsnW8Ub5SLCpbescQqn9YEbE9554Sw==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-api": "^3.0.0", + "colord": "^2.9.3", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-convert-values": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-6.1.0.tgz", + "integrity": "sha512-zx8IwP/ts9WvUM6NkVSkiU902QZL1bwPhaVaLynPtCsOTqp+ZKbNi+s6XJg3rfqpKGA/oc7Oxk5t8pOQJcwl/w==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-custom-media": { + "version": "11.0.6", + "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-11.0.6.tgz", + "integrity": "sha512-C4lD4b7mUIw+RZhtY7qUbf4eADmb7Ey8BFA2px9jUbwg7pjTZDl4KY4bvlUV+/vXQvzQRfiGEVJyAbtOsCMInw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/cascade-layer-name-parser": "^2.0.5", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/media-query-list-parser": "^4.0.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-custom-properties": { + "version": "14.0.6", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-14.0.6.tgz", + "integrity": "sha512-fTYSp3xuk4BUeVhxCSJdIPhDLpJfNakZKoiTDx7yRGCdlZrSJR7mWKVOBS4sBF+5poPQFMj2YdXx1VHItBGihQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/cascade-layer-name-parser": "^2.0.5", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-custom-selectors": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-8.0.5.tgz", + "integrity": "sha512-9PGmckHQswiB2usSO6XMSswO2yFWVoCAuih1yl9FVcwkscLjRKjwsjM3t+NIWpSU2Jx3eOiK2+t4vVTQaoCHHg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/cascade-layer-name-parser": "^2.0.5", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-custom-selectors/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-dir-pseudo-class": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-9.0.1.tgz", + "integrity": "sha512-tRBEK0MHYvcMUrAuYMEOa0zg9APqirBcgzi6P21OhxtJyJADo/SWBwY1CAwEohQ/6HDaa9jCjLRG7K3PVQYHEA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-dir-pseudo-class/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-discard-comments": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-6.0.2.tgz", + "integrity": "sha512-65w/uIqhSBBfQmYnG92FO1mWZjJ4GL5b8atm5Yw2UgrwD7HiNiSSNwJor1eCFGzUgYnN/iIknhNRVqjrrpuglw==", + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-duplicates": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-6.0.3.tgz", + "integrity": "sha512-+JA0DCvc5XvFAxwx6f/e68gQu/7Z9ud584VLmcgto28eB8FqSFZwtrLwB5Kcp70eIoWP/HXqz4wpo8rD8gpsTw==", + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-empty": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-6.0.3.tgz", + "integrity": "sha512-znyno9cHKQsK6PtxL5D19Fj9uwSzC2mB74cpT66fhgOadEUPyXFkbgwm5tvc3bt3NAy8ltE5MrghxovZRVnOjQ==", + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-overridden": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-6.0.2.tgz", + "integrity": "sha512-j87xzI4LUggC5zND7KdjsI25APtyMuynXZSujByMaav2roV6OZX+8AaCUcZSWqckZpjAjRyFDdpqybgjFO0HJQ==", + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-unused": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-6.0.5.tgz", + "integrity": "sha512-wHalBlRHkaNnNwfC8z+ppX57VhvS+HWgjW508esjdaEYr3Mx7Gnn2xA4R/CKf5+Z9S5qsqC+Uzh4ueENWwCVUA==", + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.0.16" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-double-position-gradients": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-6.0.4.tgz", + "integrity": "sha512-m6IKmxo7FxSP5nF2l63QbCC3r+bWpFUWmZXZf096WxG0m7Vl1Q1+ruFOhpdDRmKrRS+S3Jtk+TVk/7z0+BVK6g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-focus-visible": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-10.0.1.tgz", + "integrity": "sha512-U58wyjS/I1GZgjRok33aE8juW9qQgQUNwTSdxQGuShHzwuYdcklnvK/+qOWX1Q9kr7ysbraQ6ht6r+udansalA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-focus-visible/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-focus-within": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-9.0.1.tgz", + "integrity": "sha512-fzNUyS1yOYa7mOjpci/bR+u+ESvdar6hk8XNK/TRR0fiGTp2QT5N+ducP0n3rfH/m9I7H/EQU6lsa2BrgxkEjw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-focus-within/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-font-variant": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz", + "integrity": "sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==", + "license": "MIT", + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-gap-properties": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-6.0.0.tgz", + "integrity": "sha512-Om0WPjEwiM9Ru+VhfEDPZJAKWUd0mV1HmNXqp2C29z80aQ2uP9UVhLc7e3aYMIor/S5cVhoPgYQ7RtfeZpYTRw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-image-set-function": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-7.0.0.tgz", + "integrity": "sha512-QL7W7QNlZuzOwBTeXEmbVckNt1FSmhQtbMRvGGqqU4Nf4xk6KUEQhAoWuMzwbSv5jxiRiSZ5Tv7eiDB9U87znA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-lab-function": { + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-7.0.12.tgz", + "integrity": "sha512-tUcyRk1ZTPec3OuKFsqtRzW2Go5lehW29XA21lZ65XmzQkz43VY2tyWEC202F7W3mILOjw0voOiuxRGTsN+J9w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-loader": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.3.4.tgz", + "integrity": "sha512-iW5WTTBSC5BfsBJ9daFMPVrLT36MrNiC6fqOZTTaHjBNX6Pfd5p+hSBqe/fEeNd7pc13QiAyGt7VdGMw4eRC4A==", + "license": "MIT", + "dependencies": { + "cosmiconfig": "^8.3.5", + "jiti": "^1.20.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" + } + }, + "node_modules/postcss-logical": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-8.1.0.tgz", + "integrity": "sha512-pL1hXFQ2fEXNKiNiAgtfA005T9FBxky5zkX6s4GZM2D8RkVgRqz3f4g1JUoq925zXv495qk8UNldDwh8uGEDoA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-merge-idents": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-6.0.3.tgz", + "integrity": "sha512-1oIoAsODUs6IHQZkLQGO15uGEbK3EAl5wi9SS8hs45VgsxQfMnxvt+L+zIr7ifZFIH14cfAeVe2uCTa+SPRa3g==", + "license": "MIT", + "dependencies": { + "cssnano-utils": "^4.0.2", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-merge-longhand": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-6.0.5.tgz", + "integrity": "sha512-5LOiordeTfi64QhICp07nzzuTDjNSO8g5Ksdibt44d+uvIIAE1oZdRn8y/W5ZtYgRH/lnLDlvi9F8btZcVzu3w==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "stylehacks": "^6.1.1" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-merge-rules": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.1.1.tgz", + "integrity": "sha512-KOdWF0gju31AQPZiD+2Ar9Qjowz1LTChSjFFbS+e2sFgc4uHOp3ZvVX4sNeTlk0w2O31ecFGgrFzhO0RSWbWwQ==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^4.0.2", + "postcss-selector-parser": "^6.0.16" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-font-values": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-6.1.0.tgz", + "integrity": "sha512-gklfI/n+9rTh8nYaSJXlCo3nOKqMNkxuGpTn/Qm0gstL3ywTr9/WRKznE+oy6fvfolH6dF+QM4nCo8yPLdvGJg==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-gradients": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-6.0.3.tgz", + "integrity": "sha512-4KXAHrYlzF0Rr7uc4VrfwDJ2ajrtNEpNEuLxFgwkhFZ56/7gaE4Nr49nLsQDZyUe+ds+kEhf+YAUolJiYXF8+Q==", + "license": "MIT", + "dependencies": { + "colord": "^2.9.3", + "cssnano-utils": "^4.0.2", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-params": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-6.1.0.tgz", + "integrity": "sha512-bmSKnDtyyE8ujHQK0RQJDIKhQ20Jq1LYiez54WiaOoBtcSuflfK3Nm596LvbtlFcpipMjgClQGyGr7GAs+H1uA==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "cssnano-utils": "^4.0.2", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-selectors": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-6.0.4.tgz", + "integrity": "sha512-L8dZSwNLgK7pjTto9PzWRoMbnLq5vsZSTu8+j1P/2GB8qdtGQfn+K1uSvFgYvgh83cbyxT5m43ZZhUMTJDSClQ==", + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.0.16" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", + "license": "ISC", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.2.0.tgz", + "integrity": "sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==", + "license": "MIT", + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^7.0.0", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz", + "integrity": "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==", + "license": "ISC", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "license": "ISC", + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-nesting": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-13.0.2.tgz", + "integrity": "sha512-1YCI290TX+VP0U/K/aFxzHzQWHWURL+CtHMSbex1lCdpXD1SoR2sYuxDu5aNI9lPoXpKTCggFZiDJbwylU0LEQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/selector-resolve-nested": "^3.1.0", + "@csstools/selector-specificity": "^5.0.0", + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-nesting/node_modules/@csstools/selector-resolve-nested": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-resolve-nested/-/selector-resolve-nested-3.1.0.tgz", + "integrity": "sha512-mf1LEW0tJLKfWyvn5KdDrhpxHyuxpbNwTIwOYLIvsTffeyOf85j5oIzfG0yosxDgx/sswlqBnESYUcQH0vgZ0g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } + }, + "node_modules/postcss-nesting/node_modules/@csstools/selector-specificity": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", + "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } + }, + "node_modules/postcss-nesting/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-normalize-charset": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-6.0.2.tgz", + "integrity": "sha512-a8N9czmdnrjPHa3DeFlwqst5eaL5W8jYu3EBbTTkI5FHkfMhFZh1EGbku6jhHhIzTA6tquI2P42NtZ59M/H/kQ==", + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-display-values": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-6.0.2.tgz", + "integrity": "sha512-8H04Mxsb82ON/aAkPeq8kcBbAtI5Q2a64X/mnRRfPXBq7XeogoQvReqxEfc0B4WPq1KimjezNC8flUtC3Qz6jg==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-positions": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-6.0.2.tgz", + "integrity": "sha512-/JFzI441OAB9O7VnLA+RtSNZvQ0NCFZDOtp6QPFo1iIyawyXg0YI3CYM9HBy1WvwCRHnPep/BvI1+dGPKoXx/Q==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-repeat-style": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-6.0.2.tgz", + "integrity": "sha512-YdCgsfHkJ2jEXwR4RR3Tm/iOxSfdRt7jplS6XRh9Js9PyCR/aka/FCb6TuHT2U8gQubbm/mPmF6L7FY9d79VwQ==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-string": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-6.0.2.tgz", + "integrity": "sha512-vQZIivlxlfqqMp4L9PZsFE4YUkWniziKjQWUtsxUiVsSSPelQydwS8Wwcuw0+83ZjPWNTl02oxlIvXsmmG+CiQ==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-timing-functions": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-6.0.2.tgz", + "integrity": "sha512-a+YrtMox4TBtId/AEwbA03VcJgtyW4dGBizPl7e88cTFULYsprgHWTbfyjSLyHeBcK/Q9JhXkt2ZXiwaVHoMzA==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-unicode": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-6.1.0.tgz", + "integrity": "sha512-QVC5TQHsVj33otj8/JD869Ndr5Xcc/+fwRh4HAsFsAeygQQXm+0PySrKbr/8tkDKzW+EVT3QkqZMfFrGiossDg==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-url": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-6.0.2.tgz", + "integrity": "sha512-kVNcWhCeKAzZ8B4pv/DnrU1wNh458zBNp8dh4y5hhxih5RZQ12QWMuQrDgPRw3LRl8mN9vOVfHl7uhvHYMoXsQ==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-whitespace": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-6.0.2.tgz", + "integrity": "sha512-sXZ2Nj1icbJOKmdjXVT9pnyHQKiSAyuNQHSgRCUgThn2388Y9cGVDR+E9J9iAYbSbLHI+UUwLVl1Wzco/zgv0Q==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-opacity-percentage": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-opacity-percentage/-/postcss-opacity-percentage-3.0.0.tgz", + "integrity": "sha512-K6HGVzyxUxd/VgZdX04DCtdwWJ4NGLG212US4/LA1TLAbHgmAsTWVR86o+gGIbFtnTkfOpb9sCRBx8K7HO66qQ==", + "funding": [ + { + "type": "kofi", + "url": "https://ko-fi.com/mrcgrtz" + }, + { + "type": "liberapay", + "url": "https://liberapay.com/mrcgrtz" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-ordered-values": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-6.0.2.tgz", + "integrity": "sha512-VRZSOB+JU32RsEAQrO94QPkClGPKJEL/Z9PCBImXMhIeK5KAYo6slP/hBYlLgrCjFxyqvn5VC81tycFEDBLG1Q==", + "license": "MIT", + "dependencies": { + "cssnano-utils": "^4.0.2", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-overflow-shorthand": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-6.0.0.tgz", + "integrity": "sha512-BdDl/AbVkDjoTofzDQnwDdm/Ym6oS9KgmO7Gr+LHYjNWJ6ExORe4+3pcLQsLA9gIROMkiGVjjwZNoL/mpXHd5Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-page-break": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-3.0.4.tgz", + "integrity": "sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==", + "license": "MIT", + "peerDependencies": { + "postcss": "^8" + } + }, + "node_modules/postcss-place": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-10.0.0.tgz", + "integrity": "sha512-5EBrMzat2pPAxQNWYavwAfoKfYcTADJ8AXGVPcUZ2UkNloUTWzJQExgrzrDkh3EKzmAx1evfTAzF9I8NGcc+qw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-preset-env": { + "version": "10.6.1", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-10.6.1.tgz", + "integrity": "sha512-yrk74d9EvY+W7+lO9Aj1QmjWY9q5NsKjK2V9drkOPZB/X6KZ0B3igKsHUYakb7oYVhnioWypQX3xGuePf89f3g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/postcss-alpha-function": "^1.0.1", + "@csstools/postcss-cascade-layers": "^5.0.2", + "@csstools/postcss-color-function": "^4.0.12", + "@csstools/postcss-color-function-display-p3-linear": "^1.0.1", + "@csstools/postcss-color-mix-function": "^3.0.12", + "@csstools/postcss-color-mix-variadic-function-arguments": "^1.0.2", + "@csstools/postcss-content-alt-text": "^2.0.8", + "@csstools/postcss-contrast-color-function": "^2.0.12", + "@csstools/postcss-exponential-functions": "^2.0.9", + "@csstools/postcss-font-format-keywords": "^4.0.0", + "@csstools/postcss-gamut-mapping": "^2.0.11", + "@csstools/postcss-gradients-interpolation-method": "^5.0.12", + "@csstools/postcss-hwb-function": "^4.0.12", + "@csstools/postcss-ic-unit": "^4.0.4", + "@csstools/postcss-initial": "^2.0.1", + "@csstools/postcss-is-pseudo-class": "^5.0.3", + "@csstools/postcss-light-dark-function": "^2.0.11", + "@csstools/postcss-logical-float-and-clear": "^3.0.0", + "@csstools/postcss-logical-overflow": "^2.0.0", + "@csstools/postcss-logical-overscroll-behavior": "^2.0.0", + "@csstools/postcss-logical-resize": "^3.0.0", + "@csstools/postcss-logical-viewport-units": "^3.0.4", + "@csstools/postcss-media-minmax": "^2.0.9", + "@csstools/postcss-media-queries-aspect-ratio-number-values": "^3.0.5", + "@csstools/postcss-nested-calc": "^4.0.0", + "@csstools/postcss-normalize-display-values": "^4.0.1", + "@csstools/postcss-oklab-function": "^4.0.12", + "@csstools/postcss-position-area-property": "^1.0.0", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/postcss-property-rule-prelude-list": "^1.0.0", + "@csstools/postcss-random-function": "^2.0.1", + "@csstools/postcss-relative-color-syntax": "^3.0.12", + "@csstools/postcss-scope-pseudo-class": "^4.0.1", + "@csstools/postcss-sign-functions": "^1.1.4", + "@csstools/postcss-stepped-value-functions": "^4.0.9", + "@csstools/postcss-syntax-descriptor-syntax-production": "^1.0.1", + "@csstools/postcss-system-ui-font-family": "^1.0.0", + "@csstools/postcss-text-decoration-shorthand": "^4.0.3", + "@csstools/postcss-trigonometric-functions": "^4.0.9", + "@csstools/postcss-unset-value": "^4.0.0", + "autoprefixer": "^10.4.23", + "browserslist": "^4.28.1", + "css-blank-pseudo": "^7.0.1", + "css-has-pseudo": "^7.0.3", + "css-prefers-color-scheme": "^10.0.0", + "cssdb": "^8.6.0", + "postcss-attribute-case-insensitive": "^7.0.1", + "postcss-clamp": "^4.1.0", + "postcss-color-functional-notation": "^7.0.12", + "postcss-color-hex-alpha": "^10.0.0", + "postcss-color-rebeccapurple": "^10.0.0", + "postcss-custom-media": "^11.0.6", + "postcss-custom-properties": "^14.0.6", + "postcss-custom-selectors": "^8.0.5", + "postcss-dir-pseudo-class": "^9.0.1", + "postcss-double-position-gradients": "^6.0.4", + "postcss-focus-visible": "^10.0.1", + "postcss-focus-within": "^9.0.1", + "postcss-font-variant": "^5.0.0", + "postcss-gap-properties": "^6.0.0", + "postcss-image-set-function": "^7.0.0", + "postcss-lab-function": "^7.0.12", + "postcss-logical": "^8.1.0", + "postcss-nesting": "^13.0.2", + "postcss-opacity-percentage": "^3.0.0", + "postcss-overflow-shorthand": "^6.0.0", + "postcss-page-break": "^3.0.4", + "postcss-place": "^10.0.0", + "postcss-pseudo-class-any-link": "^10.0.1", + "postcss-replace-overflow-wrap": "^4.0.0", + "postcss-selector-not": "^8.0.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-pseudo-class-any-link": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-10.0.1.tgz", + "integrity": "sha512-3el9rXlBOqTFaMFkWDOkHUTQekFIYnaQY55Rsp8As8QQkpiSgIYEcF/6Ond93oHiDsGb4kad8zjt+NPlOC1H0Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-pseudo-class-any-link/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-reduce-idents": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-6.0.3.tgz", + "integrity": "sha512-G3yCqZDpsNPoQgbDUy3T0E6hqOQ5xigUtBQyrmq3tn2GxlyiL0yyl7H+T8ulQR6kOcHJ9t7/9H4/R2tv8tJbMA==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-reduce-initial": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.1.0.tgz", + "integrity": "sha512-RarLgBK/CrL1qZags04oKbVbrrVK2wcxhvta3GCxrZO4zveibqbRPmm2VI8sSgCXwoUHEliRSbOfpR0b/VIoiw==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-api": "^3.0.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-reduce-transforms": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-6.0.2.tgz", + "integrity": "sha512-sB+Ya++3Xj1WaT9+5LOOdirAxP7dJZms3GRcYheSPi1PiTMigsxHAdkrbItHxwYHr4kt1zL7mmcHstgMYT+aiA==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-replace-overflow-wrap": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz", + "integrity": "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==", + "license": "MIT", + "peerDependencies": { + "postcss": "^8.0.3" + } + }, + "node_modules/postcss-selector-not": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-8.0.1.tgz", + "integrity": "sha512-kmVy/5PYVb2UOhy0+LqUYAhKj7DUGDpSWa5LZqlkWJaaAV+dxxsOG3+St0yNLu6vsKD7Dmqx+nWQt0iil89+WA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-selector-not/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-sort-media-queries": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/postcss-sort-media-queries/-/postcss-sort-media-queries-5.2.0.tgz", + "integrity": "sha512-AZ5fDMLD8SldlAYlvi8NIqo0+Z8xnXU2ia0jxmuhxAU+Lqt9K+AlmLNJ/zWEnE9x+Zx3qL3+1K20ATgNOr3fAA==", + "license": "MIT", + "dependencies": { + "sort-css-media-queries": "2.2.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.4.23" + } + }, + "node_modules/postcss-svgo": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-6.0.3.tgz", + "integrity": "sha512-dlrahRmxP22bX6iKEjOM+c8/1p+81asjKT+V5lrgOH944ryx/OHpclnIbGsKVd3uWOXFLYJwCVf0eEkJGvO96g==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "svgo": "^3.2.0" + }, + "engines": { + "node": "^14 || ^16 || >= 18" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-unique-selectors": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-6.0.4.tgz", + "integrity": "sha512-K38OCaIrO8+PzpArzkLKB42dSARtC2tmG6PvD4b1o1Q2E9Os8jzfWFfSy/rixsHwohtsDdFtAWGjFVFUdwYaMg==", + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.0.16" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "license": "MIT" + }, + "node_modules/postcss-zindex": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-6.0.2.tgz", + "integrity": "sha512-5BxW9l1evPB/4ZIc+2GobEBoKC+h8gPGCMi+jxsYvd2x0mjq7wazk6DrP71pStqxE9Foxh5TVnonbWpFZzXaYg==", + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, + "node_modules/pretty-time": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pretty-time/-/pretty-time-1.1.0.tgz", + "integrity": "sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/prism-react-renderer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-2.4.1.tgz", + "integrity": "sha512-ey8Ls/+Di31eqzUxC46h8MksNuGx/n0AAC8uKpwFau4RPDYLuE3EXTp8N8G2vX2N7UC/+IXeNUnlWBGGcAG+Ig==", + "license": "MIT", + "dependencies": { + "@types/prismjs": "^1.26.0", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "react": ">=16.0.0" + } + }, + "node_modules/prismjs": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", + "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/property-information": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", + "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "license": "ISC" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pupa": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-3.3.0.tgz", + "integrity": "sha512-LjgDO2zPtoXP2wJpDjZrGdojii1uqO0cnwKoIoUzkfS98HDmbeiGmYiXo3lXeFlq2xvne1QFQhwYXSUCLKtEuA==", + "license": "MIT", + "dependencies": { + "escape-goat": "^4.0.0" + }, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pvtsutils": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.6.tgz", + "integrity": "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.8.1" + } + }, + "node_modules/pvutils": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.5.tgz", + "integrity": "sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==", + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/qs": { + "version": "6.15.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", + "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "license": "ISC" + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react": { + "version": "19.2.6", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.6.tgz", + "integrity": "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.6", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.6.tgz", + "integrity": "sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.6" + } + }, + "node_modules/react-fast-compare": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", + "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==", + "license": "MIT" + }, + "node_modules/react-helmet-async": { + "name": "@slorber/react-helmet-async", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@slorber/react-helmet-async/-/react-helmet-async-1.3.0.tgz", + "integrity": "sha512-e9/OK8VhwUSc67diWI8Rb3I0YgI9/SBQtnhe9aEuK6MhZm7ntZZimXgwXnd8W96YTmSOb9M4d8LwhRZyhWr/1A==", + "license": "Apache-2.0", + "dependencies": { + "@babel/runtime": "^7.12.5", + "invariant": "^2.2.4", + "prop-types": "^15.7.2", + "react-fast-compare": "^3.2.0", + "shallowequal": "^1.1.0" + }, + "peerDependencies": { + "react": "^16.6.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.6.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/react-json-view-lite": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/react-json-view-lite/-/react-json-view-lite-2.5.0.tgz", + "integrity": "sha512-tk7o7QG9oYyELWHL8xiMQ8x4WzjCzbWNyig3uexmkLb54r8jO0yH3WCWx8UZS0c49eSA4QUmG5caiRJ8fAn58g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/react-loadable": { + "name": "@docusaurus/react-loadable", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-6.0.0.tgz", + "integrity": "sha512-YMMxTUQV/QFSnbgrP3tjDzLHRg7vsbMn8e9HAa8o/1iXoiomo48b7sk/kkmWEuWNDPJVlKSJRB6Y2fHqdJk+SQ==", + "license": "MIT", + "dependencies": { + "@types/react": "*" + }, + "peerDependencies": { + "react": "*" + } + }, + "node_modules/react-loadable-ssr-addon-v5-slorber": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/react-loadable-ssr-addon-v5-slorber/-/react-loadable-ssr-addon-v5-slorber-1.0.3.tgz", + "integrity": "sha512-GXfh9VLwB5ERaCsU6RULh7tkemeX15aNh6wuMEBtfdyMa7fFG8TXrhXlx1SoEK2Ty/l6XIkzzYIQmyaWW3JgdQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.3" + }, + "engines": { + "node": ">=10.13.0" + }, + "peerDependencies": { + "react-loadable": "*", + "webpack": ">=4.41.1 || 5.x" + } + }, + "node_modules/react-router": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.4.tgz", + "integrity": "sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.13", + "history": "^4.9.0", + "hoist-non-react-statics": "^3.1.0", + "loose-envify": "^1.3.1", + "path-to-regexp": "^1.7.0", + "prop-types": "^15.6.2", + "react-is": "^16.6.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + }, + "peerDependencies": { + "react": ">=15" + } + }, + "node_modules/react-router-config": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/react-router-config/-/react-router-config-5.1.1.tgz", + "integrity": "sha512-DuanZjaD8mQp1ppHjgnnUnyOlqYXZVjnov/JzFhjLEwd3Z4dYjMSnqrEzzGThH47vpCOqPPwJM2FtthLeJ8Pbg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.1.2" + }, + "peerDependencies": { + "react": ">=15", + "react-router": ">=5" + } + }, + "node_modules/react-router-dom": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.4.tgz", + "integrity": "sha512-m4EqFMHv/Ih4kpcBCONHbkT68KoAeHN4p3lAGoNryfHi0dMy0kCzEZakiKRsvg5wHZ/JLrLW8o8KomWiz/qbYQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.13", + "history": "^4.9.0", + "loose-envify": "^1.3.1", + "prop-types": "^15.6.2", + "react-router": "5.3.4", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + }, + "peerDependencies": { + "react": ">=15" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/recma-build-jsx": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-build-jsx/-/recma-build-jsx-1.0.0.tgz", + "integrity": "sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-util-build-jsx": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/recma-jsx": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/recma-jsx/-/recma-jsx-1.0.1.tgz", + "integrity": "sha512-huSIy7VU2Z5OLv6oFLosQGGDqPqdO1iq6bWNAdhzMxSJP7RAso4fCZ1cKu8j9YHCZf3TPrq4dw3okhrylgcd7w==", + "license": "MIT", + "dependencies": { + "acorn-jsx": "^5.0.0", + "estree-util-to-js": "^2.0.0", + "recma-parse": "^1.0.0", + "recma-stringify": "^1.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/recma-parse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-parse/-/recma-parse-1.0.0.tgz", + "integrity": "sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "esast-util-from-js": "^2.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/recma-stringify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-stringify/-/recma-stringify-1.0.0.tgz", + "integrity": "sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-util-to-js": "^2.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/reflect-metadata": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", + "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", + "license": "Apache-2.0" + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "license": "MIT" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz", + "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==", + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regexpu-core": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz", + "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==", + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.2.2", + "regjsgen": "^0.8.0", + "regjsparser": "^0.13.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.2.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/registry-auth-token": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.1.1.tgz", + "integrity": "sha512-P7B4+jq8DeD2nMsAcdfaqHbssgHtZ7Z5+++a5ask90fvmJ8p5je4mOa+wzu+DB4vQ5tdJV/xywY+UnVFeQLV5Q==", + "license": "MIT", + "dependencies": { + "@pnpm/npm-conf": "^3.0.2" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/registry-url": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz", + "integrity": "sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==", + "license": "MIT", + "dependencies": { + "rc": "1.2.8" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "license": "MIT" + }, + "node_modules/regjsparser": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.1.tgz", + "integrity": "sha512-dLsljMd9sqwRkby8zhO1gSg3PnJIBFid8f4CQj/sXx+7cKx+E7u0PKhZ+U4wmhx7EfmtvnA318oVaIkAB1lRJw==", + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~3.1.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/rehype-raw": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz", + "integrity": "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-raw": "^9.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-recma": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rehype-recma/-/rehype-recma-1.0.0.tgz", + "integrity": "sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "hast-util-to-estree": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/remark-directive": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/remark-directive/-/remark-directive-3.0.1.tgz", + "integrity": "sha512-gwglrEQEZcZYgVyG1tQuA+h58EZfq5CSULw7J90AFuCTyib1thgHPoqQ+h9iFvU6R+vnZ5oNFQR5QKgGpk741A==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-directive": "^3.0.0", + "micromark-extension-directive": "^3.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-emoji": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/remark-emoji/-/remark-emoji-4.0.1.tgz", + "integrity": "sha512-fHdvsTR1dHkWKev9eNyhTo4EFwbUvJ8ka9SgeWkMPYFX4WoI7ViVBms3PjlQYgw5TLvNQso3GUB/b/8t3yo+dg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.2", + "emoticon": "^4.0.1", + "mdast-util-find-and-replace": "^3.0.1", + "node-emoji": "^2.1.0", + "unified": "^11.0.4" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/remark-frontmatter": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/remark-frontmatter/-/remark-frontmatter-5.0.0.tgz", + "integrity": "sha512-XTFYvNASMe5iPN0719nPrdItC9aU0ssC4v14mH1BCi1u0n1gAocqcujWUrByftZTbLhRtiKRyjYTSIOcr69UVQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-frontmatter": "^2.0.0", + "micromark-extension-frontmatter": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-gfm": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", + "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-gfm": "^3.0.0", + "micromark-extension-gfm": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-mdx": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.1.1.tgz", + "integrity": "sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg==", + "license": "MIT", + "dependencies": { + "mdast-util-mdx": "^3.0.0", + "micromark-extension-mdxjs": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", + "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-stringify": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", + "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-to-markdown": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "license": "MIT", + "dependencies": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + } + }, + "node_modules/renderkid/node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/renderkid/node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "license": "BSD-2-Clause", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-like": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/require-like/-/require-like-0.1.2.tgz", + "integrity": "sha512-oyrU88skkMtDdauHDuKVrgR+zuItqr6/c//FXzvmxRGMexSDc6hNvJInGW3LL46n+8b50RykrvwSUIIQH2LQ5A==", + "engines": { + "node": "*" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "license": "MIT" + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pathname": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", + "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==", + "license": "MIT" + }, + "node_modules/responselike": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", + "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", + "license": "MIT", + "dependencies": { + "lowercase-keys": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rtlcss": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-4.3.0.tgz", + "integrity": "sha512-FI+pHEn7Wc4NqKXMXFM+VAYKEj/mRIcW4h24YVwVtyjI+EqGrLc2Hx/Ny0lrZ21cBWU2goLy36eqMcNj3AQJig==", + "license": "MIT", + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0", + "postcss": "^8.4.21", + "strip-json-comments": "^3.1.1" + }, + "bin": { + "rtlcss": "bin/rtlcss.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/run-applescript": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/sax": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", + "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/schema-dts": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/schema-dts/-/schema-dts-1.1.5.tgz", + "integrity": "sha512-RJr9EaCmsLzBX2NDiO5Z3ux2BVosNZN5jo0gWgsyKvxKIUL5R3swNvoorulAeL9kLB0iTSX7V6aokhla2m7xbg==", + "license": "Apache-2.0" + }, + "node_modules/schema-utils": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", + "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/search-insights": { + "version": "2.17.3", + "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.17.3.tgz", + "integrity": "sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==", + "license": "MIT", + "peer": true + }, + "node_modules/section-matter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", + "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", + "license": "MIT", + "dependencies": { + "extend-shallow": "^2.0.1", + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "license": "MIT" + }, + "node_modules/selfsigned": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-5.5.0.tgz", + "integrity": "sha512-ftnu3TW4+3eBfLRFnDEkzGxSF/10BJBkaLJuBHZX0kiPS7bRdlpZGu6YGt4KngMkdTwJE6MbjavFpqHvqVt+Ew==", + "license": "MIT", + "dependencies": { + "@peculiar/x509": "^1.14.2", + "pkijs": "^3.3.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/semver": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", + "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-4.0.0.tgz", + "integrity": "sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA==", + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/send": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.4.1", + "range-parser": "~1.2.1", + "statuses": "~2.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/send/node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-handler": { + "version": "6.1.7", + "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.7.tgz", + "integrity": "sha512-CinAq1xWb0vR3twAv9evEU8cNWkXCb9kd5ePAHUKJBkOsUpR1wt/CvGdeca7vqumL1U5cSaeVQ6zZMxiJ3yWsg==", + "license": "MIT", + "dependencies": { + "bytes": "3.0.0", + "content-disposition": "0.5.2", + "mime-types": "2.1.18", + "minimatch": "3.1.5", + "path-is-inside": "1.0.2", + "path-to-regexp": "3.3.0", + "range-parser": "1.2.0" + } + }, + "node_modules/serve-handler/node_modules/path-to-regexp": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.3.0.tgz", + "integrity": "sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==", + "license": "MIT" + }, + "node_modules/serve-index": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.2.tgz", + "integrity": "sha512-KDj11HScOaLmrPxl70KYNW1PksP4Nb/CLL2yvC+Qd2kHMPEEpfc4Re2e4FOay+bC/+XQl/7zAcWON3JVo5v3KQ==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.8.0", + "mime-types": "~2.1.35", + "parseurl": "~1.3.3" + }, + "engines": { + "node": ">= 0.8.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "license": "MIT", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "~0.19.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "license": "MIT", + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==", + "license": "MIT" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, + "node_modules/sirv": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz", + "integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==", + "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "license": "MIT" + }, + "node_modules/sitemap": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/sitemap/-/sitemap-7.1.3.tgz", + "integrity": "sha512-tAjEd+wt/YwnEbfNB2ht51ybBJxbEWwe5ki/Z//Wh0rpBFTCUSj46GnxUKEWzhfuJTsee8x3lybHxFgUMig2hw==", + "license": "MIT", + "dependencies": { + "@types/node": "^17.0.5", + "@types/sax": "^1.2.1", + "arg": "^5.0.0", + "sax": "^1.2.4" + }, + "bin": { + "sitemap": "dist/cli.js" + }, + "engines": { + "node": ">=12.0.0", + "npm": ">=5.6.0" + } + }, + "node_modules/sitemap/node_modules/@types/node": { + "version": "17.0.45", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", + "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==", + "license": "MIT" + }, + "node_modules/skin-tone": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/skin-tone/-/skin-tone-2.0.0.tgz", + "integrity": "sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==", + "license": "MIT", + "dependencies": { + "unicode-emoji-modifier-base": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/snake-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", + "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", + "license": "MIT", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "license": "MIT", + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/sort-css-media-queries": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/sort-css-media-queries/-/sort-css-media-queries-2.2.0.tgz", + "integrity": "sha512-0xtkGhWCC9MGt/EzgnvbbbKhqWjl1+/rncmhTh5qCpbYguXh6S/qwePfv/JQ8jePXXmqingylxoC49pCkSPIbA==", + "license": "MIT", + "engines": { + "node": ">= 6.3.0" + } + }, + "node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "license": "MIT", + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "license": "MIT", + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "license": "BSD-3-Clause" + }, + "node_modules/srcset": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/srcset/-/srcset-4.0.0.tgz", + "integrity": "sha512-wvLeHgcVHKO8Sc/H/5lkGreJQVeYMm9rlmt8PuR1xE31rIuXhuzznUUqAt8MqLhB3MqJdFzlNAfpcWnxiFUcPw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "license": "MIT" + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "license": "BSD-2-Clause", + "dependencies": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", + "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/style-to-js": { + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.21.tgz", + "integrity": "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==", + "license": "MIT", + "dependencies": { + "style-to-object": "1.0.14" + } + }, + "node_modules/style-to-object": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.14.tgz", + "integrity": "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==", + "license": "MIT", + "dependencies": { + "inline-style-parser": "0.2.7" + } + }, + "node_modules/stylehacks": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-6.1.1.tgz", + "integrity": "sha512-gSTTEQ670cJNoaeIp9KX6lZmm8LJ3jPB5yJmX8Zq/wQxOsAFXV3qjWzHas3YYk1qesuVIyYWWUpZ0vSE/dTSGg==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "postcss-selector-parser": "^6.0.16" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svg-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==", + "license": "MIT" + }, + "node_modules/svgo": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.3.tgz", + "integrity": "sha512-+wn7I4p7YgJhHs38k2TNjy1vCfPIfLIJWR5MnCStsN8WuuTcBnRKcMHQLMM2ijxGZmDoZwNv8ipl5aTTen62ng==", + "license": "MIT", + "dependencies": { + "commander": "^7.2.0", + "css-select": "^5.1.0", + "css-tree": "^2.3.1", + "css-what": "^6.1.0", + "csso": "^5.0.5", + "picocolors": "^1.0.0", + "sax": "^1.5.0" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" + } + }, + "node_modules/svgo/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/swc-loader": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/swc-loader/-/swc-loader-0.2.7.tgz", + "integrity": "sha512-nwYWw3Fh9ame3Rtm7StS9SBLpHRRnYcK7bnpF3UKZmesAK0gw2/ADvlURFAINmPvKtDLzp+GBiP9yLoEjg6S9w==", + "license": "MIT", + "dependencies": { + "@swc/counter": "^0.1.3" + }, + "peerDependencies": { + "@swc/core": "^1.2.147", + "webpack": ">=2" + } + }, + "node_modules/tapable": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/terser": { + "version": "5.47.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.47.1.tgz", + "integrity": "sha512-tPbLXTI6ohPASb/1YViL428oEHu6/qv1OxqYnfaonVCFHqx4+wCd95pHrQWsL5X4pl90CTyW9piSAsS2L0VoMw==", + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.15.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.6.0.tgz", + "integrity": "sha512-Eum+5ajkaOhf5KbM26osvv21kLD7BaGqQ1UA4Ami4arYwylmGUQTgHFpHDdmJod1q4QXa66p0to/FBKID+J1vA==", + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "jest-worker": "^27.4.5", + "schema-utils": "^4.3.0", + "terser": "^5.31.1" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@minify-html/node": { + "optional": true + }, + "@swc/core": { + "optional": true + }, + "@swc/css": { + "optional": true + }, + "@swc/html": { + "optional": true + }, + "clean-css": { + "optional": true + }, + "cssnano": { + "optional": true + }, + "csso": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "html-minifier-terser": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "postcss": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/terser-webpack-plugin/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, + "node_modules/thingies": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/thingies/-/thingies-2.6.0.tgz", + "integrity": "sha512-rMHRjmlFLM1R96UYPvpmnc3LYtdFrT33JIB7L9hetGue1qAPfn1N2LJeEjxUSidu1Iku+haLZXDuEXUHNGO/lg==", + "license": "MIT", + "engines": { + "node": ">=10.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "^2" + } + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "license": "MIT" + }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "license": "MIT" + }, + "node_modules/tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==", + "license": "MIT" + }, + "node_modules/tinypool": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/tree-dump": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.1.0.tgz", + "integrity": "sha512-rMuvhU4MCDbcbnleZTFezWsaZXRFemSqAM+7jPnzUl1fo9w3YEKOxAeui0fz3OI4EU4hf23iyA7uQRVko+UaBA==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/tsyringe": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/tsyringe/-/tsyringe-4.10.0.tgz", + "integrity": "sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw==", + "license": "MIT", + "dependencies": { + "tslib": "^1.9.3" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/tsyringe/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, + "node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "license": "MIT", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "devOptional": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.25.0.tgz", + "integrity": "sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==", + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, + "node_modules/undici-types": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", + "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", + "license": "MIT" + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-emoji-modifier-base": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unicode-emoji-modifier-base/-/unicode-emoji-modifier-base-1.0.0.tgz", + "integrity": "sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "license": "MIT", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz", + "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz", + "integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unique-string": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz", + "integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==", + "license": "MIT", + "dependencies": { + "crypto-random-string": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position-from-estree": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position-from-estree/-/unist-util-position-from-estree-2.0.0.tgz", + "integrity": "sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz", + "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", + "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/update-notifier": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-6.0.2.tgz", + "integrity": "sha512-EDxhTEVPZZRLWYcJ4ZXjGFN0oP7qYvbXWzEgRm/Yql4dHX5wDbvh89YHP6PK1lzZJYrMtXUuZZz8XGK+U6U1og==", + "license": "BSD-2-Clause", + "dependencies": { + "boxen": "^7.0.0", + "chalk": "^5.0.1", + "configstore": "^6.0.0", + "has-yarn": "^3.0.0", + "import-lazy": "^4.0.0", + "is-ci": "^3.0.1", + "is-installed-globally": "^0.4.0", + "is-npm": "^6.0.0", + "is-yarn-global": "^0.4.0", + "latest-version": "^7.0.0", + "pupa": "^3.1.0", + "semver": "^7.3.7", + "semver-diff": "^4.0.0", + "xdg-basedir": "^5.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/yeoman/update-notifier?sponsor=1" + } + }, + "node_modules/update-notifier/node_modules/boxen": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.1.1.tgz", + "integrity": "sha512-2hCgjEmP8YLWQ130n2FerGv7rYpfBmnmp9Uy2Le1vge6X3gZIfSmEzP5QTDElFxcvVcXlEn8Aq6MU/PZygIOog==", + "license": "MIT", + "dependencies": { + "ansi-align": "^3.0.1", + "camelcase": "^7.0.1", + "chalk": "^5.2.0", + "cli-boxes": "^3.0.0", + "string-width": "^5.1.2", + "type-fest": "^2.13.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/update-notifier/node_modules/camelcase": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz", + "integrity": "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/update-notifier/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-loader": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz", + "integrity": "sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==", + "license": "MIT", + "dependencies": { + "loader-utils": "^2.0.0", + "mime-types": "^2.1.27", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "file-loader": "*", + "webpack": "^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "file-loader": { + "optional": true + } + } + }, + "node_modules/url-loader/node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/url-loader/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/url-loader/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" + }, + "node_modules/url-loader/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/url-loader/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/url-loader/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==", + "license": "MIT" + }, + "node_modules/utility-types": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.11.0.tgz", + "integrity": "sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/value-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", + "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==", + "license": "MIT" + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-location": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.3.tgz", + "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/watchpack": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", + "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==", + "license": "MIT", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "license": "MIT", + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/web-namespaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", + "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/webpack": { + "version": "5.107.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.107.0.tgz", + "integrity": "sha512-PSxeHk/dmLYZlnTU+vL1Gej6Evg5RNtl3flhxBresfznFnzxinHMzHKloHnywM/3ouQv7/AlZCswWDIkNSggUA==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.8", + "@types/json-schema": "^7.0.15", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.16.0", + "acorn-import-phases": "^1.0.3", + "browserslist": "^4.28.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.21.4", + "es-module-lexer": "^2.1.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "loader-runner": "^4.3.2", + "mime-db": "^1.54.0", + "neo-async": "^2.6.2", + "schema-utils": "^4.3.3", + "tapable": "^2.3.0", + "terser-webpack-plugin": "^5.5.0", + "watchpack": "^2.5.1", + "webpack-sources": "^3.4.1" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-bundle-analyzer": { + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.2.tgz", + "integrity": "sha512-vJptkMm9pk5si4Bv922ZbKLV8UTT4zib4FPgXMhgzUny0bfDDkLXAVQs3ly3fS4/TN9ROFtb0NFrm04UXFE/Vw==", + "license": "MIT", + "dependencies": { + "@discoveryjs/json-ext": "0.5.7", + "acorn": "^8.0.4", + "acorn-walk": "^8.0.0", + "commander": "^7.2.0", + "debounce": "^1.2.1", + "escape-string-regexp": "^4.0.0", + "gzip-size": "^6.0.0", + "html-escaper": "^2.0.2", + "opener": "^1.5.2", + "picocolors": "^1.0.0", + "sirv": "^2.0.3", + "ws": "^7.3.1" + }, + "bin": { + "webpack-bundle-analyzer": "lib/bin/analyzer.js" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/webpack-dev-middleware": { + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.4.5.tgz", + "integrity": "sha512-uxQ6YqGdE4hgDKNf7hUiPXOdtkXvBJXrfEGYSx7P7LC8hnUYGK70X6xQXUvXeNyBDDcsiQXpG2m3G9vxowaEuA==", + "license": "MIT", + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^4.43.1", + "mime-types": "^3.0.1", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + } + } + }, + "node_modules/webpack-dev-middleware/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack-dev-middleware/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/webpack-dev-middleware/node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack-dev-server": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.2.4.tgz", + "integrity": "sha512-GqDPGZN9bRqKBTkp4aWkobDDHMsrXKoGSdOH56smIri8qR0JG8gfL8/v/f/OZR3/OKXjG8uwJbFVhKm/FNU/UA==", + "license": "MIT", + "dependencies": { + "@types/bonjour": "^3.5.13", + "@types/connect-history-api-fallback": "^1.5.4", + "@types/express": "^4.17.25", + "@types/express-serve-static-core": "^4.17.21", + "@types/serve-index": "^1.9.4", + "@types/serve-static": "^1.15.5", + "@types/sockjs": "^0.3.36", + "@types/ws": "^8.5.10", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.2.1", + "chokidar": "^3.6.0", + "colorette": "^2.0.10", + "compression": "^1.8.1", + "connect-history-api-fallback": "^2.0.0", + "express": "^4.22.1", + "graceful-fs": "^4.2.6", + "http-proxy-middleware": "^2.0.9", + "ipaddr.js": "^2.1.0", + "launch-editor": "^2.6.1", + "open": "^10.0.3", + "p-retry": "^6.2.0", + "schema-utils": "^4.2.0", + "selfsigned": "^5.5.0", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^7.4.2", + "ws": "^8.18.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/webpack-dev-server/node_modules/open": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", + "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==", + "license": "MIT", + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "wsl-utils": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/webpack-dev-server/node_modules/ws": { + "version": "8.20.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.1.tgz", + "integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/webpack-merge": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz", + "integrity": "sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==", + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.4.1.tgz", + "integrity": "sha512-eACpxRN02yaawnt+uUNIF7Qje6A9zArxBbcAJjK1PK3S9Ycg5jIuJ8pW4q8EMnwNZCEGltcjkRx1QzOxOkKD8A==", + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpackbar": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webpackbar/-/webpackbar-7.0.0.tgz", + "integrity": "sha512-aS9soqSO2iCHgqHoCrj4LbfGQUboDCYJPSFOAchEK+9psIjNrfSWW4Y0YEz67MKURNvMmfo0ycOg9d/+OOf9/Q==", + "license": "MIT", + "dependencies": { + "ansis": "^3.2.0", + "consola": "^3.2.3", + "pretty-time": "^1.1.0", + "std-env": "^3.7.0" + }, + "engines": { + "node": ">=14.21.3" + }, + "peerDependencies": { + "@rspack/core": "*", + "webpack": "3 || 4 || 5" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "license": "Apache-2.0", + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/widest-line": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", + "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", + "license": "MIT", + "dependencies": { + "string-width": "^5.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/wsl-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", + "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==", + "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wsl-utils/node_modules/is-wsl": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/xdg-basedir": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz", + "integrity": "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/xml-js": { + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", + "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", + "license": "MIT", + "dependencies": { + "sax": "^1.2.4" + }, + "bin": { + "xml-js": "bin/cli.js" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz", + "integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==", + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + } +} diff --git a/website/package.json b/website/package.json new file mode 100644 index 0000000000..966ea4b4bd --- /dev/null +++ b/website/package.json @@ -0,0 +1,50 @@ +{ + "name": "website", + "version": "0.0.0", + "private": true, + "scripts": { + "docusaurus": "docusaurus", + "start": "docusaurus start", + "build": "docusaurus build", + "swizzle": "docusaurus swizzle", + "deploy": "docusaurus deploy", + "clear": "docusaurus clear", + "serve": "docusaurus serve", + "write-translations": "docusaurus write-translations", + "write-heading-ids": "docusaurus write-heading-ids", + "typecheck": "tsc" + }, + "dependencies": { + "@docusaurus/core": "3.10.1", + "@docusaurus/faster": "3.10.1", + "@docusaurus/preset-classic": "3.10.1", + "@easyops-cn/docusaurus-search-local": "^0.55.1", + "@mdx-js/react": "^3.0.0", + "clsx": "^2.0.0", + "prism-react-renderer": "^2.3.0", + "react": "^19.0.0", + "react-dom": "^19.0.0" + }, + "devDependencies": { + "@docusaurus/module-type-aliases": "3.10.1", + "@docusaurus/tsconfig": "3.10.1", + "@docusaurus/types": "3.10.1", + "@types/react": "^19.0.0", + "typescript": "~6.0.2" + }, + "browserslist": { + "production": [ + ">0.5%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 3 chrome version", + "last 3 firefox version", + "last 5 safari version" + ] + }, + "engines": { + "node": ">=20.0" + } +} diff --git a/website/sidebars.ts b/website/sidebars.ts new file mode 100644 index 0000000000..d21696f002 --- /dev/null +++ b/website/sidebars.ts @@ -0,0 +1,12 @@ +import type { SidebarsConfig } from '@docusaurus/plugin-content-docs'; + +const sidebars: SidebarsConfig = { + docs: [ + { + type: 'autogenerated', + dirName: '.', + }, + ], +}; + +export default sidebars; diff --git a/website/src/css/custom.css b/website/src/css/custom.css new file mode 100644 index 0000000000..b3ea77ef9e --- /dev/null +++ b/website/src/css/custom.css @@ -0,0 +1,1180 @@ +/* ============================================ + Praxis Design System + Purple-tinted dark theme, Epilogue + Hanken Grotesk + ============================================ */ + +:root { + --praxis-bg-deep: #16161e; + --praxis-bg-surface: #1e1e28; + --praxis-bg-raised: #272733; + --praxis-bg-alt: #121219; + --praxis-border: #2f2f40; + --praxis-border-hover: #3f3f55; + --praxis-text-primary: #ededf0; + --praxis-text-secondary: #8f8fa3; + --praxis-text-muted: #5c5c72; + --praxis-accent: #8b6cc7; + --praxis-accent-hover: #a084d4; + --praxis-accent-subtle: rgba(139, 108, 199, 0.1); + --praxis-font-display: 'Rajdhani', ui-sans-serif, system-ui, sans-serif; + --praxis-font-body: 'Hanken Grotesk', ui-sans-serif, system-ui, sans-serif; + --praxis-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; + + --ifm-color-primary: #8b6cc7; + --ifm-color-primary-dark: #7a58be; + --ifm-color-primary-darker: #6f4ab5; + --ifm-color-primary-darkest: #5b3a99; + --ifm-color-primary-light: #9c80d0; + --ifm-color-primary-lighter: #a88fd6; + --ifm-color-primary-lightest: #c4b3e3; + --ifm-font-family-base: var(--praxis-font-body); + --ifm-font-family-monospace: var(--praxis-font-mono); + --ifm-heading-font-family: var(--praxis-font-display); + --ifm-heading-font-weight: 700; +} + +[data-theme='dark'] { + --ifm-background-color: var(--praxis-bg-deep); + --ifm-background-surface-color: var(--praxis-bg-surface); + --ifm-color-primary: #8b6cc7; + --ifm-color-primary-dark: #7a58be; + --ifm-color-primary-darker: #6f4ab5; + --ifm-color-primary-darkest: #5b3a99; + --ifm-color-primary-light: #9c80d0; + --ifm-color-primary-lighter: #a88fd6; + --ifm-color-primary-lightest: #c4b3e3; + --ifm-font-color-base: var(--praxis-text-primary); + --ifm-font-color-secondary: var(--praxis-text-secondary); + --ifm-link-color: #a084d4; + --ifm-link-hover-color: #c4b3e3; + --ifm-navbar-background-color: var(--praxis-bg-deep); + --ifm-navbar-link-color: var(--praxis-text-secondary); + --ifm-navbar-link-hover-color: var(--praxis-text-primary); + --ifm-footer-background-color: var(--praxis-bg-deep); + --ifm-footer-color: var(--praxis-text-muted); + --ifm-footer-link-color: var(--praxis-text-secondary); + --ifm-footer-link-hover-color: var(--praxis-text-primary); + --ifm-code-background: var(--praxis-bg-surface); + --ifm-code-border-color: var(--praxis-border); + --ifm-hr-border-color: var(--praxis-border); + --ifm-toc-border-color: var(--praxis-border); + --ifm-table-border-color: var(--praxis-border); + --ifm-card-background-color: var(--praxis-bg-surface); + --docusaurus-highlighted-code-line-bg: var(--praxis-bg-raised); +} + +html { + color-scheme: dark; +} + +body { + font-family: var(--praxis-font-body); + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +/* Headings */ +h1, h2, h3, h4, h5, h6 { + font-family: var(--praxis-font-display); + letter-spacing: -0.03em; +} + +h1 { letter-spacing: -0.04em; } + +/* Navbar */ +.navbar { + border-bottom: 1px solid var(--praxis-border); + box-shadow: none; + backdrop-filter: blur(12px); + background: rgba(22, 22, 30, 0.85); + font-family: var(--praxis-font-body); +} + +.navbar__title { + font-family: var(--praxis-font-display); + font-weight: 700; + letter-spacing: -0.03em; + color: var(--praxis-text-primary); + font-size: 1.2rem; +} + +.navbar__link { + font-weight: 500; + font-size: 0.95rem; + letter-spacing: -0.01em; + position: relative; + transition: color 0.15s; +} + +.navbar__link:hover { + color: var(--praxis-accent) !important; +} + +.navbar__link--active { + color: var(--praxis-text-primary) !important; +} + +.navbar__link--active::after { + content: ''; + position: absolute; + bottom: -4px; + left: 50%; + transform: translateX(-50%); + width: 16px; + height: 2px; + background: var(--praxis-accent); + border-radius: 1px; +} + +/* Mobile navbar sidebar */ +.navbar-sidebar { + background: var(--praxis-bg-deep); + height: 100vh !important; +} + +.navbar-sidebar .navbar-sidebar__items { + height: calc(100vh - 60px) !important; +} + +.navbar-sidebar .navbar-sidebar__item { + padding: 0.5rem; +} + +.navbar-sidebar .menu__link { + font-family: var(--praxis-font-body); + font-size: 1rem; + padding: 0.75rem 1rem; + border-radius: 8px; +} + +.navbar-sidebar .navbar-sidebar__back { + font-family: var(--praxis-font-body); +} + +.navbar-sidebar__backdrop { + background: rgba(0, 0, 0, 0.6); +} + +/* ============================================ + Sidebar — OGX-style with icons and pills + ============================================ */ + +.menu { + background-color: var(--praxis-bg-deep); + font-family: var(--praxis-font-body); + padding: 0.5rem 0.75rem; +} + +/* Leaf links — pill-shaped */ +.menu__link { + color: var(--praxis-text-secondary); + font-size: 0.95rem; + font-weight: 450; + border-radius: 100px; + padding: 0.35rem 0.75rem; + transition: all 0.15s; +} + +.menu__link:hover { + color: var(--praxis-text-primary); + background-color: var(--praxis-bg-surface); + text-decoration: none; +} + +.menu__link--active:not(.menu__link--sublist) { + color: var(--praxis-accent); + font-weight: 600; + background: rgba(139, 108, 199, 0.08); +} + +/* Category headers — bolder, rounded, with spacing */ +.menu__list-item-collapsible .menu__link { + border-radius: 0.5rem; + color: var(--praxis-text-primary); + font-size: 0.95rem; + font-weight: 600; + padding: 0.5rem 0.75rem; +} + +/* Space between top-level categories */ +.menu__list > .menu__list-item:not(:first-child) > .menu__list-item-collapsible { + margin-top: 1.25rem; +} + +/* Sidebar icons for each category (Lucide-style SVGs in brand purple) */ +.theme-doc-sidebar-container .menu__list > .menu__list-item > .menu__list-item-collapsible > .menu__link::before { + background-position: 50%; + background-repeat: no-repeat; + background-size: contain; + content: ''; + display: inline-block; + height: 16px; + margin-right: 8px; + opacity: 0.6; + vertical-align: -2px; + width: 16px; +} + +/* 1. Getting Started — Rocket */ +.theme-doc-sidebar-container .menu__list > .menu__list-item:nth-child(1) > .menu__list-item-collapsible > .menu__link::before { + background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='none' stroke='%238b6cc7' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' viewBox='0 0 24 24'%3E%3Cpath d='M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09M12 15l-3-3a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.4 22.4 0 0 1-4 2'/%3E%3Cpath d='M9 12H4s.55-3.03 2-4c1.62-1.08 5 0 5 0M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5'/%3E%3C/svg%3E"); +} + +/* 2. Architecture — Boxes */ +.theme-doc-sidebar-container .menu__list > .menu__list-item:nth-child(2) > .menu__list-item-collapsible > .menu__link::before { + background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='none' stroke='%238b6cc7' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' viewBox='0 0 24 24'%3E%3Cpath d='m16.5 9.4-9-5.19M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16'/%3E%3Cpath d='M3.27 6.96 12 12.01l8.73-5.05M12 22.08V12'/%3E%3C/svg%3E"); +} + +/* 3. Configuration — Settings */ +.theme-doc-sidebar-container .menu__list > .menu__list-item:nth-child(3) > .menu__list-item-collapsible > .menu__link::before { + background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='none' stroke='%238b6cc7' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' viewBox='0 0 24 24'%3E%3Cpath d='M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2'/%3E%3Ccircle cx='12' cy='12' r='3'/%3E%3C/svg%3E"); +} + +/* 4. Filters — Funnel */ +.theme-doc-sidebar-container .menu__list > .menu__list-item:nth-child(4) > .menu__list-item-collapsible > .menu__link::before { + background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='none' stroke='%238b6cc7' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' viewBox='0 0 24 24'%3E%3Cpath d='M10 2v7.527a2 2 0 0 1-.211.896L4.72 20.55a1 1 0 0 0 .9 1.45h12.76a1 1 0 0 0 .9-1.45l-5.069-10.127A2 2 0 0 1 14 9.527V2M8.5 2h7M7 16.5h10'/%3E%3C/svg%3E"); +} + +/* 5. Protocols — Plug */ +.theme-doc-sidebar-container .menu__list > .menu__list-item:nth-child(5) > .menu__list-item-collapsible > .menu__link::before { + background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='none' stroke='%238b6cc7' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' viewBox='0 0 24 24'%3E%3Cpath d='M12 22v-5M9 8V2M15 8V2M18 8v5a6 6 0 0 1-12 0V8z'/%3E%3C/svg%3E"); +} + +/* 6. Security — Shield */ +.theme-doc-sidebar-container .menu__list > .menu__list-item:nth-child(6) > .menu__list-item-collapsible > .menu__link::before { + background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='none' stroke='%238b6cc7' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' viewBox='0 0 24 24'%3E%3Cpath d='M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z'/%3E%3C/svg%3E"); +} + +/* 7. Development — Hammer */ +.theme-doc-sidebar-container .menu__list > .menu__list-item:nth-child(7) > .menu__list-item-collapsible > .menu__link::before { + background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='none' stroke='%238b6cc7' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' viewBox='0 0 24 24'%3E%3Cpath d='m15 12-8.5 8.5c-.83.83-2.17.83-3 0q0 0 0 0a2.12 2.12 0 0 1 0-3L12 9M17.64 15 22 10.64'/%3E%3Cpath d='m20.91 11.7-1.25-1.25c-.6-.6-.93-1.4-.93-2.25V6.5l2-2h-3a5 5 0 0 0-5 5v.5l-2 2h1.7c.85 0 1.65.33 2.25.93l1.25 1.25'/%3E%3C/svg%3E"); +} + +/* Inline code in docs — brand-tinted background (not inside code blocks) */ +.markdown :not(pre) > code { + background: rgba(139, 108, 199, 0.06); + border: 1px solid rgba(139, 108, 199, 0.1); + border-radius: 4px; + padding: 0.1em 0.35em; + font-size: 0.875em; +} + +/* Reset code inside code blocks */ +.theme-code-block code { + background: transparent !important; + border: none !important; + padding: 0 !important; +} + +.theme-code-block .clean-btn { + background: transparent !important; +} + +/* Table of contents — right sidebar */ +.table-of-contents__link { + color: var(--praxis-text-muted); + font-size: 0.8125rem; + transition: color 0.2s cubic-bezier(0.16, 1, 0.3, 1); +} + +.table-of-contents__link--active { + color: var(--praxis-accent); + font-weight: 600; +} + +/* Pagination cards in docs */ +.pagination-nav__sublabel { + font-family: var(--praxis-font-body); + font-size: 0.7rem; + font-weight: 600; + letter-spacing: 0.08em; + text-transform: uppercase; + color: var(--praxis-text-muted); +} + +.pagination-nav__label { + color: var(--praxis-text-primary); +} + +/* Code blocks */ +/* Code blocks — seamless, no double borders */ +.theme-code-block { + background: var(--praxis-bg-surface) !important; + border: 1px solid var(--praxis-border); + border-radius: 0.75rem; + overflow: hidden; + box-shadow: 0 2px 12px rgba(0, 0, 0, 0.15); + margin-bottom: var(--ifm-leading); +} + +.prism-code, +pre[class*='prism'], +pre.prism-code { + background: transparent !important; + background-color: transparent !important; + border: none !important; + border-radius: 0 !important; + font-size: 0.8125rem; + padding: 1.25rem 1.5rem !important; +} + +.theme-code-block pre[style] { + background-color: transparent !important; +} + +div[class*='codeBlockTitle'] { + background: var(--praxis-bg-raised) !important; + border-bottom: 1px solid var(--praxis-border); + color: var(--praxis-text-muted); + font-family: var(--praxis-font-body); + font-size: 0.75rem; + font-weight: 600; + letter-spacing: 0.04em; + padding: 0.5rem 1rem; +} + +div[class*='codeBlockContent'] { + background: transparent !important; +} + +button[class*='copyButton'] { + background: transparent !important; + border: none !important; + color: var(--praxis-text-muted); + transition: color 0.15s; +} + +button[class*='copyButton']:hover { + color: var(--praxis-accent); +} + +/* Search bar — OGX style */ +.navbar .DocSearch-Button, +.navbar [class*='searchBox'] input, +.navbar [class*='searchBar'] input { + background-color: var(--praxis-bg-surface) !important; + border: 1px solid var(--praxis-border) !important; + border-radius: 100px !important; + color: var(--praxis-text-muted) !important; + font-family: var(--praxis-font-body) !important; + font-size: 0.85rem !important; + padding: 0.4rem 1rem !important; + transition: border-color 0.15s !important; + min-width: 200px; +} + +.navbar .DocSearch-Button:hover, +.navbar [class*='searchBox'] input:focus, +.navbar [class*='searchBar'] input:focus { + border-color: var(--praxis-accent) !important; +} + +.navbar .DocSearch-Button-Placeholder, +.navbar [class*='searchBox'] input::placeholder { + color: var(--praxis-text-muted) !important; +} + +.navbar .DocSearch-Search-Icon { + color: var(--praxis-text-muted) !important; + width: 14px !important; + height: 14px !important; +} + +/* Admonitions */ +.alert { + border-color: var(--praxis-border); + background-color: var(--praxis-bg-surface); + border-radius: 8px; +} + +/* Scrollbar */ +::-webkit-scrollbar { + width: 6px; + height: 6px; +} + +::-webkit-scrollbar-track { + background: var(--praxis-bg-deep); +} + +::-webkit-scrollbar-thumb { + background: var(--praxis-border); + border-radius: 3px; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--praxis-border-hover); +} + +/* Footer */ +.footer { + border-top: none; + font-family: var(--praxis-font-body); + padding-top: 0; +} + +.footer--dark { + background: var(--praxis-bg-deep); +} + +.footer::before { + content: ''; + display: block; + max-width: 1100px; + margin: 0 auto 3rem; + height: 1px; + background: linear-gradient(90deg, transparent, var(--praxis-border) 20%, var(--praxis-border) 80%, transparent); +} + +.footer__title { + font-family: var(--praxis-font-body); + font-size: 0.7rem; + font-weight: 600; + letter-spacing: 0.1em; + text-transform: uppercase; + color: var(--praxis-text-secondary); + margin-bottom: 1rem; +} + +.footer__item { + margin-bottom: 0.5rem; +} + +.footer__link-item { + font-size: 0.85rem; + font-weight: 400; + color: var(--praxis-text-muted); + transition: color 0.2s cubic-bezier(0.16, 1, 0.3, 1); +} + +.footer__link-item:hover { + color: var(--praxis-accent); +} + +.footer__bottom { + border-top: 1px solid var(--praxis-border); + margin-top: 2rem; + padding-top: 1.5rem; +} + +.footer__copyright { + font-size: 0.8rem; + color: var(--praxis-text-muted); + font-family: var(--praxis-font-body); +} + +/* Footer responsive: 2x2 grid on tablet */ +@media (max-width: 996px) and (min-width: 641px) { + .footer__links { + display: grid !important; + grid-template-columns: 1fr 1fr; + gap: 2rem; + } +} + +@media (max-width: 640px) { + .footer__links { + display: grid !important; + grid-template-columns: 1fr; + gap: 2rem; + } +} + +/* Pagination */ +.pagination-nav__link { + border-color: var(--praxis-border); + background-color: var(--praxis-bg-surface); + transition: border-color 0.2s cubic-bezier(0.16, 1, 0.3, 1), + transform 0.2s cubic-bezier(0.16, 1, 0.3, 1); +} + +.pagination-nav__link:hover { + border-color: var(--praxis-border-hover); + transform: translateY(-1px); +} + +/* Doc content */ +.markdown h1:first-child { + font-size: 2.25rem; + font-weight: 800; +} + +.markdown h2 { + font-size: 1.5rem; + font-weight: 700; + margin-top: 3rem; +} + +.markdown h3 { + font-size: 1.125rem; + font-weight: 600; + margin-top: 2rem; +} + +.markdown p, +.markdown li { + max-width: 75ch; + line-height: 1.75; +} + +/* Selection */ +::selection { + background: rgba(139, 108, 199, 0.3); + color: var(--praxis-text-primary); +} + +/* Entrance animation for doc pages */ +.theme-doc-markdown { + animation: fadeInUp 0.5s cubic-bezier(0.16, 1, 0.3, 1) both; +} + +@keyframes fadeInUp { + from { + opacity: 0; + transform: translateY(12px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +/* Search */ +.DocSearch-Button { + background-color: var(--praxis-bg-surface) !important; + border: 1px solid var(--praxis-border) !important; + color: var(--praxis-text-muted) !important; + border-radius: 8px !important; + font-family: var(--praxis-font-body) !important; +} + +/* Reduce motion */ +@media (prefers-reduced-motion: reduce) { + .theme-doc-markdown, + .pagination-nav__link, + .menu__link { + animation: none; + transition: none; + } +} + +/* ============================================ + Navbar Accent Line + ============================================ */ +.navbar::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 2px; + background: linear-gradient(90deg, #5b3a99 0%, #8b6cc7 50%, #a084d4 100%); + z-index: 1; +} + +/* ============================================ + Blog — OGX-style (adapted for Praxis purple) + ============================================ */ + +/* Hide sidebars everywhere */ +.blog-list-page aside.col--3, +.blog-post-page .col--2, +.blog-post-page .col--3, +.blog-post-page .table-of-contents, +.blog-post-page .theme-doc-toc-desktop, +.blog-post-page [class*='sidebar'], +.blog-tags-list-page aside.col--3, +.blog-tags-post-list-page aside.col--3 { + display: none !important; +} + +/* Full-width containers */ +.blog-list-page .container, +.blog-post-page .container, +.blog-tags-list-page .container, +.blog-tags-post-list-page .container { + max-width: 100% !important; + padding: 0 !important; +} + +.blog-list-page .row, +.blog-post-page .row, +.blog-tags-list-page .row, +.blog-tags-post-list-page .row { + margin: 0 !important; +} + +/* ---- BLOG LIST PAGE ---- */ + +.blog-list-page main.col, +.blog-list-page main.col--7 { + --ifm-col-width: 100% !important; + flex: 1 !important; + margin: 0 auto !important; + max-width: 1100px !important; + padding: 0 2rem; +} + +.blog-list-page main { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 1.5rem; + align-items: start; + padding-bottom: 2rem; + counter-reset: blog-card 0; +} + +.blog-list-page main > nav, +.blog-list-page main > article:first-of-type { + grid-column: 1 / -1; +} + +/* Hero card (first/latest post) */ +.blog-list-page main > article:first-of-type { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + text-align: center; + min-height: 60vh; + padding: 5rem 3rem 4rem; + margin: -1px -2rem 2rem !important; + max-width: calc(100% + 4rem); + width: calc(100% + 4rem); + background: rgba(255, 255, 255, 0.02); + border: none; + border-radius: 0; + position: relative; + overflow: hidden; + animation: blogCardIn 0.7s ease-out both; +} + +.blog-list-page main > article:first-of-type::before { + content: ''; + position: absolute; + top: 40%; + left: 50%; + transform: translate(-50%, -50%); + width: 800px; + height: 600px; + background: radial-gradient(ellipse, rgba(139, 108, 199, 0.08) 0%, transparent 65%); + pointer-events: none; +} + +.blog-list-page main > article:first-of-type::after { + content: ''; + position: absolute; + bottom: 1.5rem; + left: 50%; + transform: translateX(-50%); + width: 1px; + height: 32px; + background: linear-gradient(to bottom, var(--praxis-accent), transparent); + opacity: 0.35; + animation: blogCardIn 1s ease-out 0.8s both; +} + +.blog-list-page main > article:first-of-type:hover { + background: rgba(255, 255, 255, 0.03); + border-color: transparent; + box-shadow: none; + transform: none; +} + +.blog-list-page main > article:first-of-type header::before { + content: 'LATEST POST'; + display: block; + font-family: var(--praxis-font-mono); + font-size: 0.65rem; + font-weight: 400; + letter-spacing: 0.3em; + color: var(--praxis-accent); + margin-bottom: 2rem; +} + +.blog-list-page main > article:first-of-type header h2 { + font-size: clamp(2rem, 0.5rem + 4.5vw, 3.5rem); + letter-spacing: -0.05em; + line-height: 1.05; + margin-bottom: 1.25rem; + max-width: 850px; + position: relative; +} + +.blog-list-page main > article:first-of-type .markdown { + max-width: 620px; + position: relative; + -webkit-line-clamp: 4; +} + +.blog-list-page main > article:first-of-type .markdown p { + font-size: 1rem; + line-height: 1.7; +} + +.blog-list-page main > article:first-of-type .avatar { + justify-content: center; + position: relative; +} + +.blog-list-page main > article:first-of-type .avatar__photo { + height: 40px; + width: 40px; +} + +.blog-list-page main > article:first-of-type > footer.row { + justify-content: center; + position: relative; + text-align: center; +} + +/* Regular cards */ +.blog-list-page article { + background: rgba(255, 255, 255, 0.03); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 0.75rem; + padding: 2.25rem 2.25rem 2rem; + margin-bottom: 0 !important; + counter-increment: blog-card; + display: flex; + flex-direction: column; + position: relative; + transition: 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94); + animation: blogCardIn 0.5s ease-out both; +} + +/* Card counter watermark */ +.blog-list-page main > article:not(:first-of-type)::after { + content: '0' counter(blog-card); + position: absolute; + top: 1.25rem; + right: 1.5rem; + font-family: var(--praxis-font-display); + font-size: 2.5rem; + font-weight: 800; + line-height: 1; + color: rgba(139, 108, 199, 0.12); + pointer-events: none; + user-select: none; +} + +.blog-list-page article:hover { + background: rgba(255, 255, 255, 0.04); + border-color: rgba(139, 108, 199, 0.45); + box-shadow: 0 12px 40px rgba(0, 0, 0, 0.3); + transform: translateY(-5px); +} + +.blog-list-page main > article:nth-of-type(2) { animation-delay: 0.1s; } +.blog-list-page main > article:nth-of-type(3) { animation-delay: 0.15s; } +.blog-list-page main > article:nth-of-type(4) { animation-delay: 0.2s; } +.blog-list-page main > article:nth-of-type(5) { animation-delay: 0.25s; } +.blog-list-page main > article:nth-of-type(6) { animation-delay: 0.3s; } + +/* Card titles */ +.blog-list-page article header h2 { + font-size: 1.4rem; + letter-spacing: -0.03em; + line-height: 1.18; + margin-bottom: 0.5rem; +} + +.blog-list-page article header h2 a { + color: var(--praxis-text-primary) !important; + text-decoration: none; + transition: color 0.15s; +} + +.blog-list-page article header h2 a:hover { + color: var(--praxis-accent) !important; +} + +/* Card content */ +.blog-list-page article .markdown, +.blog-tags-post-list-page article .markdown { + display: -webkit-box; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; + overflow: hidden; +} + +.blog-list-page article .markdown p { + font-size: 0.875rem; + color: var(--praxis-text-secondary); + line-height: 1.6; + margin-bottom: 0.5rem; +} + +/* Hide images/code in card previews */ +.blog-list-page article .markdown .theme-code-block, +.blog-list-page article .markdown h2, +.blog-list-page article .markdown h3, +.blog-list-page article .markdown img, +.blog-list-page article .markdown pre, +.blog-list-page article .markdown hr { + display: none; +} + +/* Card footer */ +.blog-list-page article > footer.row { + margin-top: auto !important; + padding-top: 1rem; +} + +/* Date/time labels */ +.blog-list-page time, +.blog-tags-post-list-page time { + font-family: var(--praxis-font-mono); + font-size: 0.7rem; + text-transform: uppercase; + letter-spacing: 0.06em; + color: var(--praxis-text-secondary); +} + +/* Avatars */ +.blog-list-page .avatar { + margin-bottom: 0.25rem; +} + +.blog-list-page .avatar__photo { + width: 30px; + height: 30px; + border: 1px solid rgba(255, 255, 255, 0.1); +} + +.blog-list-page .avatar__name { + font-size: 0.8rem; +} + +/* Tags */ +.blog-tags a, +a[class*='tagRegular'] { + border-radius: 100px; + font-size: 0.68rem; + font-weight: 500; + padding: 0.15rem 0.55rem; + transition: 0.15s; +} + +/* Read more link */ +.blog-list-page a[class*='readMore'], +.blog-list-page a[class*='ReadMore'] { + font-family: var(--praxis-font-mono); + font-size: 0.72rem; + font-weight: 500; + letter-spacing: 0.06em; + text-transform: uppercase; + transition: 0.2s; + white-space: nowrap; + text-decoration: none; +} + +.blog-list-page a[class*='readMore']:hover, +.blog-list-page a[class*='ReadMore']:hover { + letter-spacing: 0.12em; + text-decoration: none; +} + +@keyframes blogCardIn { + from { + opacity: 0; + transform: translateY(20px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +/* ---- BLOG POST PAGE (individual article) ---- */ + +.blog-post-page { + scroll-behavior: smooth; +} + +/* Scroll progress bar */ +.blog-post-page::after { + content: ''; + position: fixed; + top: 0; + left: 0; + right: 0; + height: 2px; + background: var(--praxis-accent); + transform: scaleX(0); + transform-origin: left; + z-index: 1001; + animation: linear scrollProgress; + animation-timeline: scroll(); +} + +@keyframes scrollProgress { + to { transform: scaleX(1); } +} + +.blog-post-page main { + --ifm-col-width: 100% !important; + flex: 1 !important; + margin: 0 auto !important; + max-width: 100% !important; + padding: 0 !important; +} + +/* Hero header for blog post */ +.blog-post-page article > header { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + text-align: center; + min-height: 70vh; + padding: 0 2rem; + position: relative; + overflow: hidden; + background: rgba(255, 255, 255, 0.015); + border-bottom: none; + margin-bottom: 0; +} + +.blog-post-page article > header::before { + content: ''; + position: absolute; + top: 40%; + left: 50%; + transform: translate(-50%, -50%); + width: 800px; + height: 600px; + background: radial-gradient(ellipse, rgba(139, 108, 199, 0.08) 0%, transparent 65%); + pointer-events: none; +} + +.blog-post-page article > header::after { + content: ''; + position: absolute; + bottom: 2rem; + left: 50%; + transform: translateX(-50%); + width: 1px; + height: 40px; + background: linear-gradient(to bottom, var(--praxis-accent), transparent); + opacity: 0.4; + animation: blogCardIn 1.5s ease-out 0.8s both; +} + +/* Blog post title */ +.blog-post-page article header h1 { + font-size: clamp(2.5rem, 0.5rem + 5.5vw, 4.5rem); + font-weight: 700; + letter-spacing: -0.055em; + line-height: 1.02; + margin-bottom: 1.75rem; + max-width: 900px; + position: relative; + animation: blogCardIn 0.8s ease-out both; +} + +/* Post meta */ +.blog-post-page .margin-top--md { + animation: blogCardIn 0.8s ease-out 0.15s both; + margin-top: 1rem !important; +} + +.blog-post-page .margin-vert--md span, +.blog-post-page .margin-vert--md time { + font-family: var(--praxis-font-mono); + font-size: 0.68rem; + font-weight: 400; + letter-spacing: 0.14em; + text-transform: uppercase; + color: var(--praxis-text-secondary); +} + +/* Post author avatar */ +.blog-post-page article > header .avatar { + animation: blogCardIn 0.8s ease-out 0.3s both; + justify-content: center; + padding: 0.5rem 0 0; +} + +.blog-post-page .avatar__photo { + width: 44px; + height: 44px; + border: 2px solid rgba(255, 255, 255, 0.1); +} + +.blog-post-page .avatar__name { + font-size: 0.9rem; + font-weight: 600; +} + +/* Post content area */ +.blog-post-page article > .markdown { + animation: blogCardIn 0.6s ease-out 0.5s both; + margin: 0 auto; + max-width: 960px; + padding: 3.5rem 2rem 0; +} + +.blog-post-page .markdown { + font-size: 1.0625rem; + line-height: 1.9; + counter-reset: blog-section; +} + +.blog-post-page .markdown > p { + margin-bottom: 1.5rem; +} + +/* Drop cap on first paragraph */ +.blog-post-page .markdown > p:first-of-type { + font-size: 1.2rem; + line-height: 1.8; +} + +.blog-post-page .markdown > p:first-of-type::first-letter { + float: left; + font-family: var(--praxis-font-display); + font-size: 4.5em; + font-weight: 700; + line-height: 0.75; + margin-top: 0.02em; + padding-right: 0.08em; + color: var(--praxis-accent); +} + +/* Post links */ +.blog-post-page .markdown a:not(.hash-link) { + text-decoration-line: underline; + text-decoration-color: rgba(139, 108, 199, 0.3); + text-decoration-thickness: 1px; + text-underline-offset: 3px; + transition: text-decoration-color 0.2s; +} + +.blog-post-page .markdown a:not(.hash-link):hover { + text-decoration-color: var(--praxis-accent); +} + +/* Section headings with counter watermark */ +.blog-post-page .markdown h2 { + border-top: 1px solid rgba(255, 255, 255, 0.04); + border-bottom: none; + counter-increment: blog-section; + font-size: 1.85rem; + letter-spacing: -0.03em; + margin-top: 5rem; + margin-bottom: 1.25rem; + padding-top: 3.5rem; + padding-bottom: 0; + position: relative; + overflow: visible; +} + +.blog-post-page .markdown h2::before { + content: '0' counter(blog-section); + display: block; + font-family: var(--praxis-font-display); + font-size: 5rem; + font-weight: 800; + letter-spacing: -0.04em; + line-height: 0.85; + margin-bottom: 0.25rem; + color: rgba(139, 108, 199, 0.07); + pointer-events: none; + user-select: none; +} + +.blog-post-page .markdown > h2:first-of-type { + border-top: none; + margin-top: 3rem; + padding-top: 1rem; +} + +/* Hash link visibility */ +.blog-post-page .markdown .hash-link { + opacity: 0; + transition: opacity 0.15s; +} + +.blog-post-page .markdown h2:hover .hash-link, +.blog-post-page .markdown h3:hover .hash-link { + opacity: 0.4; +} + +/* Post footer */ +.blog-post-page article > footer { + border-top-color: rgba(255, 255, 255, 0.06); + max-width: 960px; + margin: 3rem auto 0; + padding: 0 2rem; +} + +/* Images in posts */ +.blog-post-page .markdown img { + border: 1px solid rgba(255, 255, 255, 0.06); + border-radius: 0.75rem; +} + +/* Blockquotes */ +.blog-post-page .markdown blockquote { + background: rgba(139, 108, 199, 0.04); +} + +/* ---- RESPONSIVE ---- */ + +@media (max-width: 768px) { + .blog-list-page main { + grid-template-columns: 1fr; + } + + .blog-list-page main > article:first-of-type { + min-height: 40vh; + padding: 3rem 1.5rem 2.5rem; + margin: 0 -2rem 1.5rem !important; + } + + .blog-list-page main > article:first-of-type header h2 { + font-size: 1.75rem; + } + + .blog-post-page article > header { + min-height: 50vh; + } + + .blog-post-page article header h1 { + font-size: 2rem; + } + + .blog-post-page article > .markdown { + padding: 2rem 1rem 0; + } +} + +/* Tables — editorial treatment */ +table { + border-collapse: separate; + border-spacing: 0; + border-radius: 0.75rem; + overflow: hidden; +} + +table th { + font-family: var(--praxis-font-mono); + font-size: 0.7rem; + text-transform: uppercase; + letter-spacing: 0.08em; + font-weight: 600; + background: var(--praxis-bg-raised); +} + +@media (max-width: 640px) { + [class*='blog-list-page'] article, + [class*='blogListPage'] article { + padding: 20px; + } + + [class*='blog-list-page'] article h2, + [class*='blogListPage'] article h2 { + font-size: 1.25rem; + } +} diff --git a/website/src/data/examples.ts b/website/src/data/examples.ts new file mode 100644 index 0000000000..6b3692e08d --- /dev/null +++ b/website/src/data/examples.ts @@ -0,0 +1,619 @@ +export interface Example { + name: string; + description: string; + category: string; + path: string; + filename: string; +} + +export const categories = [ + 'All', + 'Traffic Management', + 'AI / Inference', + 'Security', + 'Protocols', + 'Payload Processing', + 'Observability', + 'Transformation', + 'Pipeline', + 'Branching', + 'Operations', +] as const; + +export type Category = (typeof categories)[number]; + +export const examples: Example[] = [ + // Traffic Management + { + name: 'Basic Reverse Proxy', + description: 'Minimal single-listener, single-cluster proxy', + category: 'Traffic Management', + path: 'examples/configs/traffic-management/basic-reverse-proxy.yaml', + filename: 'basic-reverse-proxy.yaml', + }, + { + name: 'Path-Based Routing', + description: 'Route by URL path prefix to separate clusters', + category: 'Traffic Management', + path: 'examples/configs/traffic-management/path-based-routing.yaml', + filename: 'path-based-routing.yaml', + }, + { + name: 'Host-Based Routing', + description: 'Route by Host header; one listener, multiple domains', + category: 'Traffic Management', + path: 'examples/configs/traffic-management/hosts.yaml', + filename: 'hosts.yaml', + }, + { + name: 'Canary Routing', + description: 'Weighted traffic split for canary deployments', + category: 'Traffic Management', + path: 'examples/configs/traffic-management/canary-routing.yaml', + filename: 'canary-routing.yaml', + }, + { + name: 'Circuit Breaker', + description: 'Per-cluster circuit breaker with closed/open/half-open states', + category: 'Traffic Management', + path: 'examples/configs/traffic-management/circuit-breaker.yaml', + filename: 'circuit-breaker.yaml', + }, + { + name: 'Round Robin', + description: 'Default strategy: even distribution across backends', + category: 'Traffic Management', + path: 'examples/configs/traffic-management/round-robin.yaml', + filename: 'round-robin.yaml', + }, + { + name: 'Weighted Load Balancing', + description: 'Proportional traffic split via per-endpoint weights', + category: 'Traffic Management', + path: 'examples/configs/traffic-management/weighted-load-balancing.yaml', + filename: 'weighted-load-balancing.yaml', + }, + { + name: 'Least Connections', + description: 'Route to backend with fewest in-flight requests', + category: 'Traffic Management', + path: 'examples/configs/traffic-management/least-connections.yaml', + filename: 'least-connections.yaml', + }, + { + name: 'Session Affinity', + description: 'consistent_hash to pin a user to one backend', + category: 'Traffic Management', + path: 'examples/configs/traffic-management/session-affinity.yaml', + filename: 'session-affinity.yaml', + }, + { + name: 'Health Checks', + description: 'Active HTTP and TCP health check probes per cluster', + category: 'Traffic Management', + path: 'examples/configs/traffic-management/health-checks.yaml', + filename: 'health-checks.yaml', + }, + { + name: 'Timeout', + description: '504 when upstream exceeds a latency SLA', + category: 'Traffic Management', + path: 'examples/configs/traffic-management/timeout.yaml', + filename: 'timeout.yaml', + }, + { + name: 'Rate Limiting', + description: 'Token bucket rate limiter with per-IP and global modes', + category: 'Traffic Management', + path: 'examples/configs/traffic-management/rate-limiting.yaml', + filename: 'rate-limiting.yaml', + }, + { + name: 'Static Response', + description: 'Fixed response without upstream', + category: 'Traffic Management', + path: 'examples/configs/traffic-management/static-response.yaml', + filename: 'static-response.yaml', + }, + { + name: 'Redirect', + description: '3xx redirects with path/query template substitution', + category: 'Traffic Management', + path: 'examples/configs/traffic-management/redirect.yaml', + filename: 'redirect.yaml', + }, + { + name: 'Hostname Upstream', + description: 'Resolve hostname upstream endpoints such as localhost:9000', + category: 'Traffic Management', + path: 'examples/configs/traffic-management/hostname-upstream.yaml', + filename: 'hostname-upstream.yaml', + }, + + // Payload Processing + { + name: 'AI Inference Body-Based Routing', + description: 'Route LLM requests by model field in JSON body', + category: 'Payload Processing', + path: 'examples/configs/payload-processing/ai-inference-body-based-routing.yaml', + filename: 'ai-inference-body-based-routing.yaml', + }, + { + name: 'JSON-RPC Routing', + description: 'Route JSON-RPC 2.0 requests by method for MCP and A2A protocols', + category: 'Payload Processing', + path: 'examples/configs/payload-processing/json-rpc-routing.yaml', + filename: 'json-rpc-routing.yaml', + }, + { + name: 'MCP Classifier Routing', + description: 'Route MCP requests by body-derived method and tool name', + category: 'Payload Processing', + path: 'examples/configs/payload-processing/mcp-classifier-routing.yaml', + filename: 'mcp-classifier-routing.yaml', + }, + { + name: 'Stream Buffer', + description: 'Stream-buffered body inspection before forwarding', + category: 'Payload Processing', + path: 'examples/configs/payload-processing/stream-buffer.yaml', + filename: 'stream-buffer.yaml', + }, + { + name: 'Compression', + description: 'Gzip, brotli, and zstd response compression', + category: 'Payload Processing', + path: 'examples/configs/payload-processing/compression.yaml', + filename: 'compression.yaml', + }, + { + name: 'Multi-Field Extraction', + description: 'Extract multiple JSON fields into headers in one pass', + category: 'Payload Processing', + path: 'examples/configs/payload-processing/multi-field-extraction.yaml', + filename: 'multi-field-extraction.yaml', + }, + { + name: 'Conditional Field Extraction', + description: 'Apply json_body_field only on matching request paths', + category: 'Payload Processing', + path: 'examples/configs/payload-processing/conditional-field-extraction.yaml', + filename: 'conditional-field-extraction.yaml', + }, + { + name: 'Field Extraction Access Control', + description: 'Extract tenant_id from body for header-based routing', + category: 'Payload Processing', + path: 'examples/configs/payload-processing/field-extraction-access-control.yaml', + filename: 'field-extraction-access-control.yaml', + }, + { + name: 'Body Size Limit with Extraction', + description: 'Global body size ceiling with json_body_field extraction', + category: 'Payload Processing', + path: 'examples/configs/payload-processing/body-size-limit-with-extraction.yaml', + filename: 'body-size-limit-with-extraction.yaml', + }, + { + name: 'Multi-Listener Body Pipeline', + description: 'Three listeners with different body processing strategies', + category: 'Payload Processing', + path: 'examples/configs/payload-processing/multi-listener-body-pipeline.yaml', + filename: 'multi-listener-body-pipeline.yaml', + }, + + // Security + { + name: 'CSRF Protection', + description: 'CSRF protection via origin validation', + category: 'Security', + path: 'examples/configs/security/csrf.yaml', + filename: 'csrf.yaml', + }, + { + name: 'Forwarded Headers', + description: 'X-Forwarded-For/Proto/Host with trusted proxies', + category: 'Security', + path: 'examples/configs/security/forwarded-headers.yaml', + filename: 'forwarded-headers.yaml', + }, + { + name: 'Guardrails', + description: 'Reject requests matching header or body string/regex rules', + category: 'Security', + path: 'examples/configs/security/guardrails.yaml', + filename: 'guardrails.yaml', + }, + { + name: 'IP ACL', + description: 'Allow or deny by source IP/CIDR', + category: 'Security', + path: 'examples/configs/security/ip-acl.yaml', + filename: 'ip-acl.yaml', + }, + { + name: 'Downstream Read Timeout', + description: 'Protect against slow client attacks with read timeouts', + category: 'Security', + path: 'examples/configs/security/downstream-read-timeout.yaml', + filename: 'downstream-read-timeout.yaml', + }, + { + name: 'CORS', + description: 'CORS preflight handling with origin validation', + category: 'Security', + path: 'examples/configs/security/cors.yaml', + filename: 'cors.yaml', + }, + + // Observability + { + name: 'Access Logging', + description: 'Access log with sampling', + category: 'Observability', + path: 'examples/configs/observability/access-logging.yaml', + filename: 'access-logging.yaml', + }, + { + name: 'Request ID and Logging', + description: 'request_id + access_log: correlation IDs and structured logs', + category: 'Observability', + path: 'examples/configs/observability/logging.yaml', + filename: 'logging.yaml', + }, + { + name: 'TCP Access Log', + description: 'Structured JSON TCP connection logging', + category: 'Observability', + path: 'examples/configs/observability/tcp-access-log.yaml', + filename: 'tcp-access-log.yaml', + }, + + // Transformation + { + name: 'Header Manipulation', + description: 'Add, overwrite, and remove request/response headers', + category: 'Transformation', + path: 'examples/configs/transformation/header-manipulation.yaml', + filename: 'header-manipulation.yaml', + }, + { + name: 'Path Rewriting', + description: 'Strip prefix, add prefix, or regex replace on request paths', + category: 'Transformation', + path: 'examples/configs/transformation/path-rewriting.yaml', + filename: 'path-rewriting.yaml', + }, + { + name: 'URL Rewriting', + description: 'Regex path transformation and query string manipulation', + category: 'Transformation', + path: 'examples/configs/transformation/url-rewriting.yaml', + filename: 'url-rewriting.yaml', + }, + + // Protocols + { + name: 'TCP Proxy', + description: 'L4 bidirectional TCP forwarding', + category: 'Protocols', + path: 'examples/configs/protocols/tcp-proxy.yaml', + filename: 'tcp-proxy.yaml', + }, + { + name: 'TCP Timeouts', + description: 'TCP proxy with idle and max duration timeouts', + category: 'Protocols', + path: 'examples/configs/protocols/tcp-timeouts.yaml', + filename: 'tcp-timeouts.yaml', + }, + { + name: 'TCP Consistent Hash', + description: 'TCP load balancing with consistent-hash client IP affinity', + category: 'Protocols', + path: 'examples/configs/protocols/tcp-consistent-hash.yaml', + filename: 'tcp-consistent-hash.yaml', + }, + { + name: 'TCP Least Connections', + description: 'TCP load balancing via least-connections strategy', + category: 'Protocols', + path: 'examples/configs/protocols/tcp-least-connections.yaml', + filename: 'tcp-least-connections.yaml', + }, + { + name: 'TCP Round Robin', + description: 'TCP round-robin load balancing across replicas', + category: 'Protocols', + path: 'examples/configs/protocols/tcp-round-robin.yaml', + filename: 'tcp-round-robin.yaml', + }, + { + name: 'Mixed Protocol', + description: 'HTTP + TCP listeners on one server', + category: 'Protocols', + path: 'examples/configs/protocols/mixed-protocol.yaml', + filename: 'mixed-protocol.yaml', + }, + { + name: 'TLS Termination', + description: 'HTTPS listener; plain HTTP to backends', + category: 'Protocols', + path: 'examples/configs/protocols/tls-termination.yaml', + filename: 'tls-termination.yaml', + }, + { + name: 'TLS Cipher Suites', + description: 'Restrict accepted TLS cipher suites per listener', + category: 'Protocols', + path: 'examples/configs/protocols/tls-cipher-suites.yaml', + filename: 'tls-cipher-suites.yaml', + }, + { + name: 'TLS SNI Routing', + description: 'Route TLS connections by SNI hostname without termination', + category: 'Protocols', + path: 'examples/configs/protocols/tls-sni-routing.yaml', + filename: 'tls-sni-routing.yaml', + }, + { + name: 'TCP TLS mTLS', + description: 'TCP proxy with mutual TLS', + category: 'Protocols', + path: 'examples/configs/protocols/tcp-tls-mtls.yaml', + filename: 'tcp-tls-mtls.yaml', + }, + { + name: 'TCP TLS Termination', + description: 'TCP proxy with TLS termination', + category: 'Protocols', + path: 'examples/configs/protocols/tcp-tls-termination.yaml', + filename: 'tcp-tls-termination.yaml', + }, + { + name: 'TLS HTTP Re-encrypt', + description: 'TLS termination with re-encryption to upstream', + category: 'Protocols', + path: 'examples/configs/protocols/tls-http-reencrypt.yaml', + filename: 'tls-http-reencrypt.yaml', + }, + { + name: 'TLS mTLS Both', + description: 'mTLS on both listener and upstream', + category: 'Protocols', + path: 'examples/configs/protocols/tls-mtls-both.yaml', + filename: 'tls-mtls-both.yaml', + }, + { + name: 'TLS mTLS Listener', + description: 'mTLS on listener (require client cert)', + category: 'Protocols', + path: 'examples/configs/protocols/tls-mtls-listener.yaml', + filename: 'tls-mtls-listener.yaml', + }, + { + name: 'TLS mTLS Listener Request', + description: 'mTLS on listener (request client cert)', + category: 'Protocols', + path: 'examples/configs/protocols/tls-mtls-listener-request.yaml', + filename: 'tls-mtls-listener-request.yaml', + }, + { + name: 'TLS mTLS Upstream', + description: 'mTLS to upstream (client cert)', + category: 'Protocols', + path: 'examples/configs/protocols/tls-mtls-upstream.yaml', + filename: 'tls-mtls-upstream.yaml', + }, + { + name: 'TLS Multi-Certificate', + description: 'SNI-based multi-certificate selection', + category: 'Protocols', + path: 'examples/configs/protocols/tls-multi-cert.yaml', + filename: 'tls-multi-cert.yaml', + }, + { + name: 'TLS Verify Disabled', + description: 'Upstream TLS with verification disabled', + category: 'Protocols', + path: 'examples/configs/protocols/tls-verify-disabled.yaml', + filename: 'tls-verify-disabled.yaml', + }, + { + name: 'TLS Version Constraint', + description: 'Minimum TLS version constraint', + category: 'Protocols', + path: 'examples/configs/protocols/tls-version-constraint.yaml', + filename: 'tls-version-constraint.yaml', + }, + { + name: 'Upstream CA File', + description: 'Global upstream CA file reference', + category: 'Protocols', + path: 'examples/configs/protocols/upstream-ca-file.yaml', + filename: 'upstream-ca-file.yaml', + }, + { + name: 'Upstream TLS', + description: 'Plain HTTP listener; TLS to upstream with SNI', + category: 'Protocols', + path: 'examples/configs/protocols/upstream-tls.yaml', + filename: 'upstream-tls.yaml', + }, + { + name: 'WebSocket', + description: 'Transparent WebSocket upgrade proxying over HTTP', + category: 'Protocols', + path: 'examples/configs/protocols/websocket.yaml', + filename: 'websocket.yaml', + }, + + // Pipeline + { + name: 'Default Config', + description: 'Built-in default config (static JSON on /)', + category: 'Pipeline', + path: 'core/src/config/default.yaml', + filename: 'default.yaml', + }, + { + name: 'Composed Chains', + description: 'Multiple named chains composed per listener', + category: 'Pipeline', + path: 'examples/configs/pipeline/composed-chains.yaml', + filename: 'composed-chains.yaml', + }, + { + name: 'Conditional Filters', + description: 'when/unless conditions on request and response phase', + category: 'Pipeline', + path: 'examples/configs/pipeline/conditional-filters.yaml', + filename: 'conditional-filters.yaml', + }, + { + name: 'Branch Chains', + description: 'All branch chain scenarios in one config (six patterns)', + category: 'Pipeline', + path: 'examples/configs/pipeline/branch-chains.yaml', + filename: 'branch-chains.yaml', + }, + { + name: 'Failure Mode', + description: 'Failure mode behavior (open continues, closed rejects on error)', + category: 'Pipeline', + path: 'examples/configs/pipeline/failure-mode.yaml', + filename: 'failure-mode.yaml', + }, + + // AI / Inference + { + name: 'Credential Injection', + description: 'Inject per-cluster API credentials and strip client tokens', + category: 'AI / Inference', + path: 'examples/configs/ai/credential-injection.yaml', + filename: 'credential-injection.yaml', + }, + { + name: 'Model-to-Header Routing', + description: 'Route by model field in JSON body via X-Model header', + category: 'AI / Inference', + path: 'examples/configs/ai/model-to-header-routing.yaml', + filename: 'model-to-header-routing.yaml', + }, + { + name: 'Prompt Enrichment', + description: 'Inject system messages into chat completion requests', + category: 'AI / Inference', + path: 'examples/configs/ai/prompt-enrichment.yaml', + filename: 'prompt-enrichment.yaml', + }, + + // Branching + { + name: 'Unconditional Branch', + description: 'Always-fire branch for injecting side-effect chains', + category: 'Branching', + path: 'examples/configs/branching/unconditional-branch.yaml', + filename: 'unconditional-branch.yaml', + }, + { + name: 'Conditional Terminal', + description: 'Short-circuit the pipeline with a static response on result match', + category: 'Branching', + path: 'examples/configs/branching/conditional-terminal.yaml', + filename: 'conditional-terminal.yaml', + }, + { + name: 'Conditional Skip-To', + description: 'Skip filters by jumping to a named rejoin point on result match', + category: 'Branching', + path: 'examples/configs/branching/conditional-skip-to.yaml', + filename: 'conditional-skip-to.yaml', + }, + { + name: 'Multiple Branches', + description: 'Multiple branches on one filter with first-match-wins evaluation', + category: 'Branching', + path: 'examples/configs/branching/multiple-branches.yaml', + filename: 'multiple-branches.yaml', + }, + { + name: 'Named Chain Ref', + description: 'Reference a top-level chain by name instead of inline definition', + category: 'Branching', + path: 'examples/configs/branching/named-chain-ref.yaml', + filename: 'named-chain-ref.yaml', + }, + { + name: 'Nested Branches', + description: 'Multi-level decision tree with branches inside branches', + category: 'Branching', + path: 'examples/configs/branching/nested-branches.yaml', + filename: 'nested-branches.yaml', + }, + { + name: 'Reentrance', + description: 'Loop back to a named filter with max_iterations cap', + category: 'Branching', + path: 'examples/configs/branching/reentrance.yaml', + filename: 'reentrance.yaml', + }, + { + name: 'Cross-Chain Flat', + description: 'Branch across concatenated chains via flat pipeline name index', + category: 'Branching', + path: 'examples/configs/branching/cross-chain-flat.yaml', + filename: 'cross-chain-flat.yaml', + }, + + // Operations + { + name: 'Production Gateway', + description: 'Full production setup with composed chains', + category: 'Operations', + path: 'examples/configs/operations/production-gateway.yaml', + filename: 'production-gateway.yaml', + }, + { + name: 'Multi-Listener', + description: 'Multiple listeners sharing a filter chain', + category: 'Operations', + path: 'examples/configs/operations/multi-listener.yaml', + filename: 'multi-listener.yaml', + }, + { + name: 'Hot Reload', + description: 'Dynamic config reload without restart', + category: 'Operations', + path: 'examples/configs/operations/hot-reload.yaml', + filename: 'hot-reload.yaml', + }, + { + name: 'Admin Interface', + description: 'Admin interface with health endpoints', + category: 'Operations', + path: 'examples/configs/operations/admin-interface.yaml', + filename: 'admin-interface.yaml', + }, + { + name: 'Container Default', + description: 'Default containerized deployment with public binding', + category: 'Operations', + path: 'examples/configs/operations/container-default.yaml', + filename: 'container-default.yaml', + }, + { + name: 'Max Connections', + description: 'Per-listener connection limit with 503 rejection', + category: 'Operations', + path: 'examples/configs/operations/max-connections.yaml', + filename: 'max-connections.yaml', + }, + { + name: 'Log Overrides', + description: 'Per-module log level tuning via runtime config', + category: 'Operations', + path: 'examples/configs/operations/log-overrides.yaml', + filename: 'log-overrides.yaml', + }, +]; diff --git a/website/src/pages/examples/index.module.css b/website/src/pages/examples/index.module.css new file mode 100644 index 0000000000..99fec7fe03 --- /dev/null +++ b/website/src/pages/examples/index.module.css @@ -0,0 +1,277 @@ +.container { + max-width: 1100px; + margin: 0 auto; + padding: 64px 24px; +} + +.title { + font-family: var(--praxis-font-display); + font-size: 2.25rem; + font-weight: 800; + letter-spacing: -0.04em; + color: var(--praxis-text-primary); + margin-bottom: 8px; +} + +.subtitle { + color: var(--praxis-text-muted); + font-family: var(--praxis-font-body); + font-size: 1rem; + margin-bottom: 40px; + line-height: 1.6; +} + +.tabs { + display: flex; + flex-wrap: wrap; + gap: 8px; + margin-bottom: 32px; + border-bottom: 1px solid var(--praxis-border); + padding-bottom: 16px; +} + +.tab { + background: none; + border: 1px solid var(--praxis-border); + border-radius: 6px; + color: var(--praxis-text-muted); + padding: 8px 16px; + font-size: 0.8rem; + font-family: var(--praxis-font-body); + font-weight: 500; + cursor: pointer; + transition: all 0.25s cubic-bezier(0.16, 1, 0.3, 1); +} + +.tab:hover { + border-color: var(--praxis-border-hover); + color: var(--praxis-text-secondary); +} + +.tabActive { + background: var(--praxis-accent); + color: var(--praxis-text-primary); + border-color: var(--praxis-accent); +} + +.tabActive:hover { + background: var(--praxis-accent-hover); + border-color: var(--praxis-accent-hover); +} + +.grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); + gap: 12px; +} + +.card { + background: var(--praxis-bg-surface); + border: 1px solid var(--praxis-border); + border-radius: 10px; + padding: 20px; + cursor: pointer; + text-align: left; + font: inherit; + transition: border-color 0.2s cubic-bezier(0.16, 1, 0.3, 1); +} + +.card:hover { + border-color: var(--praxis-border-hover); +} + +.card:focus-visible { + outline: 2px solid var(--praxis-accent); + outline-offset: 2px; +} + +.cardSelected { + border-color: var(--praxis-accent); +} + +.cardHeader { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 6px; + gap: 12px; +} + +.cardName { + font-family: var(--praxis-font-display); + font-size: 0.95rem; + font-weight: 600; + color: var(--praxis-text-primary); + letter-spacing: -0.02em; +} + +.badge { + font-size: 0.675rem; + font-family: var(--praxis-font-body); + font-weight: 500; + color: var(--praxis-text-muted); + background: var(--praxis-bg-deep); + border: 1px solid var(--praxis-border); + border-radius: 4px; + padding: 2px 8px; + white-space: nowrap; +} + +.cardDesc { + font-family: var(--praxis-font-body); + font-size: 0.8rem; + color: var(--praxis-text-muted); + line-height: 1.5; + margin: 0; +} + +.count { + color: var(--praxis-text-muted); + font-family: var(--praxis-font-body); + font-size: 0.85rem; + margin-bottom: 24px; +} + +/* Overlay that pops in */ +.overlay { + position: fixed; + inset: 0; + z-index: 200; + background: rgba(0, 0, 0, 0.6); + display: flex; + align-items: center; + justify-content: center; + padding: 48px 24px; + animation: overlayIn 0.2s ease-out; +} + +@keyframes overlayIn { + from { opacity: 0; } + to { opacity: 1; } +} + +@keyframes panelIn { + from { opacity: 0; transform: scale(0.97) translateY(8px); } + to { opacity: 1; transform: scale(1) translateY(0); } +} + +.overlayPanel { + background: var(--praxis-bg-surface); + border: 1px solid var(--praxis-border); + border-radius: 14px; + width: 100%; + max-width: 800px; + max-height: 80vh; + display: flex; + flex-direction: column; + overflow: hidden; + animation: panelIn 0.25s cubic-bezier(0.16, 1, 0.3, 1); +} + +.overlayHeader { + display: flex; + align-items: center; + justify-content: space-between; + padding: 16px 24px; + border-bottom: 1px solid var(--praxis-border); + gap: 16px; + flex-shrink: 0; +} + +.overlayName { + font-family: var(--praxis-font-display); + font-size: 1.1rem; + font-weight: 700; + color: var(--praxis-text-primary); + margin-right: 12px; +} + +.overlayBadge { + font-size: 0.675rem; + font-family: var(--praxis-font-body); + font-weight: 500; + color: var(--praxis-text-muted); + background: var(--praxis-bg-raised); + border: 1px solid var(--praxis-border); + border-radius: 4px; + padding: 2px 8px; +} + +.overlayActions { + display: flex; + align-items: center; + gap: 8px; +} + +.overlayBtn { + background: none; + border: 1px solid var(--praxis-border); + border-radius: 6px; + color: var(--praxis-text-muted); + padding: 6px 14px; + font-size: 0.75rem; + font-family: var(--praxis-font-body); + cursor: pointer; + transition: all 0.15s; + text-decoration: none; +} + +.overlayBtn:hover { + border-color: var(--praxis-accent); + color: var(--praxis-accent); + text-decoration: none; +} + +.overlayClose { + background: none; + border: none; + font-size: 1.25rem; + padding: 4px 10px; + color: var(--praxis-text-muted); + cursor: pointer; + transition: color 0.15s; +} + +.overlayClose:hover { + color: var(--praxis-text-primary); +} + +.overlayBody { + padding: 24px; + overflow: auto; + flex: 1; +} + +.overlayBody pre { + margin: 0; + font-size: 0.875rem; + line-height: 1.7; + color: var(--praxis-text-secondary); + font-family: var(--praxis-font-mono); + white-space: pre; +} + +.overlayLoading { + color: var(--praxis-text-muted); + font-family: var(--praxis-font-body); + font-size: 0.85rem; +} + +@media (max-width: 640px) { + .grid { + grid-template-columns: 1fr; + } + + .overlay { + padding: 16px; + } + + .overlayPanel { + max-height: 90vh; + } + + .overlayHeader { + flex-direction: column; + align-items: flex-start; + } +} diff --git a/website/src/pages/examples/index.tsx b/website/src/pages/examples/index.tsx new file mode 100644 index 0000000000..60ebbe7fde --- /dev/null +++ b/website/src/pages/examples/index.tsx @@ -0,0 +1,131 @@ +import React, { useState, useRef, useEffect } from 'react'; +import Layout from '@theme/Layout'; +import { examples, categories, type Category, type Example } from '../../data/examples'; +import styles from './index.module.css'; + +function CodeOverlay({ example, onClose }: { example: Example; onClose: () => void }) { + const [yaml, setYaml] = useState(null); + const [copied, setCopied] = useState(false); + + useEffect(() => { + const url = `https://raw.githubusercontent.com/praxis-proxy/praxis/main/${example.path}`; + fetch(url) + .then((res) => res.text()) + .then(setYaml) + .catch(() => setYaml('# Could not load this example.\n# View it on GitHub instead.')); + }, [example.path]); + + useEffect(() => { + const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose(); }; + document.addEventListener('keydown', onKey); + document.body.style.overflow = 'hidden'; + return () => { + document.removeEventListener('keydown', onKey); + document.body.style.overflow = ''; + }; + }, [onClose]); + + const handleCopy = async () => { + if (!yaml) return; + try { + await navigator.clipboard.writeText(yaml); + setCopied(true); + setTimeout(() => setCopied(false), 2000); + } catch {} + }; + + return ( +
+
e.stopPropagation()}> +
+
+ {example.name} + {example.category} +
+
+ + GitHub + + + +
+
+
+ {yaml ?
{yaml}
:

Loading...

} +
+
+
+ ); +} + +export default function Examples(): React.JSX.Element { + const [activeCategory, setActiveCategory] = useState('All'); + const [selected, setSelected] = useState(null); + + const filtered = + activeCategory === 'All' + ? examples + : examples.filter((e) => e.category === activeCategory); + + const handleSelect = (example: Example) => { + setSelected(selected?.path === example.path ? null : example); + }; + + return ( + +
+

Examples

+

+ {examples.length} configurations you can copy and run. Each one demonstrates a real use case. +

+
+ {categories.map((cat) => ( + + ))} +
+

+ Showing {filtered.length} example{filtered.length !== 1 ? 's' : ''} +

+
+ {filtered.map((example) => ( + + ))} +
+ + {selected && ( + setSelected(null)} + /> + )} +
+
+ ); +} diff --git a/website/src/pages/index.module.css b/website/src/pages/index.module.css new file mode 100644 index 0000000000..b5dab0e72d --- /dev/null +++ b/website/src/pages/index.module.css @@ -0,0 +1,631 @@ +/* ============================================ + Landing Page — Split hero with pipeline viz + ============================================ */ + +@keyframes revealUp { + from { opacity: 0; transform: translateY(24px); } + to { opacity: 1; transform: translateY(0); } +} + +@keyframes revealScale { + from { opacity: 0; transform: scale(0.96); } + to { opacity: 1; transform: scale(1); } +} + +@keyframes lineExpand { + from { transform: scaleX(0); } + to { transform: scaleX(1); } +} + +@keyframes flowDown { + 0% { top: -6px; opacity: 0; } + 20% { opacity: 1; } + 80% { opacity: 1; } + 100% { top: calc(100% - 2px); opacity: 0; } +} + +@keyframes dotPulse { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.4; } +} + +/* Hero — darker shade */ +.hero { + position: relative; + padding: 0; + overflow: hidden; + background: var(--praxis-bg-alt); +} + +.heroSplit { + max-width: 1200px; + margin: 0 auto; + padding: 72px 24px 88px; + display: flex; + align-items: flex-start; + gap: 64px; + position: relative; + z-index: 1; +} + +.heroContent { + flex: 1; + min-width: 0; +} + +.heroVisual { + flex: 0 0 340px; + padding-top: 16px; + opacity: 0; + animation: revealUp 0.8s cubic-bezier(0.16, 1, 0.3, 1) 0.6s both; +} + +/* Radial glow behind hero content */ +.heroGlow { + position: absolute; + top: 30%; + left: 25%; + transform: translate(-50%, -50%); + width: 800px; + height: 600px; + background: radial-gradient(ellipse, rgba(139, 108, 199, 0.07) 0%, transparent 65%); + pointer-events: none; + z-index: 0; +} + +.heroTitle { + font-family: var(--praxis-font-display); + font-size: clamp(2.5rem, 5.5vw, 4.5rem); + font-weight: 900; + letter-spacing: -0.045em; + color: var(--praxis-text-primary); + margin-bottom: 20px; + line-height: 1.02; + opacity: 0; + animation: revealUp 0.7s cubic-bezier(0.16, 1, 0.3, 1) 0.2s both; +} + +.heroAccent { + color: var(--praxis-accent); +} + +.heroSubtitle { + font-family: var(--praxis-font-body); + font-size: 1.0625rem; + font-weight: 400; + color: var(--praxis-text-secondary); + max-width: 480px; + margin-bottom: 36px; + line-height: 1.65; + opacity: 0; + animation: revealUp 0.7s cubic-bezier(0.16, 1, 0.3, 1) 0.3s both; +} + +/* CTAs */ +.heroCtas { + display: flex; + gap: 12px; + margin-bottom: 28px; + opacity: 0; + animation: revealUp 0.6s cubic-bezier(0.16, 1, 0.3, 1) 0.4s both; +} + +.ctaPrimary { + background: var(--praxis-accent); + color: var(--praxis-text-primary); + padding: 11px 26px; + border-radius: 8px; + font-family: var(--praxis-font-body); + font-weight: 600; + font-size: 0.875rem; + text-decoration: none; + letter-spacing: -0.01em; + transition: background 0.25s cubic-bezier(0.16, 1, 0.3, 1), + transform 0.25s cubic-bezier(0.16, 1, 0.3, 1), + box-shadow 0.25s cubic-bezier(0.16, 1, 0.3, 1); +} + +.ctaPrimary:hover { + background: var(--praxis-accent-hover); + color: var(--praxis-text-primary); + text-decoration: none; + transform: translateY(-1px); +} + +.ctaSecondary { + border: 1px solid var(--praxis-border); + color: var(--praxis-text-secondary); + padding: 11px 26px; + border-radius: 8px; + font-family: var(--praxis-font-body); + font-weight: 500; + font-size: 0.875rem; + text-decoration: none; + letter-spacing: -0.01em; + transition: border-color 0.25s cubic-bezier(0.16, 1, 0.3, 1), + color 0.25s cubic-bezier(0.16, 1, 0.3, 1), + transform 0.25s cubic-bezier(0.16, 1, 0.3, 1); +} + +.ctaSecondary:hover { + border-color: var(--praxis-accent); + color: var(--praxis-text-primary); + text-decoration: none; + transform: translateY(-1px); +} + +/* Install snippet */ +.installSnippet { + display: inline-flex; + align-items: center; + gap: 10px; + background: var(--praxis-bg-surface); + border: 1px solid var(--praxis-border); + border-radius: 8px; + padding: 11px 18px; + font-family: var(--praxis-font-mono); + font-size: 0.825rem; + color: var(--praxis-text-secondary); + cursor: pointer; + transition: border-color 0.25s cubic-bezier(0.16, 1, 0.3, 1), + background 0.25s cubic-bezier(0.16, 1, 0.3, 1); + opacity: 0; + animation: revealUp 0.6s cubic-bezier(0.16, 1, 0.3, 1) 0.5s both; +} + +.installSnippet:hover { + border-color: var(--praxis-accent); + background: var(--praxis-bg-raised); +} + +.installSnippet code { + color: var(--praxis-text-primary); + background: none; + padding: 0; + border: none; + font-family: var(--praxis-font-mono); +} + +.installPrompt { + color: var(--praxis-text-muted); +} + +.installCopyHint { + font-size: 0.85rem; + color: var(--praxis-text-muted); + transition: color 0.2s; +} + +.installCopied { + color: var(--praxis-accent) !important; +} + +/* ============================================ + Pipeline Visualization + ============================================ */ + +.pipeline { + background: rgba(139, 108, 199, 0.04); + border: 1px solid rgba(139, 108, 199, 0.2); + border-radius: 16px; + padding: 24px 20px 20px; + position: relative; + display: flex; + flex-direction: column; + align-items: center; +} + +.pipelineLabel { + font-family: var(--praxis-font-body); + font-size: 0.6rem; + font-weight: 600; + letter-spacing: 0.12em; + text-transform: uppercase; + color: var(--praxis-text-muted); + margin-bottom: 20px; + text-align: center; + width: 100%; +} + +/* Entry point */ +.pipelineEntry { + display: flex; + flex-direction: column; + align-items: center; + gap: 6px; + margin-bottom: 0; +} + +.pipelineDot { + width: 8px; + height: 8px; + border-radius: 50%; + background: var(--praxis-accent); + animation: dotPulse 2s ease-in-out infinite; +} + +.pipelineEntryLabel { + font-family: var(--praxis-font-body); + font-size: 0.65rem; + color: var(--praxis-text-muted); + letter-spacing: 0.02em; +} + +/* Connector line with flowing dot */ +.pipelineConnector { + width: 1px; + height: 28px; + background: rgba(139, 108, 199, 0.25); + margin: 0 auto; + position: relative; + overflow: hidden; +} + +.flowDot { + position: absolute; + left: 50%; + transform: translateX(-50%); + width: 5px; + height: 5px; + border-radius: 50%; + background: var(--praxis-accent); + animation: flowDown 2s cubic-bezier(0.4, 0, 0.2, 1) infinite; +} + +/* Filter node */ +.filterNode { + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + gap: 4px; + background: rgba(255, 255, 255, 0.04); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 8px; + padding: 12px 20px; + width: 100%; + transition: border-color 0.3s; +} + +.filterNode:hover { + border-color: var(--praxis-border-hover); +} + +.filterNodeAccent { + border-color: rgba(139, 108, 199, 0.3); +} + +.filterName { + font-family: var(--praxis-font-mono); + font-size: 0.75rem; + font-weight: 600; + color: var(--praxis-text-primary); + letter-spacing: -0.01em; +} + +.filterDesc { + font-family: var(--praxis-font-body); + font-size: 0.625rem; + color: var(--praxis-text-muted); + margin-top: 1px; +} + +/* Branch */ +.pipelineBranch { + display: flex; + gap: 12px; + margin-top: 0; + margin-left: -8px; + width: calc(100% + 16px); +} + +.branchLeft, +.branchRight { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; +} + +.branchConnector { + width: 1px; + height: 24px; + background: rgba(139, 108, 199, 0.25); + position: relative; + overflow: hidden; +} + +.filterNodeSmall { + background: rgba(255, 255, 255, 0.04); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 6px; + padding: 10px 14px; + text-align: center; + width: 100%; + transition: border-color 0.3s; +} + +.filterNodeSmall:hover { + border-color: var(--praxis-border-hover); +} + +.filterNodeSmall .filterName { + font-size: 0.675rem; +} + +.filterNodeSmall .filterDesc { + font-size: 0.575rem; + color: var(--praxis-accent); + opacity: 0.7; +} + +/* Pipeline footer (load_balancer convergence) */ +.pipelineFooter { + display: flex; + flex-direction: column; + align-items: center; + margin-top: 0; +} + +.pipelineConnectorCenter { + width: 1px; + height: 24px; + background: rgba(139, 108, 199, 0.25); + position: relative; + overflow: hidden; +} + +/* Decorative line */ +.heroLine { + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: 1px; + background: linear-gradient( + 90deg, + transparent 0%, + var(--praxis-border) 15%, + var(--praxis-accent) 50%, + var(--praxis-border) 85%, + transparent 100% + ); + opacity: 0; + animation: lineExpand 1s cubic-bezier(0.16, 1, 0.3, 1) 0.8s both; +} + +/* ============================================ + Features + ============================================ */ + +.features { + padding: 80px 0; + position: relative; +} + +.featuresInner { + max-width: 1200px; + margin: 0 auto; + padding: 0 24px; +} + +.featuresTitle { + font-family: var(--praxis-font-display); + font-size: clamp(1.5rem, 3vw, 2rem); + font-weight: 800; + letter-spacing: -0.03em; + color: var(--praxis-text-primary); + margin-bottom: 40px; +} + +.featuresGrid { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 16px; +} + +.featureCard { + background: var(--praxis-bg-surface); + border: 1px solid var(--praxis-border); + border-radius: 12px; + padding: 32px; + transition: border-color 0.3s cubic-bezier(0.16, 1, 0.3, 1), + transform 0.3s cubic-bezier(0.16, 1, 0.3, 1), + box-shadow 0.3s cubic-bezier(0.16, 1, 0.3, 1); + opacity: 0; + animation: revealScale 0.6s cubic-bezier(0.16, 1, 0.3, 1) both; + position: relative; + overflow: hidden; +} + +.featureCard:hover { + border-color: var(--praxis-border-hover); + transform: translateY(-2px); + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2); +} + +.featureCard:nth-child(1) { + grid-column: span 2; + animation-delay: 0.8s; +} +.featureCard:nth-child(2) { animation-delay: 0.9s; } +.featureCard:nth-child(3) { animation-delay: 1.0s; } +.featureCard:nth-child(4) { animation-delay: 1.1s; } + +.featureIcon { + margin-right: 10px; + color: var(--praxis-accent); +} + +.featureTitle { + font-family: var(--praxis-font-display); + font-size: 1.125rem; + font-weight: 700; + color: var(--praxis-text-primary); + margin-bottom: 10px; + letter-spacing: -0.02em; + line-height: 1.3; +} + +.featureDesc { + font-family: var(--praxis-font-body); + font-size: 0.875rem; + color: var(--praxis-text-muted); + line-height: 1.6; + margin: 0; +} + +/* ============================================ + CTA Section + ============================================ */ + +/* CTA — darker shade (alternating) */ +.ctaSection { + padding: 96px 0; + position: relative; + background: var(--praxis-bg-alt); +} + +.ctaSection::before { + content: ''; + position: absolute; + top: 0; + left: 50%; + transform: translateX(-50%); + width: min(1200px, calc(100% - 48px)); + height: 1px; + background: linear-gradient( + 90deg, + transparent, + var(--praxis-border) 20%, + var(--praxis-border) 80%, + transparent + ); +} + +.ctaInner { + max-width: 1200px; + margin: 0 auto; + padding: 0 24px; + display: flex; + align-items: center; + justify-content: space-between; + gap: 48px; +} + +.ctaSectionTitle { + font-family: var(--praxis-font-display); + font-size: 1.75rem; + font-weight: 800; + color: var(--praxis-text-primary); + letter-spacing: -0.03em; + margin: 0; + line-height: 1.2; +} + +.ctaSectionSub { + font-family: var(--praxis-font-body); + font-size: 0.9375rem; + color: var(--praxis-text-muted); + margin-top: 8px; +} + +.ctaLinks { + display: flex; + gap: 12px; + flex-shrink: 0; +} + +/* ============================================ + Responsive + ============================================ */ + +@media (max-width: 960px) { + .heroSplit { + flex-direction: column; + gap: 48px; + } + + .heroVisual { + flex: none; + width: 100%; + max-width: 400px; + } + + .featuresGrid { + grid-template-columns: repeat(2, 1fr); + } + + .featureCard:nth-child(1) { + grid-column: span 1; + } +} + +@media (max-width: 768px) { + .heroSplit { + padding: 48px 24px 64px; + } + + .heroTitle { + font-size: 2.25rem; + } + + .ctaInner { + flex-direction: column; + text-align: center; + gap: 24px; + } + + .ctaLinks { + flex-wrap: wrap; + justify-content: center; + } + + .heroCtas { + flex-wrap: wrap; + } + + .heroVisual { + flex: none; + width: 100%; + max-width: 340px; + margin: 0 auto; + } +} + +@media (max-width: 640px) { + .featuresGrid { + grid-template-columns: 1fr; + } + + .featureCard { + padding: 24px; + } +} + +/* Reduced motion */ +@media (prefers-reduced-motion: reduce) { + .heroTitle, + .heroSubtitle, + .heroCtas, + .installSnippet, + .featureCard, + .heroLine, + .heroVisual { + animation: none; + opacity: 1; + transform: none; + } + + .flowDot, + .pipelineDot { + animation: none; + } + + + .featureCard, + .ctaPrimary, + .ctaSecondary { + transition: none; + } +} diff --git a/website/src/pages/index.tsx b/website/src/pages/index.tsx new file mode 100644 index 0000000000..6573605044 --- /dev/null +++ b/website/src/pages/index.tsx @@ -0,0 +1,233 @@ +import React, { useState } from 'react'; +import Layout from '@theme/Layout'; +import styles from './index.module.css'; + +const features = [ + { + title: 'AI-Native Routing', + description: + 'Route LLM requests to the right provider by inspecting JSON bodies. Inject credentials per-cluster so clients never handle API keys.', + icon: '⇉', + }, + { + title: 'Everything is a Filter', + description: + '35+ built-in filters you compose into pipelines. Need something custom? Write it in Rust — it compiles into the binary.', + icon: '≡', + }, + { + title: 'Secure by Default', + description: + 'Zero lines of unsafe code. Rustls instead of OpenSSL. Every security filter — CORS, CSRF, IP ACL, rate limiting — ships ready to use.', + icon: '△', + }, + { + title: 'Any Protocol, Zero Downtime', + description: + 'HTTP/1.1, HTTP/2, TCP, WebSocket, SSE, gRPC with TLS and mTLS. Swap configs at runtime without dropping a connection.', + icon: '⬡', + }, +]; + +function Pipeline() { + return ( +