From d32b694422db771a0682ea56f7e35b401580afd2 Mon Sep 17 00:00:00 2001 From: Moshe Immerman Date: Thu, 21 May 2026 16:14:25 +0200 Subject: [PATCH] feat(opensearch): add opensearch plugin for trace querying Introduce a new OpenSearch plugin that enables profile-based trace querying for Mission Control. The plugin provides: - Generic trace query interface supporting multiple OpenSearch index formats (Jaeger, OTEL) - Profile-driven filtering and customizable table views - React-based UI with real-time query preview and result inspection - Connection validation and secure credential handling - Configurable tracing profiles with field mappings and query parameters The plugin integrates with Mission Control's plugin SDK and can be deployed as a standalone binary module. Refs #opensearch --- Taskfile.yml | 7 +- opensearch/Plugin.yaml | 24 + opensearch/Taskfile.yml | 80 + opensearch/client.go | 172 + opensearch/go.mod | 27 + opensearch/go.sum | 110 + opensearch/http.go | 18 + opensearch/internal/gen-checksum/main.go | 70 + opensearch/main.go | 125 + opensearch/ops.go | 102 + opensearch/parser.go | 351 ++ opensearch/parser_test.go | 43 + opensearch/profile.go | 383 ++ opensearch/profile_test.go | 47 + opensearch/profiles/jaeger.yaml | 56 + opensearch/profiles/otel.yaml | 55 + opensearch/query.go | 253 ++ opensearch/ui-src/index.html | 12 + opensearch/ui-src/package.json | 25 + opensearch/ui-src/pnpm-lock.yaml | 4465 ++++++++++++++++++++++ opensearch/ui-src/src/main.tsx | 457 +++ opensearch/ui-src/src/styles.css | 1 + opensearch/ui-src/src/version.ts | 2 + opensearch/ui-src/src/vite-env.d.ts | 1 + opensearch/ui-src/tsconfig.json | 21 + opensearch/ui-src/vite.config.ts | 12 + opensearch/ui/index.html | 13 + opensearch/ui_checksum.go | 5 + 28 files changed, 6934 insertions(+), 3 deletions(-) create mode 100644 opensearch/Plugin.yaml create mode 100644 opensearch/Taskfile.yml create mode 100644 opensearch/client.go create mode 100644 opensearch/go.mod create mode 100644 opensearch/go.sum create mode 100644 opensearch/http.go create mode 100644 opensearch/internal/gen-checksum/main.go create mode 100644 opensearch/main.go create mode 100644 opensearch/ops.go create mode 100644 opensearch/parser.go create mode 100644 opensearch/parser_test.go create mode 100644 opensearch/profile.go create mode 100644 opensearch/profile_test.go create mode 100644 opensearch/profiles/jaeger.yaml create mode 100644 opensearch/profiles/otel.yaml create mode 100644 opensearch/query.go create mode 100644 opensearch/ui-src/index.html create mode 100644 opensearch/ui-src/package.json create mode 100644 opensearch/ui-src/pnpm-lock.yaml create mode 100644 opensearch/ui-src/src/main.tsx create mode 100644 opensearch/ui-src/src/styles.css create mode 100644 opensearch/ui-src/src/version.ts create mode 100644 opensearch/ui-src/src/vite-env.d.ts create mode 100644 opensearch/ui-src/tsconfig.json create mode 100644 opensearch/ui-src/vite.config.ts create mode 100644 opensearch/ui/index.html create mode 100644 opensearch/ui_checksum.go diff --git a/Taskfile.yml b/Taskfile.yml index 62db924..d8f24a8 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -38,9 +38,9 @@ tasks: - task --list build: - desc: Build the full incident-commander binary with embedded UI - deps: - - go:build + desc: Build standalone plugin modules + cmds: + - task -d opensearch build clean: desc: Remove build artifacts and Task checksums @@ -53,6 +53,7 @@ tasks: tailwind-asset: desc: Download the vendored Tailwind script used by the OIDC static page cmds: + - mkdir -p auth/oidc/static - curl -sL "https://cdn.tailwindcss.com/{{.TAILWIND_VERSION}}" -o {{.TAILWIND_JS}} generates: - "{{.TAILWIND_JS}}" diff --git a/opensearch/Plugin.yaml b/opensearch/Plugin.yaml new file mode 100644 index 0000000..86ed512 --- /dev/null +++ b/opensearch/Plugin.yaml @@ -0,0 +1,24 @@ +apiVersion: mission-control.flanksource.com/v1 +kind: Plugin +metadata: + name: opensearch +spec: + source: opensearch + version: "0.1.0" + selector: + types: + - MissionControl::Connection + - OpenSearch::Cluster + - OpenSearch::Index + - Elasticsearch::Cluster + - Elasticsearch::Index + connections: + opensearch: {} + + # Optional plugin properties: + # defaultProfile: jaeger + # index: jaeger-span* + # profilesYaml: | + # custom: + # imports: [otel] + # index: traces-* diff --git a/opensearch/Taskfile.yml b/opensearch/Taskfile.yml new file mode 100644 index 0000000..c18616c --- /dev/null +++ b/opensearch/Taskfile.yml @@ -0,0 +1,80 @@ +version: "3" + +vars: + PLUGIN_NAME: opensearch + VERSION: + sh: git describe --tags --always --dirty 2>/dev/null || echo dev + BUILD_DATE: + sh: date -u "+%Y-%m-%d %H:%M:%S" + PLUGIN_PATH: + sh: echo "${MISSION_CONTROL_PLUGIN_PATH:-$HOME/.mission-control/plugins}" + +tasks: + ui:install: + desc: Install pnpm dependencies for the OpenSearch plugin UI + dir: ui-src + cmds: + - PATH="/usr/local/opt/node/bin:$PATH" CI=true pnpm install --no-frozen-lockfile --prefer-offline + sources: + - package.json + status: + - test -f node_modules/.modules.yaml + - test node_modules/.modules.yaml -nt package.json + + ui:build: + desc: Build the plugin UI bundle into ./ui + dir: ui-src + deps: [ui:install] + env: + PLUGIN_VERSION: "{{.VERSION}}" + PLUGIN_BUILD_DATE: "{{.BUILD_DATE}}" + cmds: + - PATH="/usr/local/opt/node/bin:$PATH" pnpm run build + sources: + - src/**/*.ts + - src/**/*.tsx + - src/**/*.css + - index.html + - package.json + - tsconfig.json + - vite.config.ts + generates: + - ../ui/index.html + + generate: + desc: Regenerate ui_checksum.go from the built UI bundle + deps: [ui:build] + cmds: + - go generate . + sources: + - ui/** + - internal/gen-checksum/main.go + generates: + - ui_checksum.go + + test: + desc: Run plugin unit tests + cmds: + - go test . + + build: + desc: Build and install the plugin binary into $MISSION_CONTROL_PLUGIN_PATH + deps: [generate] + cmds: + - mkdir -p {{.PLUGIN_PATH}} + - >- + go build -o {{.PLUGIN_PATH}}/{{.PLUGIN_NAME}} + -ldflags "-X 'main.Version={{.VERSION}}' -X 'main.BuildDate={{.BUILD_DATE}}'" + . + - echo "Installed {{.PLUGIN_PATH}}/{{.PLUGIN_NAME}} version={{.VERSION}} built={{.BUILD_DATE}}" + sources: + - ./*.go + - profiles/** + - internal/**/*.go + - ui/** + - ui_checksum.go + - ../../plugin/**/*.go + - ../../go.mod + - ../../go.sum + generates: + - "{{.PLUGIN_PATH}}/{{.PLUGIN_NAME}}" diff --git a/opensearch/client.go b/opensearch/client.go new file mode 100644 index 0000000..51d5178 --- /dev/null +++ b/opensearch/client.go @@ -0,0 +1,172 @@ +package main + +import ( + "bytes" + "context" + "crypto/tls" + "encoding/json" + "fmt" + "io" + "net/http" + "strings" + "time" + + "github.com/flanksource/incident-commander/plugin/sdk" +) + +type resolvedOpenSearch struct { + URLs []string + Username string + Password string + Index string + InsecureSkipVerify bool +} + +type openSearchClient struct { + conn resolvedOpenSearch + client *http.Client +} + +func resolveOpenSearch(ctx context.Context, host sdk.HostClient, configItemID string) (resolvedOpenSearch, error) { + if host == nil { + return resolvedOpenSearch{}, fmt.Errorf("no host client available") + } + conn, err := host.GetConnection(ctx, "opensearch", configItemID) + if err != nil { + return resolvedOpenSearch{}, fmt.Errorf("get opensearch connection: %w", err) + } + if conn == nil { + return resolvedOpenSearch{}, fmt.Errorf("host returned no opensearch connection") + } + out := resolvedOpenSearch{ + Username: conn.Username, + Password: conn.Password, + } + if conn.Url != "" { + out.URLs = append(out.URLs, conn.Url) + } + if conn.Properties != nil { + props := conn.Properties.AsMap() + if raw, ok := props["urls"].(string); ok { + for _, part := range strings.Split(raw, ",") { + if trimmed := strings.TrimSpace(part); trimmed != "" { + out.URLs = append(out.URLs, trimmed) + } + } + } + if values, ok := props["urls"].([]any); ok { + for _, value := range values { + if s, ok := value.(string); ok && strings.TrimSpace(s) != "" { + out.URLs = append(out.URLs, strings.TrimSpace(s)) + } + } + } + if index, ok := props["index"].(string); ok { + out.Index = index + } + if insecure, ok := props["insecureSkipVerify"].(bool); ok { + out.InsecureSkipVerify = insecure + } + if insecure, ok := props["insecure_tls"].(bool); ok { + out.InsecureSkipVerify = insecure + } + } + out.URLs = uniqueStrings(out.URLs) + if len(out.URLs) == 0 { + return resolvedOpenSearch{}, fmt.Errorf("opensearch connection has no urls") + } + return out, nil +} + +func newOpenSearchClient(conn resolvedOpenSearch) *openSearchClient { + transport := http.DefaultTransport.(*http.Transport).Clone() + if conn.InsecureSkipVerify { + transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} + } + return &openSearchClient{ + conn: conn, + client: &http.Client{ + Timeout: 60 * time.Second, + Transport: transport, + }, + } +} + +func (c *openSearchClient) Check(ctx context.Context) error { + req, err := http.NewRequestWithContext(ctx, http.MethodGet, strings.TrimRight(c.conn.URLs[0], "/"), nil) + if err != nil { + return err + } + c.authorize(req) + resp, err := c.client.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + if resp.StatusCode >= 400 { + body, _ := io.ReadAll(io.LimitReader(resp.Body, 4096)) + return fmt.Errorf("opensearch returned %s: %s", resp.Status, strings.TrimSpace(string(body))) + } + return nil +} + +func (c *openSearchClient) Search(ctx context.Context, index string, limit int, query map[string]any) (map[string]any, error) { + if limit <= 0 { + limit = 100 + } + body, err := json.Marshal(query) + if err != nil { + return nil, fmt.Errorf("marshal query: %w", err) + } + base := strings.TrimRight(c.conn.URLs[0], "/") + url := base + "/" + strings.Trim(index, "/") + "/_search" + req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(body)) + if err != nil { + return nil, err + } + q := req.URL.Query() + q.Set("size", fmt.Sprintf("%d", limit)) + req.URL.RawQuery = q.Encode() + req.Header.Set("Content-Type", "application/json") + c.authorize(req) + resp, err := c.client.Do(req) + if err != nil { + return nil, fmt.Errorf("execute search: %w", err) + } + defer resp.Body.Close() + respBody, err := io.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("read search response: %w", err) + } + if resp.StatusCode >= 400 { + return nil, fmt.Errorf("opensearch search returned %s: %s", resp.Status, strings.TrimSpace(string(respBody))) + } + var result map[string]any + if err := json.Unmarshal(respBody, &result); err != nil { + return nil, fmt.Errorf("decode search response: %w", err) + } + return result, nil +} + +func (c *openSearchClient) authorize(req *http.Request) { + if c.conn.Username != "" || c.conn.Password != "" { + req.SetBasicAuth(c.conn.Username, c.conn.Password) + } +} + +func uniqueStrings(values []string) []string { + seen := map[string]struct{}{} + out := make([]string, 0, len(values)) + for _, value := range values { + value = strings.TrimSpace(value) + if value == "" { + continue + } + if _, ok := seen[value]; ok { + continue + } + seen[value] = struct{}{} + out = append(out, value) + } + return out +} diff --git a/opensearch/go.mod b/opensearch/go.mod new file mode 100644 index 0000000..a2e4f99 --- /dev/null +++ b/opensearch/go.mod @@ -0,0 +1,27 @@ +module github.com/flanksource/mission-control-plugins/opensearch + +go 1.26.1 + +require ( + github.com/flanksource/incident-commander v0.0.1747 + gopkg.in/yaml.v3 v3.0.1 +) + + +require ( + github.com/fatih/color v1.18.0 // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/hashicorp/go-hclog v1.6.3 // indirect + github.com/hashicorp/go-plugin v1.8.0 // indirect + github.com/hashicorp/yamux v0.1.2 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/oklog/run v1.1.0 // indirect + golang.org/x/net v0.53.0 // indirect + golang.org/x/sys v0.43.0 // indirect + golang.org/x/text v0.36.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 // indirect + google.golang.org/grpc v1.80.0 // indirect + google.golang.org/protobuf v1.36.11 // indirect + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect +) diff --git a/opensearch/go.sum b/opensearch/go.sum new file mode 100644 index 0000000..e035ed9 --- /dev/null +++ b/opensearch/go.sum @@ -0,0 +1,110 @@ +github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= +github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw= +github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 h1:z2ogiKUYzX5Is6zr/vP9vJGqPwcdqsWjOt+V8J7+bTc= +github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= +github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-plugin v1.8.0 h1:ie8S6RRY8RvB2usYZv+AAZ/wBvx2AU5p5QeP5j/FORs= +github.com/hashicorp/go-plugin v1.8.0/go.mod h1:BExt6KEaIYx804z8k4gRzRLEvxKVb+kn0NMcihqOqb8= +github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8= +github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns= +github.com/jhump/protoreflect v1.17.0 h1:qOEr613fac2lOuTgWN4tPAtLL7fUSbuJL5X5XumQh94= +github.com/jhump/protoreflect v1.17.0/go.mod h1:h9+vUUL38jiBzck8ck+6G/aeMX8Z4QUY/NiJPwPNi+8= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/onsi/ginkgo/v2 v2.28.1 h1:S4hj+HbZp40fNKuLUQOYLDgZLwNUVn19N3Atb98NCyI= +github.com/onsi/ginkgo/v2 v2.28.1/go.mod h1:CLtbVInNckU3/+gC8LzkGUb9oF+e8W8TdUsxPwvdOgE= +github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28= +github.com/onsi/gomega v1.39.1/go.mod h1:hL6yVALoTOxeWudERyfppUcZXjMwIMLnuSfruD2lcfg= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= +go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= +go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= +go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= +go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= +go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= +go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= +go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= +go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= +go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI= +golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY= +golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA= +golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs= +golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= +golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= +golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg= +golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164= +golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s= +golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0= +gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= +gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 h1:RmoJA1ujG+/lRGNfUnOMfhCy5EipVMyvUE+KNbPbTlw= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM= +google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/opensearch/http.go b/opensearch/http.go new file mode 100644 index 0000000..491c6db --- /dev/null +++ b/opensearch/http.go @@ -0,0 +1,18 @@ +package main + +import ( + "net/http" + + "github.com/flanksource/incident-commander/plugin/sdk" +) + +func (p *OpenSearchPlugin) HTTPHandler() http.Handler { + mux := http.NewServeMux() + mux.Handle("/version", sdk.VersionHandler(sdk.BuildInfo{ + Name: pluginName, + Version: Version, + BuildDate: BuildDate, + UIChecksum: uiChecksum, + })) + return mux +} diff --git a/opensearch/internal/gen-checksum/main.go b/opensearch/internal/gen-checksum/main.go new file mode 100644 index 0000000..a124b0f --- /dev/null +++ b/opensearch/internal/gen-checksum/main.go @@ -0,0 +1,70 @@ +package main + +import ( + "crypto/sha256" + "encoding/hex" + "fmt" + "io" + "io/fs" + "os" + "path/filepath" + "sort" +) + +const ( + outputPath = "ui_checksum.go" + uiDir = "ui" +) + +func main() { + files, err := walk(uiDir) + if err != nil { + fmt.Fprintf(os.Stderr, "gen-checksum: walk %s: %v\n", uiDir, err) + os.Exit(1) + } + hasher := sha256.New() + for _, path := range files { + f, err := os.Open(path) + if err != nil { + fmt.Fprintf(os.Stderr, "gen-checksum: open %s: %v\n", path, err) + os.Exit(1) + } + fmt.Fprintf(hasher, "%s\x00", path) + if _, err := io.Copy(hasher, f); err != nil { + f.Close() + fmt.Fprintf(os.Stderr, "gen-checksum: read %s: %v\n", path, err) + os.Exit(1) + } + f.Close() + } + sum := hex.EncodeToString(hasher.Sum(nil)) + contents := fmt.Sprintf(`// Code generated by plugins/opensearch/internal/gen-checksum. DO NOT EDIT. + +package main + +const uiChecksum = %q +`, sum) + if err := os.WriteFile(outputPath, []byte(contents), 0o644); err != nil { + fmt.Fprintf(os.Stderr, "gen-checksum: write %s: %v\n", outputPath, err) + os.Exit(1) + } +} + +func walk(root string) ([]string, error) { + var out []string + err := filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + if d.IsDir() { + return nil + } + out = append(out, path) + return nil + }) + if err != nil { + return nil, err + } + sort.Strings(out) + return out, nil +} diff --git a/opensearch/main.go b/opensearch/main.go new file mode 100644 index 0000000..611fc47 --- /dev/null +++ b/opensearch/main.go @@ -0,0 +1,125 @@ +// OpenSearch plugin: generic profile-based trace querying for Mission Control. +// +// Build: task -d plugins/opensearch build +// Apply: kubectl apply -f plugins/opensearch/Plugin.yaml +package main + +import ( + "context" + "embed" + "io/fs" + + pluginpb "github.com/flanksource/incident-commander/plugin/proto" + "github.com/flanksource/incident-commander/plugin/sdk" +) + +const ( + OpProfilesList = "profiles-list" + OpTraceQuery = "trace-query" + OpQueryPreview = "query-preview" + OpConnectionCheck = "connection-check" + pluginName = "opensearch" +) + +//go:generate go run ./internal/gen-checksum + +//go:embed all:ui +var uiAssets embed.FS + +var ( + Version = "" + BuildDate = "" +) + +func main() { + sub, err := fs.Sub(uiAssets, "ui") + if err != nil { + panic(err) + } + sdk.Serve(newPlugin(), sdk.WithStaticAssets(sub)) +} + +type OpenSearchPlugin struct { + settings PluginSettings +} + +type PluginSettings struct { + DefaultProfile string + Index string + Profiles map[string]TracingProfile +} + +func defaultSettings() PluginSettings { + return PluginSettings{ + DefaultProfile: "jaeger", + Profiles: map[string]TracingProfile{}, + } +} + +func newPlugin() *OpenSearchPlugin { + return &OpenSearchPlugin{settings: defaultSettings()} +} + +func (p *OpenSearchPlugin) Manifest() *pluginpb.PluginManifest { + return &pluginpb.PluginManifest{ + Name: pluginName, + Version: sdk.FormatVersion(Version, BuildDate, uiChecksum), + Description: "Query OpenSearch trace indexes through profile-driven filters and table views.", + Capabilities: []string{"tabs", "operations"}, + Tabs: []*pluginpb.TabSpec{ + {Name: "OpenSearch", Icon: "lucide:search", Path: "/", Scope: "config"}, + }, + Operations: operationDefs(), + } +} + +func (p *OpenSearchPlugin) Configure(_ context.Context, settings map[string]any) error { + next := p.settings + if next.DefaultProfile == "" { + next = defaultSettings() + } + if v, ok := settings["defaultProfile"].(string); ok && v != "" { + next.DefaultProfile = v + } + if v, ok := settings["index"].(string); ok && v != "" { + next.Index = v + } + if v, ok := settings["profilesYaml"].(string); ok && v != "" { + profiles, err := parseProfilesYAML([]byte(v)) + if err != nil { + return err + } + next.Profiles = profiles + } + p.settings = next + return nil +} + +func (p *OpenSearchPlugin) Operations() []sdk.Operation { + handlers := map[string]func(context.Context, sdk.InvokeCtx) (any, error){ + OpProfilesList: p.profilesList, + OpTraceQuery: p.traceQuery, + OpQueryPreview: p.queryPreview, + OpConnectionCheck: p.connectionCheck, + } + defs := operationDefs() + out := make([]sdk.Operation, 0, len(defs)) + for _, d := range defs { + if h, ok := handlers[d.Name]; ok { + out = append(out, sdk.Operation{Def: d, Handler: h}) + } + } + return out +} + +func operationDefs() []*pluginpb.OperationDef { + mk := func(name, desc string) *pluginpb.OperationDef { + return &pluginpb.OperationDef{Name: name, Description: desc, Scope: "config", ResultMime: sdk.ClickyResultMimeType} + } + return []*pluginpb.OperationDef{ + mk(OpProfilesList, "List resolved OpenSearch tracing profiles."), + mk(OpTraceQuery, "Run a profile-based OpenSearch trace query."), + mk(OpQueryPreview, "Render the OpenSearch query body without executing it."), + mk(OpConnectionCheck, "Verify the resolved OpenSearch connection responds."), + } +} diff --git a/opensearch/ops.go b/opensearch/ops.go new file mode 100644 index 0000000..df34393 --- /dev/null +++ b/opensearch/ops.go @@ -0,0 +1,102 @@ +package main + +import ( + "context" + "encoding/json" + "fmt" + + "github.com/flanksource/incident-commander/plugin/sdk" +) + +type TraceQueryRequest struct { + Profile string `json:"profile"` + From string `json:"from,omitempty"` + To string `json:"to,omitempty"` + Limit int `json:"limit,omitempty"` + Params map[string]any `json:"params,omitempty"` +} + +type ConnectionCheckResult struct { + OK bool `json:"ok"` + URLs []string `json:"urls"` + Index string `json:"index,omitempty"` + Message string `json:"message,omitempty"` +} + +func (p *OpenSearchPlugin) profilesList(_ context.Context, _ sdk.InvokeCtx) (any, error) { + return p.settings.profileSummaries() +} + +func (p *OpenSearchPlugin) queryPreview(_ context.Context, req sdk.InvokeCtx) (any, error) { + params, profile, err := p.decodeQuery(req.ParamsJSON) + if err != nil { + return nil, err + } + return buildQueryPreview(profile, params) +} + +func (p *OpenSearchPlugin) traceQuery(ctx context.Context, req sdk.InvokeCtx) (any, error) { + params, profile, err := p.decodeQuery(req.ParamsJSON) + if err != nil { + return nil, err + } + preview, err := buildQueryPreview(profile, params) + if err != nil { + return nil, err + } + conn, err := resolveOpenSearch(ctx, req.Host, req.ConfigItemID) + if err != nil { + return nil, err + } + if profile.Index == "" { + profile.Index = conn.Index + } + if profile.Index == "" { + return nil, fmt.Errorf("no OpenSearch index configured for profile %q", profile.Name) + } + client := newOpenSearchClient(conn) + raw, err := client.Search(ctx, profile.Index, preview.Request.Limit, preview.Request.Query) + if err != nil { + return nil, err + } + return parseSearchResult(raw, profile), nil +} + +func (p *OpenSearchPlugin) connectionCheck(ctx context.Context, req sdk.InvokeCtx) (any, error) { + conn, err := resolveOpenSearch(ctx, req.Host, req.ConfigItemID) + if err != nil { + return nil, err + } + err = newOpenSearchClient(conn).Check(ctx) + result := ConnectionCheckResult{ + OK: err == nil, + URLs: conn.URLs, + Index: conn.Index, + } + if err != nil { + result.Message = err.Error() + return result, err + } + result.Message = "connected" + return result, nil +} + +func (p *OpenSearchPlugin) decodeQuery(data []byte) (TraceQueryRequest, TracingProfile, error) { + var req TraceQueryRequest + if len(data) > 0 { + if err := json.Unmarshal(data, &req); err != nil { + return TraceQueryRequest{}, TracingProfile{}, fmt.Errorf("decode params: %w", err) + } + } + if req.Params == nil { + req.Params = map[string]any{} + } + profile, err := p.settings.resolveProfile(req.Profile) + if err != nil { + return TraceQueryRequest{}, TracingProfile{}, err + } + if req.Profile == "" { + req.Profile = profile.Name + } + return req, profile, nil +} diff --git a/opensearch/parser.go b/opensearch/parser.go new file mode 100644 index 0000000..093fd78 --- /dev/null +++ b/opensearch/parser.go @@ -0,0 +1,351 @@ +package main + +import ( + "encoding/json" + "fmt" + "math" + "strconv" + "strings" + "time" +) + +type TraceResult struct { + Profile string `json:"profile"` + Index string `json:"index"` + Total int `json:"total"` + Traces []Trace `json:"traces"` +} + +type Trace struct { + Timestamp string `json:"timestamp,omitempty"` + TraceID string `json:"trace_id,omitempty"` + SpanID string `json:"span_id,omitempty"` + ParentID string `json:"parent_id,omitempty"` + ServiceName string `json:"service_name,omitempty"` + OperationName string `json:"operation_name,omitempty"` + Status string `json:"status,omitempty"` + DurationMS float64 `json:"duration_ms,omitempty"` + Attributes map[string]any `json:"attributes,omitempty"` + Cells map[string]any `json:"cells,omitempty"` + Raw map[string]any `json:"raw,omitempty"` + Children []Trace `json:"children,omitempty"` +} + +func parseSearchResult(result map[string]any, profile TracingProfile) TraceResult { + hitsObj, _ := result["hits"].(map[string]any) + hits, _ := hitsObj["hits"].([]any) + traces := make([]Trace, 0, len(hits)) + for _, hitRaw := range hits { + hit, _ := hitRaw.(map[string]any) + source, _ := hit["_source"].(map[string]any) + if source == nil { + source = map[string]any{} + } + fields, _ := hit["fields"].(map[string]any) + merged := cloneAnyMap(source) + for k, v := range fields { + if _, ok := merged[k]; !ok { + merged[k] = unwrapFieldValue(v) + } + } + trace := traceFromDocument(merged, profile) + trace.Raw = merged + trace.Cells = evalCells(trace, profile.Columns) + traces = append(traces, trace) + } + return TraceResult{ + Profile: profile.Name, + Index: profile.Index, + Total: totalHits(hitsObj, len(traces)), + Traces: buildTraceTree(traces), + } +} + +func traceFromDocument(doc map[string]any, profile TracingProfile) Trace { + attrs := flattenDocument(doc) + trace := Trace{ + Timestamp: stringValue(firstPath(doc, profile.DateField, "@timestamp", "timestamp", "startTimeMillis")), + TraceID: stringValue(firstPath(doc, profile.TraceIDField, "trace_id", "traceID")), + SpanID: stringValue(firstPath(doc, profile.SpanIDField, "span_id", "spanID")), + ParentID: parentID(doc, profile), + ServiceName: stringValue(firstPath(doc, profile.ServiceField, "service_name", "process.serviceName")), + OperationName: stringValue(firstPath(doc, profile.OperationField, "operation_name", "operationName")), + DurationMS: durationMillis(firstPath(doc, "duration_ms", "duration", "durationNano", "duration_nano")), + Attributes: attrs, + } + trace.Status = statusValue(doc, attrs, profile) + if ts := normalizeTimestamp(trace.Timestamp); ts != "" { + trace.Timestamp = ts + } + return trace +} + +func evalCells(trace Trace, columns []TracingColumn) map[string]any { + env := map[string]any{ + "timestamp": trace.Timestamp, + "trace_id": trace.TraceID, + "span_id": trace.SpanID, + "parent_id": trace.ParentID, + "service_name": trace.ServiceName, + "operation_name": trace.OperationName, + "status": trace.Status, + "duration_ms": trace.DurationMS, + } + for k, v := range trace.Attributes { + env[k] = v + } + out := make(map[string]any, len(columns)) + for _, col := range columns { + if col.Name == "" || col.Field == "" { + continue + } + if v, ok := env[col.Field]; ok { + out[col.Name] = v + continue + } + if v := lookupPath(trace.Raw, col.Field); v != nil { + out[col.Name] = v + } + } + return out +} + +func parentID(doc map[string]any, profile TracingProfile) string { + if profile.Format == "jaeger" { + if refs, ok := doc["references"].([]any); ok { + for _, raw := range refs { + ref, _ := raw.(map[string]any) + if profile.ParentRefType != "" { + if stringValue(ref["refType"]) != profile.ParentRefType { + continue + } + } + if id := stringValue(firstPath(ref, "spanID", "span_id")); id != "" { + return id + } + } + } + } + return stringValue(firstPath(doc, profile.ParentIDField, "parent_id", "parentID")) +} + +func statusValue(doc map[string]any, attrs map[string]any, profile TracingProfile) string { + for _, field := range profile.StatusFields { + if v := stringValue(lookupPath(doc, field)); v != "" { + return v + } + if v := stringValue(attrs[field]); v != "" { + return v + } + } + for _, field := range []string{"status", "status.code", "tag.error", "error"} { + if v := stringValue(lookupPath(doc, field)); v != "" { + return v + } + if v := stringValue(attrs[field]); v != "" { + return v + } + } + return "" +} + +func buildTraceTree(flat []Trace) []Trace { + byID := map[string]*Trace{} + for i := range flat { + if flat[i].SpanID != "" { + byID[flat[i].SpanID] = &flat[i] + } + } + var roots []Trace + for i := range flat { + if flat[i].ParentID != "" { + if parent, ok := byID[flat[i].ParentID]; ok { + parent.Children = append(parent.Children, flat[i]) + continue + } + } + roots = append(roots, flat[i]) + } + if len(roots) == 0 { + return flat + } + return roots +} + +func flattenDocument(doc map[string]any) map[string]any { + out := map[string]any{} + var walk func(string, any) + walk = func(prefix string, value any) { + switch v := value.(type) { + case map[string]any: + for key, child := range v { + next := key + if prefix != "" { + next = prefix + "." + key + } + walk(next, child) + } + case []any: + if isJaegerTags(prefix, v) { + for _, raw := range v { + tag, _ := raw.(map[string]any) + key := stringValue(tag["key"]) + if key == "" { + continue + } + out["tag."+key] = firstPath(tag, "value", "vStr", "vDouble", "vBool", "vLong") + } + return + } + out[prefix] = v + default: + out[prefix] = v + } + } + walk("", doc) + return out +} + +func isJaegerTags(prefix string, values []any) bool { + if prefix != "tags" && prefix != "process.tags" { + return false + } + if len(values) == 0 { + return false + } + first, ok := values[0].(map[string]any) + if !ok { + return false + } + _, hasKey := first["key"] + return hasKey +} + +func firstPath(doc map[string]any, paths ...string) any { + for _, path := range paths { + if path == "" { + continue + } + if v := lookupPath(doc, path); v != nil { + return v + } + } + return nil +} + +func lookupPath(doc map[string]any, dotted string) any { + if doc == nil || dotted == "" { + return nil + } + if v, ok := doc[dotted]; ok { + return v + } + parts := strings.Split(dotted, ".") + var cur any = doc + for _, part := range parts { + switch typed := cur.(type) { + case map[string]any: + cur = typed[part] + case []any: + if len(typed) == 0 { + return nil + } + cur = typed[0] + if m, ok := cur.(map[string]any); ok { + cur = m[part] + } + default: + return nil + } + if cur == nil { + return nil + } + } + return cur +} + +func unwrapFieldValue(v any) any { + if arr, ok := v.([]any); ok && len(arr) == 1 { + return arr[0] + } + return v +} + +func stringValue(v any) string { + switch t := unwrapFieldValue(v).(type) { + case nil: + return "" + case string: + return t + case json.Number: + return t.String() + case float64: + if math.Trunc(t) == t { + return strconv.FormatInt(int64(t), 10) + } + return strconv.FormatFloat(t, 'f', -1, 64) + case bool: + return strconv.FormatBool(t) + default: + return fmt.Sprint(t) + } +} + +func durationMillis(v any) float64 { + switch t := unwrapFieldValue(v).(type) { + case float64: + if t > 1_000_000 { + return math.Round(t/10_000) / 100 + } + return t + case int: + return float64(t) + case string: + n, _ := strconv.ParseFloat(t, 64) + if n > 1_000_000 { + return math.Round(n/10_000) / 100 + } + return n + default: + return 0 + } +} + +func normalizeTimestamp(raw string) string { + if raw == "" { + return "" + } + if n, err := strconv.ParseInt(raw, 10, 64); err == nil { + if n > 10_000_000_000_000 { + return time.UnixMilli(n).Format(time.RFC3339Nano) + } + return time.Unix(n, 0).Format(time.RFC3339Nano) + } + if ts, err := time.Parse(time.RFC3339Nano, raw); err == nil { + return ts.Format(time.RFC3339Nano) + } + return raw +} + +func totalHits(hits map[string]any, fallback int) int { + total, ok := hits["total"].(map[string]any) + if !ok { + return fallback + } + switch v := total["value"].(type) { + case float64: + return int(v) + case int: + return v + default: + return fallback + } +} + +func cloneAnyMap(in map[string]any) map[string]any { + out := make(map[string]any, len(in)) + for k, v := range in { + out[k] = v + } + return out +} diff --git a/opensearch/parser_test.go b/opensearch/parser_test.go new file mode 100644 index 0000000..2cec94c --- /dev/null +++ b/opensearch/parser_test.go @@ -0,0 +1,43 @@ +package main + +import "testing" + +func TestParseJaegerSearchResult(t *testing.T) { + profile, err := defaultSettings().resolveProfile("jaeger") + if err != nil { + t.Fatal(err) + } + result := map[string]any{ + "hits": map[string]any{ + "total": map[string]any{"value": float64(1)}, + "hits": []any{ + map[string]any{ + "_source": map[string]any{ + "traceID": "t1", + "spanID": "s1", + "operationName": "GET /health", + "startTimeMillis": float64(1710000000000), + "duration": float64(123000), + "process": map[string]any{ + "serviceName": "api", + }, + "tags": []any{ + map[string]any{"key": "otel@status_code", "value": "OK"}, + }, + }, + }, + }, + }, + } + parsed := parseSearchResult(result, profile) + if parsed.Total != 1 || len(parsed.Traces) != 1 { + t.Fatalf("unexpected result: %#v", parsed) + } + trace := parsed.Traces[0] + if trace.TraceID != "t1" || trace.ServiceName != "api" || trace.OperationName != "GET /health" { + t.Fatalf("unexpected trace: %#v", trace) + } + if trace.Status != "OK" { + t.Fatalf("status = %q", trace.Status) + } +} diff --git a/opensearch/profile.go b/opensearch/profile.go new file mode 100644 index 0000000..c076c12 --- /dev/null +++ b/opensearch/profile.go @@ -0,0 +1,383 @@ +package main + +import ( + "embed" + "fmt" + "io/fs" + "path" + "sort" + "strings" + + "gopkg.in/yaml.v3" +) + +//go:embed profiles/*.yaml +var profileFS embed.FS + +type TracingProfile struct { + Name string `yaml:"name,omitempty" json:"name,omitempty"` + Hidden bool `yaml:"hidden,omitempty" json:"hidden,omitempty"` + Format string `yaml:"format,omitempty" json:"format,omitempty"` + Index string `yaml:"index,omitempty" json:"index,omitempty"` + DateField string `yaml:"dateField,omitempty" json:"dateField,omitempty"` + TraceIDField string `yaml:"traceIdField,omitempty" json:"traceIdField,omitempty"` + SpanIDField string `yaml:"spanIdField,omitempty" json:"spanIdField,omitempty"` + ParentIDField string `yaml:"parentIdField,omitempty" json:"parentIdField,omitempty"` + ParentRefType string `yaml:"parentRefType,omitempty" json:"parentRefType,omitempty"` + ServiceField string `yaml:"serviceField,omitempty" json:"serviceField,omitempty"` + OperationField string `yaml:"operationField,omitempty" json:"operationField,omitempty"` + StatusFields []string `yaml:"statusFields,omitempty" json:"statusFields,omitempty"` + SelectFields []string `yaml:"selectFields,omitempty" json:"selectFields,omitempty"` + SourceExcludes []string `yaml:"sourceExcludes,omitempty" json:"sourceExcludes,omitempty"` + Imports []string `yaml:"imports,omitempty" json:"imports,omitempty"` + Defaults map[string]any `yaml:"defaults,omitempty" json:"defaults,omitempty"` + Params map[string]TracingParam `yaml:"params,omitempty" json:"params,omitempty"` + Columns []TracingColumn `yaml:"columns,omitempty" json:"columns,omitempty"` +} + +type TracingParam struct { + Field string `yaml:"field,omitempty" json:"field,omitempty"` + Operator string `yaml:"operator,omitempty" json:"operator,omitempty"` + Clause string `yaml:"clause,omitempty" json:"clause,omitempty"` + Format string `yaml:"format,omitempty" json:"format,omitempty"` + Template string `yaml:"template,omitempty" json:"template,omitempty"` + Description string `yaml:"description,omitempty" json:"description,omitempty"` + Required bool `yaml:"required,omitempty" json:"required,omitempty"` + Internal bool `yaml:"internal,omitempty" json:"internal,omitempty"` +} + +type TracingColumn struct { + Name string `yaml:"name,omitempty" json:"name,omitempty"` + Field string `yaml:"field,omitempty" json:"field,omitempty"` + Detail bool `yaml:"detail,omitempty" json:"detail,omitempty"` +} + +type ProfileSummary struct { + Name string `json:"name"` + Format string `json:"format"` + Backend string `json:"backend"` + Index string `json:"index"` + Params []ProfileParam `json:"params"` + Columns []TracingColumn `json:"columns"` + Defaults map[string]any `json:"defaults"` + Profile *TracingProfile `json:"-"` +} + +type ProfileParam struct { + Name string `json:"name"` + Operator string `json:"operator"` + Description string `json:"description"` + Required bool `json:"required"` +} + +func defaultProfiles() map[string]TracingProfile { + entries, err := fs.ReadDir(profileFS, "profiles") + if err != nil { + panic(err) + } + out := make(map[string]TracingProfile, len(entries)) + for _, entry := range entries { + if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".yaml") { + continue + } + data, err := profileFS.ReadFile(path.Join("profiles", entry.Name())) + if err != nil { + panic(err) + } + var p TracingProfile + if err := yaml.Unmarshal(data, &p); err != nil { + panic(err) + } + if p.Name == "" { + p.Name = strings.TrimSuffix(entry.Name(), ".yaml") + } + out[p.Name] = p + } + return out +} + +func parseProfilesYAML(data []byte) (map[string]TracingProfile, error) { + var profiles map[string]TracingProfile + if err := yaml.Unmarshal(data, &profiles); err != nil { + var single TracingProfile + if err2 := yaml.Unmarshal(data, &single); err2 != nil { + return nil, fmt.Errorf("parse profilesYaml: %w", err) + } + if single.Name == "" { + return nil, fmt.Errorf("profilesYaml single profile requires name") + } + profiles = map[string]TracingProfile{single.Name: single} + } + for name, profile := range profiles { + if profile.Name == "" { + profile.Name = name + profiles[name] = profile + } + } + return profiles, nil +} + +func (s PluginSettings) resolveProfile(name string) (TracingProfile, error) { + if strings.TrimSpace(name) == "" { + name = s.DefaultProfile + } + defaults := defaultProfiles() + custom := s.Profiles + resolved := map[string]TracingProfile{} + visiting := map[string]bool{} + + var resolve func(string) (TracingProfile, error) + resolve = func(profileName string) (TracingProfile, error) { + if p, ok := resolved[profileName]; ok { + return p, nil + } + if visiting[profileName] { + return TracingProfile{}, fmt.Errorf("cyclic tracing profile import at %q", profileName) + } + visiting[profileName] = true + defer delete(visiting, profileName) + + base, hasDefault := defaults[profileName] + override, hasCustom := custom[profileName] + if !hasDefault && !hasCustom { + return TracingProfile{}, fmt.Errorf("tracing profile %q not found", profileName) + } + + profile := TracingProfile{Name: profileName} + for _, imported := range base.Imports { + p, err := resolve(imported) + if err != nil { + return TracingProfile{}, fmt.Errorf("resolve import %q for %q: %w", imported, profileName, err) + } + profile = mergeProfiles(profile, p) + } + profile = mergeProfiles(profile, base) + for _, imported := range override.Imports { + p, err := resolve(imported) + if err != nil { + return TracingProfile{}, fmt.Errorf("resolve import %q for %q: %w", imported, profileName, err) + } + profile = mergeProfiles(profile, p) + } + profile = mergeProfiles(profile, override) + if profile.Name == "" { + profile.Name = profileName + } + if s.Index != "" { + profile.Index = s.Index + } + profile = profile.withDefaults() + if err := profile.validate(); err != nil { + return TracingProfile{}, err + } + resolved[profileName] = profile + return profile, nil + } + return resolve(name) +} + +func (s PluginSettings) profileNames() []string { + names := map[string]struct{}{} + for name := range defaultProfiles() { + names[name] = struct{}{} + } + for name := range s.Profiles { + names[name] = struct{}{} + } + out := make([]string, 0, len(names)) + for name := range names { + p, err := s.resolveProfile(name) + if err == nil && !p.Hidden { + out = append(out, name) + } + } + sort.Slice(out, func(i, j int) bool { + leftDepth := strings.Count(out[i], ".") + rightDepth := strings.Count(out[j], ".") + if leftDepth != rightDepth { + return leftDepth < rightDepth + } + return out[i] < out[j] + }) + return out +} + +func (s PluginSettings) profileSummaries() ([]ProfileSummary, error) { + names := s.profileNames() + out := make([]ProfileSummary, 0, len(names)) + for _, name := range names { + profile, err := s.resolveProfile(name) + if err != nil { + return nil, err + } + params := make([]ProfileParam, 0, len(profile.Params)) + paramNames := make([]string, 0, len(profile.Params)) + for name, param := range profile.Params { + if !param.Internal { + paramNames = append(paramNames, name) + } + } + sort.Strings(paramNames) + for _, name := range paramNames { + param := profile.Params[name] + params = append(params, ProfileParam{ + Name: name, + Operator: firstNonEmpty(param.Operator, "term"), + Description: param.Description, + Required: param.Required, + }) + } + p := profile + out = append(out, ProfileSummary{ + Name: profile.Name, + Format: profile.Format, + Backend: "opensearch", + Index: profile.Index, + Params: params, + Columns: profile.Columns, + Defaults: cloneMap(profile.Defaults), + Profile: &p, + }) + } + return out, nil +} + +func (p TracingProfile) withDefaults() TracingProfile { + if p.Format == "" { + p.Format = "flat" + } + if p.Index == "" { + p.Index = "otel-traces-*" + } + if p.DateField == "" { + p.DateField = "@timestamp" + } + if p.TraceIDField == "" { + p.TraceIDField = "trace_id" + } + if p.SpanIDField == "" { + p.SpanIDField = "span_id" + } + if p.ParentIDField == "" { + p.ParentIDField = "parent_id" + } + if p.ServiceField == "" { + p.ServiceField = "service_name" + } + if p.OperationField == "" { + p.OperationField = "operation_name" + } + if p.Params == nil { + p.Params = map[string]TracingParam{} + } + if p.Defaults == nil { + p.Defaults = map[string]any{} + } + if len(p.Columns) == 0 { + p.Columns = []TracingColumn{ + {Name: "Time", Field: "timestamp"}, + {Name: "Service", Field: "service_name"}, + {Name: "Operation", Field: "operation_name"}, + {Name: "Status", Field: "status"}, + {Name: "Trace ID", Field: "trace_id"}, + } + } + return p +} + +func (p TracingProfile) validate() error { + if p.Name == "" { + return fmt.Errorf("tracing profile name is required") + } + if p.Index == "" { + return fmt.Errorf("tracing profile %q index is required", p.Name) + } + if p.DateField == "" { + return fmt.Errorf("tracing profile %q dateField is required", p.Name) + } + for name, param := range p.Params { + if param.Field == "" { + return fmt.Errorf("tracing profile %q param %q field is required", p.Name, name) + } + } + return nil +} + +func mergeProfiles(base, override TracingProfile) TracingProfile { + out := base + if override.Name != "" { + out.Name = override.Name + } + if override.Hidden { + out.Hidden = true + } + if override.Format != "" { + out.Format = override.Format + } + if override.Index != "" { + out.Index = override.Index + } + if override.DateField != "" { + out.DateField = override.DateField + } + if override.TraceIDField != "" { + out.TraceIDField = override.TraceIDField + } + if override.SpanIDField != "" { + out.SpanIDField = override.SpanIDField + } + if override.ParentIDField != "" { + out.ParentIDField = override.ParentIDField + } + if override.ParentRefType != "" { + out.ParentRefType = override.ParentRefType + } + if override.ServiceField != "" { + out.ServiceField = override.ServiceField + } + if override.OperationField != "" { + out.OperationField = override.OperationField + } + if len(override.StatusFields) > 0 { + out.StatusFields = append([]string(nil), override.StatusFields...) + } + if len(override.SelectFields) > 0 { + out.SelectFields = append([]string(nil), override.SelectFields...) + } + if len(override.SourceExcludes) > 0 { + out.SourceExcludes = append([]string(nil), override.SourceExcludes...) + } + if len(override.Columns) > 0 { + out.Columns = append([]TracingColumn(nil), override.Columns...) + } + if out.Defaults == nil { + out.Defaults = map[string]any{} + } + for k, v := range override.Defaults { + out.Defaults[k] = v + } + if out.Params == nil { + out.Params = map[string]TracingParam{} + } + for k, v := range override.Params { + out.Params[k] = v + } + return out +} + +func firstNonEmpty(values ...string) string { + for _, v := range values { + if v != "" { + return v + } + } + return "" +} + +func cloneMap(in map[string]any) map[string]any { + out := make(map[string]any, len(in)) + for k, v := range in { + out[k] = v + } + return out +} diff --git a/opensearch/profile_test.go b/opensearch/profile_test.go new file mode 100644 index 0000000..b0db192 --- /dev/null +++ b/opensearch/profile_test.go @@ -0,0 +1,47 @@ +package main + +import "testing" + +func TestResolveProfileIncludesDefaults(t *testing.T) { + profile, err := defaultSettings().resolveProfile("jaeger") + if err != nil { + t.Fatal(err) + } + if profile.Index != "jaeger-span*" { + t.Fatalf("index = %q", profile.Index) + } + if _, ok := profile.Params["trace_id"]; !ok { + t.Fatalf("trace_id param missing") + } +} + +func TestBuildTraceQueryRejectsUnknownFilter(t *testing.T) { + profile, err := defaultSettings().resolveProfile("otel") + if err != nil { + t.Fatal(err) + } + _, err = buildTraceQuery(QueryBuildOptions{Params: map[string]any{"missing": "x"}}, profile) + if err == nil { + t.Fatalf("expected unsupported filter error") + } +} + +func TestBuildTraceQueryUsesTermsForCSV(t *testing.T) { + profile := TracingProfile{ + Name: "test", + Index: "traces-*", + DateField: "@timestamp", + Params: map[string]TracingParam{ + "trace_id": {Field: "trace_id", Operator: "term"}, + }, + }.withDefaults() + query, err := buildTraceQuery(QueryBuildOptions{Params: map[string]any{"trace_id": "a,b"}}, profile) + if err != nil { + t.Fatal(err) + } + boolQuery := query["query"].(map[string]any)["bool"].(map[string]any) + filter := boolQuery["filter"].([]map[string]any) + if _, ok := filter[0]["terms"]; !ok { + t.Fatalf("expected terms query, got %#v", filter[0]) + } +} diff --git a/opensearch/profiles/jaeger.yaml b/opensearch/profiles/jaeger.yaml new file mode 100644 index 0000000..ba52e28 --- /dev/null +++ b/opensearch/profiles/jaeger.yaml @@ -0,0 +1,56 @@ +name: jaeger +format: jaeger +index: jaeger-span* +dateField: startTimeMillis +traceIdField: traceID +spanIdField: spanID +parentIdField: references.spanID +parentRefType: CHILD_OF +serviceField: process.serviceName +operationField: operationName +statusFields: + - tag.otel@status_code + - tag.error + - tag.error.message + - tag.exception.message +selectFields: + - traceID + - spanID + - operationName + - duration +params: + trace_id: + field: traceID + operator: term + description: Trace ID + span_id: + field: spanID + operator: term + description: Span ID + service: + field: process.serviceName + operator: term + description: Service name + operation: + field: operationName + operator: match_phrase + description: Operation name + status: + field: tag.otel@status_code + operator: term + description: Status code +columns: + - name: Time + field: timestamp + - name: Service + field: service_name + - name: Operation + field: operation_name + - name: Status + field: status + - name: Duration + field: duration_ms + - name: Trace ID + field: trace_id + - name: Span ID + field: span_id diff --git a/opensearch/profiles/otel.yaml b/opensearch/profiles/otel.yaml new file mode 100644 index 0000000..0832375 --- /dev/null +++ b/opensearch/profiles/otel.yaml @@ -0,0 +1,55 @@ +name: otel +format: flat +index: otel-traces-* +dateField: "@timestamp" +traceIdField: trace_id +spanIdField: span_id +parentIdField: parent_id +serviceField: service_name +operationField: operation_name +statusFields: + - status + - status.code + - attributes.error +selectFields: + - trace_id + - span_id + - parent_id + - service_name + - operation_name +params: + trace_id: + field: trace_id + operator: term + description: Trace ID + span_id: + field: span_id + operator: term + description: Span ID + service: + field: service_name + operator: term + description: Service name + operation: + field: operation_name + operator: match_phrase + description: Operation name + status: + field: status + operator: term + description: Status +columns: + - name: Time + field: timestamp + - name: Service + field: service_name + - name: Operation + field: operation_name + - name: Status + field: status + - name: Duration + field: duration_ms + - name: Trace ID + field: trace_id + - name: Span ID + field: span_id diff --git a/opensearch/query.go b/opensearch/query.go new file mode 100644 index 0000000..1c4bb09 --- /dev/null +++ b/opensearch/query.go @@ -0,0 +1,253 @@ +package main + +import ( + "fmt" + "sort" + "strings" +) + +const ( + clauseFilter = "filter" + clauseMust = "must" + clauseShould = "should" + clauseMustNot = "must_not" +) + +type QueryBuildOptions struct { + From string + To string + Params map[string]any +} + +type TraceQueryPreview struct { + Profile string `json:"profile"` + Request TraceQueryPreviewRequest `json:"request"` +} + +type TraceQueryPreviewRequest struct { + Index string `json:"index"` + Limit int `json:"limit"` + Query map[string]any `json:"query"` +} + +func buildQueryPreview(profile TracingProfile, req TraceQueryRequest) (TraceQueryPreview, error) { + limit := req.Limit + if limit <= 0 { + limit = 100 + } + query, err := buildTraceQuery(QueryBuildOptions{From: req.From, To: req.To, Params: req.Params}, profile) + if err != nil { + return TraceQueryPreview{}, err + } + return TraceQueryPreview{ + Profile: profile.Name, + Request: TraceQueryPreviewRequest{ + Index: profile.Index, + Limit: limit, + Query: query, + }, + }, nil +} + +func buildTraceQuery(opts QueryBuildOptions, profile TracingProfile) (map[string]any, error) { + queryParams, err := mergeQueryParams(profile, opts.Params) + if err != nil { + return nil, err + } + + boolClauses := map[string][]map[string]any{ + clauseFilter: {}, + clauseMust: {}, + clauseShould: {}, + clauseMustNot: {}, + } + + names := make([]string, 0, len(queryParams)) + for name := range queryParams { + names = append(names, name) + } + sort.Strings(names) + for _, name := range names { + param, ok := profile.Params[name] + if !ok { + return nil, fmt.Errorf("filter %q is not supported by tracing profile %q", name, profile.Name) + } + clauses, err := buildParamClauses(param, queryParams[name]) + if err != nil { + return nil, fmt.Errorf("build filter %q: %w", name, err) + } + bucket := firstNonEmpty(param.Clause, clauseFilter) + if _, ok := boolClauses[bucket]; !ok { + return nil, fmt.Errorf("unsupported clause %q for filter %q", bucket, name) + } + boolClauses[bucket] = append(boolClauses[bucket], clauses...) + } + + rangeQuery := map[string]any{} + if strings.TrimSpace(opts.From) != "" { + rangeQuery["gte"] = strings.TrimSpace(opts.From) + } + if strings.TrimSpace(opts.To) != "" { + rangeQuery["lte"] = strings.TrimSpace(opts.To) + } + if len(rangeQuery) > 0 { + rangeQuery["format"] = "strict_date_optional_time||epoch_millis" + boolClauses[clauseFilter] = append(boolClauses[clauseFilter], map[string]any{ + "range": map[string]any{profile.DateField: rangeQuery}, + }) + } + + query := map[string]any{ + "sort": []map[string]any{{profile.DateField: map[string]any{"order": "desc"}}}, + } + if len(profile.SelectFields) > 0 { + query["stored_fields"] = []string{"*"} + query["fields"] = profile.SelectFields + } + if profile.DateField != "" { + query["docvalue_fields"] = []map[string]any{{"field": profile.DateField, "format": "date_time"}} + } + if len(profile.SourceExcludes) > 0 { + query["_source"] = map[string]any{"excludes": profile.SourceExcludes} + } + + boolQuery := map[string]any{} + for _, bucket := range []string{clauseFilter, clauseMust, clauseShould, clauseMustNot} { + if len(boolClauses[bucket]) > 0 { + boolQuery[bucket] = boolClauses[bucket] + } + } + if len(boolQuery) > 0 { + if len(boolClauses[clauseShould]) > 0 { + boolQuery["minimum_should_match"] = 1 + } + query["query"] = map[string]any{"bool": boolQuery} + } else { + query["query"] = map[string]any{"match_all": map[string]any{}} + } + return query, nil +} + +func mergeQueryParams(profile TracingProfile, overrides map[string]any) (map[string]any, error) { + params := cloneMap(profile.Defaults) + for key, value := range overrides { + if isEmptyParamValue(value) { + continue + } + if param, ok := profile.Params[key]; ok && param.Internal { + return nil, fmt.Errorf("filter %q is internal to tracing profile %q", key, profile.Name) + } + params[key] = value + } + var missing []string + for name, param := range profile.Params { + if !param.Required { + continue + } + if isEmptyParamValue(params[name]) { + missing = append(missing, name) + } + } + if len(missing) > 0 { + sort.Strings(missing) + return nil, fmt.Errorf("tracing profile %q requires param(s): %s", profile.Name, strings.Join(missing, ", ")) + } + return params, nil +} + +func buildParamClauses(param TracingParam, value any) ([]map[string]any, error) { + values := normalizeParamValues(value) + if len(values) == 0 { + return nil, nil + } + formatted := make([]any, 0, len(values)) + for _, item := range values { + formatted = append(formatted, formatParamValue(param, item)) + } + switch firstNonEmpty(param.Operator, "term") { + case "term": + if len(formatted) > 1 { + return []map[string]any{{"terms": map[string]any{param.Field: formatted}}}, nil + } + return []map[string]any{{"term": map[string]any{param.Field: formatted[0]}}}, nil + case "terms": + return []map[string]any{{"terms": map[string]any{param.Field: formatted}}}, nil + case "match_phrase": + out := make([]map[string]any, 0, len(formatted)) + for _, item := range formatted { + out = append(out, map[string]any{"match_phrase": map[string]any{param.Field: item}}) + } + return out, nil + case "wildcard": + out := make([]map[string]any, 0, len(formatted)) + for _, item := range formatted { + out = append(out, map[string]any{"wildcard": map[string]any{param.Field: item}}) + } + return out, nil + case "query_string": + out := make([]map[string]any, 0, len(formatted)) + for _, item := range formatted { + out = append(out, map[string]any{"query_string": map[string]any{"fields": []string{param.Field}, "query": item}}) + } + return out, nil + case "exists": + return []map[string]any{{"exists": map[string]any{"field": param.Field}}}, nil + default: + return nil, fmt.Errorf("unsupported operator %q", param.Operator) + } +} + +func formatParamValue(param TracingParam, value any) any { + s, ok := value.(string) + if !ok { + return value + } + if param.Template != "" { + return strings.ReplaceAll(param.Template, "{value}", s) + } + return s +} + +func normalizeParamValues(value any) []any { + switch v := value.(type) { + case nil: + return nil + case []any: + return v + case []string: + out := make([]any, 0, len(v)) + for _, item := range v { + out = append(out, item) + } + return out + case string: + if strings.Contains(v, ",") { + parts := strings.Split(v, ",") + out := make([]any, 0, len(parts)) + for _, part := range parts { + if trimmed := strings.TrimSpace(part); trimmed != "" { + out = append(out, trimmed) + } + } + return out + } + return []any{v} + default: + return []any{v} + } +} + +func isEmptyParamValue(value any) bool { + switch v := value.(type) { + case nil: + return true + case string: + return strings.TrimSpace(v) == "" + case []any: + return len(v) == 0 + case []string: + return len(v) == 0 + default: + return false + } +} diff --git a/opensearch/ui-src/index.html b/opensearch/ui-src/index.html new file mode 100644 index 0000000..edd32ec --- /dev/null +++ b/opensearch/ui-src/index.html @@ -0,0 +1,12 @@ + + + + + + OpenSearch + + +
+ + + diff --git a/opensearch/ui-src/package.json b/opensearch/ui-src/package.json new file mode 100644 index 0000000..81cdf90 --- /dev/null +++ b/opensearch/ui-src/package.json @@ -0,0 +1,25 @@ +{ + "name": "@flanksource/opensearch-plugin-ui", + "private": true, + "version": "0.1.0", + "type": "module", + "scripts": { + "build": "tsc && vite build" + }, + "dependencies": { + "@flanksource/clicky-ui": "^0.2.1", + "@tanstack/react-query": "^5.90.11", + "@vitejs/plugin-react": "^5.1.0", + "lucide-react": "^0.553.0", + "vite": "^7.2.4", + "typescript": "^5.9.3", + "react": "^19.2.0", + "react-dom": "^19.2.0" + }, + "devDependencies": { + "@tailwindcss/vite": "^4.2.2", + "@types/react": "^19.2.7", + "@types/react-dom": "^19.2.3", + "tailwindcss": "^4.2.2" + } +} diff --git a/opensearch/ui-src/pnpm-lock.yaml b/opensearch/ui-src/pnpm-lock.yaml new file mode 100644 index 0000000..45f4a97 --- /dev/null +++ b/opensearch/ui-src/pnpm-lock.yaml @@ -0,0 +1,4465 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@flanksource/clicky-ui': + specifier: ^0.2.1 + version: 0.2.1(@tanstack/react-query@5.100.9(react@19.2.6))(@types/react@19.2.14)(@vue/compiler-sfc@3.5.33)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(tailwindcss@4.2.4)(typescript@5.9.3) + '@tanstack/react-query': + specifier: ^5.90.11 + version: 5.100.9(react@19.2.6) + '@vitejs/plugin-react': + specifier: ^5.1.0 + version: 5.2.0(vite@7.3.3(@types/node@24.12.3)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.4)) + lucide-react: + specifier: ^0.553.0 + version: 0.553.0(react@19.2.6) + react: + specifier: ^19.2.0 + version: 19.2.6 + react-dom: + specifier: ^19.2.0 + version: 19.2.6(react@19.2.6) + typescript: + specifier: ^5.9.3 + version: 5.9.3 + vite: + specifier: ^7.2.4 + version: 7.3.3(@types/node@24.12.3)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.4) + devDependencies: + '@tailwindcss/vite': + specifier: ^4.2.2 + version: 4.2.4(vite@7.3.3(@types/node@24.12.3)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.4)) + '@types/react': + specifier: ^19.2.7 + version: 19.2.14 + '@types/react-dom': + specifier: ^19.2.3 + version: 19.2.3(@types/react@19.2.14) + tailwindcss: + specifier: ^4.2.2 + version: 4.2.4 + +packages: + + '@ai-sdk/gateway@3.0.13': + resolution: {integrity: sha512-g7nE4PFtngOZNZSy1lOPpkC+FAiHxqBJXqyRMEG7NUrEVZlz5goBdtHg1YgWRJIX776JTXAmbOI5JreAKVAsVA==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + + '@ai-sdk/provider-utils@4.0.5': + resolution: {integrity: sha512-Ow/X/SEkeExTTc1x+nYLB9ZHK2WUId8+9TlkamAx7Tl9vxU+cKzWx2dwjgMHeCN6twrgwkLrrtqckQeO4mxgVA==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + + '@ai-sdk/provider@3.0.2': + resolution: {integrity: sha512-HrEmNt/BH/hkQ7zpi2o6N3k1ZR1QTb7z85WYhYygiTxOQuaml4CMtHCWRbric5WPU+RNsYI7r1EpyVQMKO1pYw==} + engines: {node: '>=18'} + + '@ai-sdk/vue@3.0.33': + resolution: {integrity: sha512-czM9Js3a7f+Eo35gjEYEeJYUoPvMg5Dfi4bOLyDBghLqn0gaVg8yTmTaSuHCg+3K/+1xPjyXd4+2XcQIohWWiQ==} + engines: {node: '>=18'} + peerDependencies: + vue: ^3.3.4 + + '@babel/code-frame@7.29.0': + resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.29.3': + resolution: {integrity: sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.29.0': + resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.29.1': + resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.28.6': + resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.28.6': + resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.28.6': + resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-plugin-utils@7.28.6': + resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.27.1': + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.29.2': + resolution: {integrity: sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.3': + resolution: {integrity: sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-transform-react-jsx-self@7.27.1': + resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-source@7.27.1': + resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/template@7.28.6': + resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.29.0': + resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.29.0': + resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} + engines: {node: '>=6.9.0'} + + '@codemirror/autocomplete@6.20.1': + resolution: {integrity: sha512-1cvg3Vz1dSSToCNlJfRA2WSI4ht3K+WplO0UMOgmUYPivCyy2oueZY6Lx7M9wThm7SDUBViRmuT+OG/i8+ON9A==} + + '@codemirror/commands@6.10.3': + resolution: {integrity: sha512-JFRiqhKu+bvSkDLI+rUhJwSxQxYb759W5GBezE8Uc8mHLqC9aV/9aTC7yJSqCtB3F00pylrLCwnyS91Ap5ej4Q==} + + '@codemirror/lang-css@6.3.1': + resolution: {integrity: sha512-kr5fwBGiGtmz6l0LSJIbno9QrifNMUusivHbnA1H6Dmqy4HZFte3UAICix1VuKo0lMPKQr2rqB+0BkKi/S3Ejg==} + + '@codemirror/lang-html@6.4.11': + resolution: {integrity: sha512-9NsXp7Nwp891pQchI7gPdTwBuSuT3K65NGTHWHNJ55HjYcHLllr0rbIZNdOzas9ztc1EUVBlHou85FFZS4BNnw==} + + '@codemirror/lang-javascript@6.2.5': + resolution: {integrity: sha512-zD4e5mS+50htS7F+TYjBPsiIFGanfVqg4HyUz6WNFikgOPf2BgKlx+TQedI1w6n/IqRBVBbBWmGFdLB/7uxO4A==} + + '@codemirror/lang-json@6.0.2': + resolution: {integrity: sha512-x2OtO+AvwEHrEwR0FyyPtfDUiloG3rnVTSZV1W8UteaLL8/MajQd8DpvUb2YVzC+/T18aSDv0H9mu+xw0EStoQ==} + + '@codemirror/lang-xml@6.1.0': + resolution: {integrity: sha512-3z0blhicHLfwi2UgkZYRPioSgVTo9PV5GP5ducFH6FaHy0IAJRg+ixj5gTR1gnT/glAIC8xv4w2VL1LoZfs+Jg==} + + '@codemirror/lang-yaml@6.1.3': + resolution: {integrity: sha512-AZ8DJBuXGVHybpBQhmZtgew5//4hv3tdkXnr3vDmOUMJRuB6vn/uuwtmTOTlqEaQFg3hQSVeA90NmvIQyUV6FQ==} + + '@codemirror/language@6.12.3': + resolution: {integrity: sha512-QwCZW6Tt1siP37Jet9Tb02Zs81TQt6qQrZR2H+eGMcFsL1zMrk2/b9CLC7/9ieP1fjIUMgviLWMmgiHoJrj+ZA==} + + '@codemirror/lint@6.9.5': + resolution: {integrity: sha512-GElsbU9G7QT9xXhpUg1zWGmftA/7jamh+7+ydKRuT0ORpWS3wOSP0yT1FOlIZa7mIJjpVPipErsyvVqB9cfTFA==} + + '@codemirror/state@6.6.0': + resolution: {integrity: sha512-4nbvra5R5EtiCzr9BTHiTLc+MLXK2QGiAVYMyi8PkQd3SR+6ixar/Q/01Fa21TBIDOZXgeWV4WppsQolSreAPQ==} + + '@codemirror/view@6.41.1': + resolution: {integrity: sha512-ToDnWKbBnke+ZLrP6vgTTDScGi5H37YYuZGniQaBzxMVdtCxMrslsmtnOvbPZk4RX9bvkQqnWR/WS/35tJA0qg==} + + '@esbuild/aix-ppc64@0.27.7': + resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.27.7': + resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.27.7': + resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.27.7': + resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.27.7': + resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.27.7': + resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.27.7': + resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.27.7': + resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.27.7': + resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.27.7': + resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.27.7': + resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.27.7': + resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.27.7': + resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.27.7': + resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.27.7': + resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.27.7': + resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.27.7': + resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.27.7': + resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.27.7': + resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.27.7': + resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.27.7': + resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.27.7': + resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.27.7': + resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.27.7': + resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.27.7': + resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.27.7': + resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@flanksource/clicky-ui@0.2.1': + resolution: {integrity: sha512-FEAv1a6UzG2A2+MvO3qYOQvyE75znPFDIncRIMgA7QUDs08pAJRzYXZcIhFI7euDV6KTTZ9tBuTO5TEe4svWSA==} + peerDependencies: + '@shikijs/transformers': ^1.24.0 + '@tanstack/react-query': ^5.0.0 + marked: ^15.0.0 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + shiki: ^1.24.0 + tailwindcss: ^3.4.0 + peerDependenciesMeta: + '@shikijs/transformers': + optional: true + '@tanstack/react-query': + optional: true + marked: + optional: true + shiki: + optional: true + + '@floating-ui/core@1.7.5': + resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==} + + '@floating-ui/dom@1.7.6': + resolution: {integrity: sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==} + + '@floating-ui/utils@0.2.10': + resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} + + '@floating-ui/utils@0.2.11': + resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} + + '@floating-ui/vue@1.1.11': + resolution: {integrity: sha512-HzHKCNVxnGS35r9fCHBc3+uCnjw9IWIlCPL683cGgM9Kgj2BiAl8x1mS7vtvP6F9S/e/q4O6MApwSHj8hNLGfw==} + + '@floating-ui/vue@1.1.9': + resolution: {integrity: sha512-BfNqNW6KA83Nexspgb9DZuz578R7HT8MZw1CfK9I6Ah4QReNWEJsXWHN+SdmOVLNGmTPDi+fDT535Df5PzMLbQ==} + + '@headlessui/tailwindcss@0.2.2': + resolution: {integrity: sha512-xNe42KjdyA4kfUKLLPGzME9zkH7Q3rOZ5huFihWNWOQFxnItxPB3/67yBI8/qBfY8nwBRx5GHn4VprsoluVMGw==} + engines: {node: '>=10'} + peerDependencies: + tailwindcss: ^3.0 || ^4.0 + + '@headlessui/vue@1.7.23': + resolution: {integrity: sha512-JzdCNqurrtuu0YW6QaDtR2PIYCKPUWq28csDyMvN4zmGccmE7lz40Is6hc3LA4HFeCI7sekZ/PQMTNmn9I/4Wg==} + engines: {node: '>=10'} + peerDependencies: + vue: ^3.2.0 + + '@iconify/react@5.2.1': + resolution: {integrity: sha512-37GDR3fYDZmnmUn9RagyaX+zca24jfVOMY8E1IXTqJuE8pxNtN51KWPQe3VODOWvuUurq7q9uUu3CFrpqj5Iqg==} + peerDependencies: + react: '>=16' + + '@iconify/types@2.0.0': + resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} + + '@internationalized/date@3.12.1': + resolution: {integrity: sha512-6IedsVWXyq4P9Tj+TxuU8WGWM70hYLl12nbYU8jkikVpa6WXapFazPUcHUMDMoWftIDE2ILDkFFte6W2nFCkRQ==} + + '@internationalized/number@3.6.6': + resolution: {integrity: sha512-iFgmQaXHE0vytNfpLZWOC2mEJCBRzcUxt53Xf/yCXG93lRvqas237i3r7X4RKMwO3txiyZD4mQjKAByFv6UGSQ==} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@lezer/common@1.5.2': + resolution: {integrity: sha512-sxQE460fPZyU3sdc8lafxiPwJHBzZRy/udNFynGQky1SePYBdhkBl1kOagA9uT3pxR8K09bOrmTUqA9wb/PjSQ==} + + '@lezer/css@1.3.3': + resolution: {integrity: sha512-RzBo8r+/6QJeow7aPHIpGVIH59xTcJXp399820gZoMo9noQDRVpJLheIBUicYwKcsbOYoBRoLZlf2720dG/4Tg==} + + '@lezer/highlight@1.2.3': + resolution: {integrity: sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==} + + '@lezer/html@1.3.13': + resolution: {integrity: sha512-oI7n6NJml729m7pjm9lvLvmXbdoMoi2f+1pwSDJkl9d68zGr7a9Btz8NdHTGQZtW2DA25ybeuv/SyDb9D5tseg==} + + '@lezer/javascript@1.5.4': + resolution: {integrity: sha512-vvYx3MhWqeZtGPwDStM2dwgljd5smolYD2lR2UyFcHfxbBQebqx8yjmFmxtJ/E6nN6u1D9srOiVWm3Rb4tmcUA==} + + '@lezer/json@1.0.3': + resolution: {integrity: sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==} + + '@lezer/lr@1.4.10': + resolution: {integrity: sha512-rnCpTIBafOx4mRp43xOxDJbFipJm/c0cia/V5TiGlhmMa+wsSdoGmUN3w5Bqrks/09Q/D4tNAmWaT8p6NRi77A==} + + '@lezer/xml@1.0.6': + resolution: {integrity: sha512-CdDwirL0OEaStFue/66ZmFSeppuL6Dwjlk8qk153mSQwiSH/Dlri4GNymrNWnUmPl2Um7QfV1FO9KFUyX3Twww==} + + '@lezer/yaml@1.0.4': + resolution: {integrity: sha512-2lrrHqxalACEbxIbsjhqGpSW8kWpUKuY6RHgnSAFZa6qK62wvnPxA8hGOwOoDbwHcOFs5M4o27mjGu+P7TvBmw==} + + '@marijn/find-cluster-break@1.0.2': + resolution: {integrity: sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==} + + '@opentelemetry/api@1.9.0': + resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} + engines: {node: '>=8.0.0'} + + '@phosphor-icons/core@2.1.1': + resolution: {integrity: sha512-v4ARvrip4qBCImOE5rmPUylOEK4iiED9ZyKjcvzuezqMaiRASCHKcRIuvvxL/twvLpkfnEODCOJp5dM4eZilxQ==} + + '@radix-ui/react-compose-refs@1.1.2': + resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-slot@1.2.4': + resolution: {integrity: sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@replit/codemirror-css-color-picker@6.3.0': + resolution: {integrity: sha512-19biDANghUm7Fz7L1SNMIhK48tagaWuCOHj4oPPxc7hxPGkTVY2lU/jVZ8tsbTKQPVG7BO2CBDzs7CBwb20t4A==} + peerDependencies: + '@codemirror/language': ^6.0.0 + '@codemirror/state': ^6.0.0 + '@codemirror/view': ^6.0.0 + + '@rolldown/pluginutils@1.0.0-rc.3': + resolution: {integrity: sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==} + + '@rollup/rollup-android-arm-eabi@4.60.3': + resolution: {integrity: sha512-x35CNW/ANXG3hE/EZpRU8MXX1JDN86hBb2wMGAtltkz7pc6cxgjpy1OMMfDosOQ+2hWqIkag/fGok1Yady9nGw==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.60.3': + resolution: {integrity: sha512-xw3xtkDApIOGayehp2+Rz4zimfkaX65r4t47iy+ymQB2G4iJCBBfj0ogVg5jpvjpn8UWn/+q9tprxleYeNp3Hw==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.60.3': + resolution: {integrity: sha512-vo6Y5Qfpx7/5EaamIwi0WqW2+zfiusVihKatLvtN1VFVy3D13uERk/6gZLU1UiHRL6fDXqj/ELIeVRGnvcTE1g==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.60.3': + resolution: {integrity: sha512-D+0QGcZhBzTN82weOnsSlY7V7+RMmPuF1CkbxyMAGE8+ZHeUjyb76ZiWmBlCu//AQQONvxcqRbwZTajZKqjuOw==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.60.3': + resolution: {integrity: sha512-6HnvHCT7fDyj6R0Ph7A6x8dQS/S38MClRWeDLqc0MdfWkxjiu1HSDYrdPhqSILzjTIC/pnXbbJbo+ft+gy/9hQ==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.60.3': + resolution: {integrity: sha512-KHLgC3WKlUYW3ShFKnnosZDOJ0xjg9zp7au3sIm2bs/tGBeC2ipmvRh/N7JKi0t9Ue20C0dpEshi8WUubg+cnA==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.60.3': + resolution: {integrity: sha512-DV6fJoxEYWJOvaZIsok7KrYl0tPvga5OZ2yvKHNNYyk/2roMLqQAbGhr78EQ5YhHpnhLKJD3S1WFusAkmUuV5g==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.60.3': + resolution: {integrity: sha512-mQKoJAzvuOs6F+TZybQO4GOTSMUu7v0WdxEk24krQ/uUxXoPTtHjuaUuPmFhtBcM4K0ons8nrE3JyhTuCFtT/w==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.60.3': + resolution: {integrity: sha512-Whjj2qoiJ6+OOJMGptTYazaJvjOJm+iKHpXQM1P3LzGjt7Ff++Tp7nH4N8J/BUA7R9IHfDyx4DJIflifwnbmIA==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.60.3': + resolution: {integrity: sha512-4YTNHKqGng5+yiZt3mg77nmyuCfmNfX4fPmyUapBcIk+BdwSwmCWGXOUxhXbBEkFHtoN5boLj/5NON+u5QC9tg==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loong64-gnu@4.60.3': + resolution: {integrity: sha512-SU3kNlhkpI4UqlUc2VXPGK9o886ZsSeGfMAX2ba2b8DKmMXq4AL7KUrkSWVbb7koVqx41Yczx6dx5PNargIrEA==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-loong64-musl@4.60.3': + resolution: {integrity: sha512-6lDLl5h4TXpB1mTf2rQWnAk/LcXrx9vBfu/DT5TIPhvMhRWaZ5MxkIc8u4lJAmBo6klTe1ywXIUHFjylW505sg==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.60.3': + resolution: {integrity: sha512-BMo8bOw8evlup/8G+cj5xWtPyp93xPdyoSN16Zy90Q2QZ0ZYRhCt6ZJSwbrRzG9HApFabjwj2p25TUPDWrhzqQ==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-ppc64-musl@4.60.3': + resolution: {integrity: sha512-E0L8X1dZN1/Rph+5VPF6Xj2G7JJvMACVXtamTJIDrVI44Y3K+G8gQaMEAavbqCGTa16InptiVrX6eM6pmJ+7qA==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.60.3': + resolution: {integrity: sha512-oZJ/WHaVfHUiRAtmTAeo3DcevNsVvH8mbvodjZy7D5QKvCefO371SiKRpxoDcCxB3PTRTLayWBkvmDQKTcX/sw==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.60.3': + resolution: {integrity: sha512-Dhbyh7j9FybM3YaTgaHmVALwA8AkUwTPccyCQ79TG9AJUsMQqgN1DDEZNr4+QUfwiWvLDumW5vdwzoeUF+TNxQ==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.60.3': + resolution: {integrity: sha512-cJd1X5XhHHlltkaypz1UcWLA8AcoIi1aWhsvaWDskD1oz2eKCypnqvTQ8ykMNI0RSmm7NkTdSqSSD7zM0xa6Ig==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.60.3': + resolution: {integrity: sha512-DAZDBHQfG2oQuhY7mc6I3/qB4LU2fQCjRvxbDwd/Jdvb9fypP4IJ4qmtu6lNjes6B531AI8cg1aKC2di97bUxA==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.60.3': + resolution: {integrity: sha512-cRxsE8c13mZOh3vP+wLDxpQBRrOHDIGOWyDL93Sy0Ga8y515fBcC2pjUfFwUe5T7tqvTvWbCpg1URM/AXdWIXA==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-openbsd-x64@4.60.3': + resolution: {integrity: sha512-QaWcIgRxqEdQdhJqW4DJctsH6HCmo5vHxY0krHSX4jMtOqfzC+dqDGuHM87bu4H8JBeibWx7jFz+h6/4C8wA5Q==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.60.3': + resolution: {integrity: sha512-AaXwSvUi3QIPtroAUw1t5yHGIyqKEXwH54WUocFolZhpGDruJcs8c+xPNDRn4XiQsS7MEwnYsHW2l0MBLDMkWg==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.60.3': + resolution: {integrity: sha512-65LAKM/bAWDqKNEelHlcHvm2V+Vfb8C6INFxQXRHCvaVN1rJfwr4NvdP4FyzUaLqWfaCGaadf6UbTm8xJeYfEg==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.60.3': + resolution: {integrity: sha512-EEM2gyhBF5MFnI6vMKdX1LAosE627RGBzIoGMdLloPZkXrUN0Ckqgr2Qi8+J3zip/8NVVro3/FjB+tjhZUgUHA==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.60.3': + resolution: {integrity: sha512-E5Eb5H/DpxaoXH++Qkv28RcUJboMopmdDUALBczvHMf7hNIxaDZqwY5lK12UK1BHacSmvupoEWGu+n993Z0y1A==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.60.3': + resolution: {integrity: sha512-hPt/bgL5cE+Qp+/TPHBqptcAgPzgj46mPcg/16zNUmbQk0j+mOEQV/+Lqu8QRtDV3Ek95Q6FeFITpuhl6OTsAA==} + cpu: [x64] + os: [win32] + + '@scalar/agent-chat@0.10.14': + resolution: {integrity: sha512-b92iQVZt2aXG6jzfFrovOzoKkjuSIuMo8mLCuWuo6q/0GeQRkdLWz4DTaNBpaNv7J6AoptfGj8hAaA6W5PyRXw==} + engines: {node: '>=22'} + + '@scalar/api-client@3.6.0': + resolution: {integrity: sha512-6W5c5BFAkCcwlQdhyhfSaVo4+Hfz8bZxjgLMl6HCgxBzjU2iiRPSPpkIB3+BGo+dxaIRCLoWXh/vTfYR+hA02w==} + engines: {node: '>=22'} + + '@scalar/api-reference-react@0.9.33': + resolution: {integrity: sha512-fxR1FFLahw1uazyi/NVFos+4MsEcJNWWM+YecdgkwdTExJ/RGNPakAniFnAmgVOFbu1WWzQlpAMhebwVFrxb9Q==} + engines: {node: '>=22'} + peerDependencies: + react: ^18.0.0 || ^19.0.0 + + '@scalar/api-reference@1.55.2': + resolution: {integrity: sha512-/AUWMBOqBg1AgMewuat6/hm1GNA1pgxIISHCjfDh3/XpLRKSqYCS5VwjDYNe23sOrovWsh+h/D1YK6On3Pxfwg==} + engines: {node: '>=22'} + + '@scalar/code-highlight@0.3.4': + resolution: {integrity: sha512-gGr3D8bfInwZDHsxamYIaG72Wr+kRNX8d4zcOflAfQJ0ZfvqoVbYhhkiSd6K+DLySItK9lWl/cgjJdtKWlT2ig==} + engines: {node: '>=22'} + + '@scalar/components@0.24.2': + resolution: {integrity: sha512-Llht48QpeT2ju4fGZWItCvl3KgZLFuWt70Sfzak2JXNvqHkLNlnUYl8isEzwGcQFfhG/tCwVghCAAMwkjFSTXA==} + engines: {node: '>=22'} + + '@scalar/helpers@0.6.0': + resolution: {integrity: sha512-pfSamAgBxqFeE8IpEG6uGkHlnPhY1CLeOTttV9+vKQbrBk5b7vvyTsUXv0Hz4kNU1TFrxcTTPE+Akn5S+jlTtQ==} + engines: {node: '>=22'} + + '@scalar/icons@0.7.2': + resolution: {integrity: sha512-21L2y/D6oU7wZHHa9i6FK98cZ+XH4HX9+e69uNpvlp4awRUpz6ifNHOLlxI607bq+Yz4G313gnV0uyUHwZ/pig==} + engines: {node: '>=22'} + + '@scalar/json-magic@0.12.12': + resolution: {integrity: sha512-F7q6mPlVdHntvEvlJPwzvA2E2fjxsNtMeSzODtcdhp4mdQndMqqxEhy0rKmRvk36Oka+9F/hl3EDG194BpNBGg==} + engines: {node: '>=22'} + + '@scalar/oas-utils@0.15.2': + resolution: {integrity: sha512-7ngu7ieNO8YUfEYEXcrJBIBbytjoq8HIATOJqxykZvUz0Vm5ttOgONSaAOXB19gE6t5xUl4A156MkjenOEwK6Q==} + engines: {node: '>=22'} + + '@scalar/openapi-types@0.8.0': + resolution: {integrity: sha512-WmaxVSfvY5K/TwcG2B2TU1WOe1As1uc2s7myswtP6dBlcjU3hM08SApxv/jmyGaCE8t4gO5BBhmHY4pDUfmr2g==} + engines: {node: '>=22'} + + '@scalar/openapi-upgrader@0.2.7': + resolution: {integrity: sha512-sC/uLQOivfX+Oef2QhUpgmERL7KZc1z+hiYkcwZQaUyVOHh5e6OscW0skfzbxKPyJfQ6Ocv0Iom9wMToCGaAPw==} + engines: {node: '>=22'} + + '@scalar/postman-to-openapi@0.7.5': + resolution: {integrity: sha512-H6cTuD28XXeqSP2SEjmsJDaMKC/a95Jxr10qYyLyZ3Tc8jzQO7iVDn04PXDUUsFGyQ74x1txWq2JlckV3CHaZQ==} + engines: {node: '>=22'} + + '@scalar/sidebar@0.9.10': + resolution: {integrity: sha512-lQG775TDRAbHe/Y6BNDI53tb8Rhigq4n4mw2f83EuBy+6w8SQC4Ib81HZyPY0O+n3La0qyYuXOzl8douboATsg==} + engines: {node: '>=22'} + + '@scalar/snippetz@0.9.6': + resolution: {integrity: sha512-s2Rso+qajyyf9DBzIgt+T3HZ1Ewx1W+YOUdYg1ldJhlXjBtn0q1w6gbnv4C2HHCgXRh/6YIzIj7eDUWK9K3+sQ==} + engines: {node: '>=22'} + + '@scalar/themes@0.15.3': + resolution: {integrity: sha512-KIGMVglWKxVcdPsdjiXDgyAYhCh53w0qoKRG/cmfP+N4OwR0pk0WzFaMzBscu+sKoZ8SMvZqbXyODO5CBtyD3w==} + engines: {node: '>=22'} + + '@scalar/typebox@0.1.3': + resolution: {integrity: sha512-lU055AUccECZMIfGA0z/C1StYmboAYIPJLDFBzOO81yXBi35Pxdq+I4fWX6iUZ8qcoHneiLGk9jAUM1rA93iEg==} + + '@scalar/types@0.9.6': + resolution: {integrity: sha512-UaCQQcscFTJdxZREE8KhUdSJgaDlc44TZbmWcZffs4m1hzqOvEI7lEBS13iBpLq7/cxUXFgyJdecywvNqJ0PkA==} + engines: {node: '>=22'} + + '@scalar/use-codemirror@0.14.11': + resolution: {integrity: sha512-5wtC4pUjzhy72j3aAueJg+fh9KflevJvXMn0YscsxiDTvqwIzeZcHe1N9VNtvzDXgLblEeBT6D0+Vs+boyExxg==} + engines: {node: '>=22'} + + '@scalar/use-hooks@0.4.3': + resolution: {integrity: sha512-dhDWGwqtiVshrAv/bpJ9qPt2Mdbbqyqvtvl2Fau+S9iv7Trsc2XDbfBc40cckSj6EhajgR4EHiuCR0E4DyaveQ==} + engines: {node: '>=22'} + + '@scalar/use-toasts@0.10.2': + resolution: {integrity: sha512-1iHQFbDXv0YQRp13aa63S5EcTJ5K8T0ocnLxk+nziloPrLjKt6jdRt6vOHsLSv5sm9kFKcVKNQTQgialmKCOGA==} + engines: {node: '>=22'} + + '@scalar/validation@0.3.2': + resolution: {integrity: sha512-iepw5zfpne2mNsCQdN/pST4HEfGwp7LMTb/f1sRuIN25SEXbdeUDvZnk1eoEPxol2TgGJUR3QXfaHQ4f8p6wHw==} + engines: {node: '>=20'} + + '@scalar/workspace-store@0.49.2': + resolution: {integrity: sha512-1kOWtqFUwx1EI0f9ceiD/5q3OOlu4ioS4oRi8f35NTEzVwDcf9RTzQuUuTSzFku47Iv6hdfTFpPm1y3TMr6j+Q==} + engines: {node: '>=22'} + + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + + '@swc/helpers@0.5.21': + resolution: {integrity: sha512-jI/VAmtdjB/RnI8GTnokyX7Ug8c+g+ffD6QRLa6XQewtnGyukKkKSk3wLTM3b5cjt1jNh9x0jfVlagdN2gDKQg==} + + '@tailwindcss/node@4.2.4': + resolution: {integrity: sha512-Ai7+yQPxz3ddrDQzFfBKdHEVBg0w3Zl83jnjuwxnZOsnH9pGn93QHQtpU0p/8rYWxvbFZHneni6p1BSLK4DkGA==} + + '@tailwindcss/oxide-android-arm64@4.2.4': + resolution: {integrity: sha512-e7MOr1SAn9U8KlZzPi1ZXGZHeC5anY36qjNwmZv9pOJ8E4Q6jmD1vyEHkQFmNOIN7twGPEMXRHmitN4zCMN03g==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.2.4': + resolution: {integrity: sha512-tSC/Kbqpz/5/o/C2sG7QvOxAKqyd10bq+ypZNf+9Fi2TvbVbv1zNpcEptcsU7DPROaSbVgUXmrzKhurFvo5eDg==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.2.4': + resolution: {integrity: sha512-yPyUXn3yO/ufR6+Kzv0t4fCg2qNr90jxXc5QqBpjlPNd0NqyDXcmQb/6weunH/MEDXW5dhyEi+agTDiqa3WsGg==} + engines: {node: '>= 20'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.2.4': + resolution: {integrity: sha512-BoMIB4vMQtZsXdGLVc2z+P9DbETkiopogfWZKbWwM8b/1Vinbs4YcUwo+kM/KeLkX3Ygrf4/PsRndKaYhS8Eiw==} + engines: {node: '>= 20'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.4': + resolution: {integrity: sha512-7pIHBLTHYRAlS7V22JNuTh33yLH4VElwKtB3bwchK/UaKUPpQ0lPQiOWcbm4V3WP2I6fNIJ23vABIvoy2izdwA==} + engines: {node: '>= 20'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.2.4': + resolution: {integrity: sha512-+E4wxJ0ZGOzSH325reXTWB48l42i93kQqMvDyz5gqfRzRZ7faNhnmvlV4EPGJU3QJM/3Ab5jhJ5pCRUsKn6OQw==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-musl@4.2.4': + resolution: {integrity: sha512-bBADEGAbo4ASnppIziaQJelekCxdMaxisrk+fB7Thit72IBnALp9K6ffA2G4ruj90G9XRS2VQ6q2bCKbfFV82g==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-gnu@4.2.4': + resolution: {integrity: sha512-7Mx25E4WTfnht0TVRTyC00j3i0M+EeFe7wguMDTlX4mRxafznw0CA8WJkFjWYH5BlgELd1kSjuU2JiPnNZbJDA==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-musl@4.2.4': + resolution: {integrity: sha512-2wwJRF7nyhOR0hhHoChc04xngV3iS+akccHTGtz965FwF0up4b2lOdo6kI1EbDaEXKgvcrFBYcYQQ/rrnWFVfA==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-wasm32-wasi@4.2.4': + resolution: {integrity: sha512-FQsqApeor8Fo6gUEklzmaa9994orJZZDBAlQpK2Mq+DslRKFJeD6AjHpBQ0kZFQohVr8o85PPh8eOy86VlSCmw==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.2.4': + resolution: {integrity: sha512-L9BXqxC4ToVgwMFqj3pmZRqyHEztulpUJzCxUtLjobMCzTPsGt1Fa9enKbOpY2iIyVtaHNeNvAK8ERP/64sqGQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.2.4': + resolution: {integrity: sha512-ESlKG0EpVJQwRjXDDa9rLvhEAh0mhP1sF7sap9dNZT0yyl9SAG6T7gdP09EH0vIv0UNTlo6jPWyujD6559fZvw==} + engines: {node: '>= 20'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.2.4': + resolution: {integrity: sha512-9El/iI069DKDSXwTvB9J4BwdO5JhRrOweGaK25taBAvBXyXqJAX+Jqdvs8r8gKpsI/1m0LeJLyQYTf/WLrBT1Q==} + engines: {node: '>= 20'} + + '@tailwindcss/vite@4.2.4': + resolution: {integrity: sha512-pCvohwOCspk3ZFn6eJzrrX3g4n2JY73H6MmYC87XfGPyTty4YsCjYTMArRZm/zOI8dIt3+EcrLHAFPe5A4bgtw==} + peerDependencies: + vite: ^5.2.0 || ^6 || ^7 || ^8 + + '@tanstack/query-core@5.100.9': + resolution: {integrity: sha512-SJSFw1S8+kQ0+knv/XGfrbocWoAlT7vDKsSImtLx3ZPQmEcR46hkDjLSvynSy25N8Ms4tIEini1FuBd5k7IscQ==} + + '@tanstack/react-query@5.100.9': + resolution: {integrity: sha512-Oa44XkaI3kCNN6ME0KByU3xT3SEUNOMfZpHxL6+wFoTm+OeUFYHKdeYVe0aOXlRDm/f15sgLwEt2HDorIdW8+A==} + peerDependencies: + react: ^18 || ^19 + + '@tanstack/virtual-core@3.14.0': + resolution: {integrity: sha512-JLANqGy/D6k4Ujmh8Tr25lGimuOXNiaVyXaCAZS0W+1390sADdGnyUdSWNIfd49gebtIxGMij4IktRVzrdr12Q==} + + '@tanstack/vue-virtual@3.13.24': + resolution: {integrity: sha512-A0k2qF0zFSUStXSZkGXABouXr2Tw2Ztl/cVIYG9qy84uR8W7UNjAcX3DvzBS3YnDcwvLxab8v7dbmYBZ39itDA==} + peerDependencies: + vue: ^2.7.0 || ^3.0.0 + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.27.0': + resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.28.0': + resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + + '@types/debug@4.1.13': + resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/har-format@1.2.16': + resolution: {integrity: sha512-fluxdy7ryD3MV6h8pTfTYpy/xQzCFC7m89nOH9y94cNqJ1mDIDPut7MnRHI3F6qRmh/cT2fUjG1MLdCNb4hE9A==} + + '@types/hast@3.0.4': + resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + + '@types/node@24.12.3': + resolution: {integrity: sha512-8oljBDGun9cIsZRJR6fkihn0TSXJI0UDOOhncYaERq6M0JMDoPLxyscwruJcb4GKS6dvK/d8xebYBg27h/duaQ==} + + '@types/react-dom@19.2.3': + resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} + peerDependencies: + '@types/react': ^19.2.0 + + '@types/react@19.2.14': + resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} + + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + + '@types/web-bluetooth@0.0.20': + resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==} + + '@types/web-bluetooth@0.0.21': + resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==} + + '@ungap/structured-clone@1.3.1': + resolution: {integrity: sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==} + + '@unhead/vue@2.1.13': + resolution: {integrity: sha512-HYy0shaHRnLNW9r85gppO8IiGz0ONWVV3zGdlT8CQ0tbTwixznJCIiyqV4BSV1aIF1jJIye0pd1p/k6Eab8Z/A==} + peerDependencies: + vue: '>=3.5.18' + + '@vercel/oidc@3.1.0': + resolution: {integrity: sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w==} + engines: {node: '>= 20'} + + '@vitejs/plugin-react@5.2.0': + resolution: {integrity: sha512-YmKkfhOAi3wsB1PhJq5Scj3GXMn3WvtQ/JC0xoopuHoXSdmtdStOpFrYaT1kie2YgFBcIe64ROzMYRjCrYOdYw==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + + '@vue-macros/common@3.1.2': + resolution: {integrity: sha512-h9t4ArDdniO9ekYHAD95t9AZcAbb19lEGK+26iAjUODOIJKmObDNBSe4+6ELQAA3vtYiFPPBtHh7+cQCKi3Dng==} + engines: {node: '>=20.19.0'} + peerDependencies: + vue: ^2.7.0 || ^3.2.25 + peerDependenciesMeta: + vue: + optional: true + + '@vue/compiler-core@3.5.33': + resolution: {integrity: sha512-3PZLQwFw4Za3TC8t0FvTy3wI16Kt+pmwcgNZca4Pj9iWL2E72a/gZlpBtAJvEdDMdCxdG/qq0C7PN0bsJuv0Rw==} + + '@vue/compiler-dom@3.5.33': + resolution: {integrity: sha512-PXq0yrfCLzzL07rbXO4awtXY1Z06LG2eu6Adg3RJFa/j3Cii217XxxLXG22N330gw7GmALCY0Z8RgXEviwgpjA==} + + '@vue/compiler-sfc@3.5.33': + resolution: {integrity: sha512-UTUvRO9cY+rROrx/pvN9P5Z7FgA6QGfokUCfhQE4EnmUj3rVnK+CHI0LsEO1pg+I7//iRYMUfcNcCPe7tg0CoA==} + + '@vue/compiler-ssr@3.5.33': + resolution: {integrity: sha512-IErjYdnj1qIupG5xxiVIYiiRvDhGWV4zuh/RCrwfYpuL+HWQzeU6lCk/nF9r7olWMnjKxCAkOctT2qFWFkzb1A==} + + '@vue/devtools-api@8.1.1': + resolution: {integrity: sha512-bsDMJ07b3GN1puVwJb/fyFnj/U2imyswK5UQVLZwVl7O05jDrt6BHxeG5XffmOOdasOj/bOmIjxJvGPxU7pcqw==} + + '@vue/devtools-kit@8.1.1': + resolution: {integrity: sha512-gVBaBv++i+adg4JpH71k9ppl4soyR7Y2McEqO5YNgv0BI1kMZ7BDX5gnwkZ5COYgiCyhejZG+yGNrBAjj6Coqg==} + + '@vue/devtools-shared@8.1.1': + resolution: {integrity: sha512-+h4ttmJYl/txpxHKaoZcaKpC+pvckgLzIDiSQlaQ7kKthKh8KuwoLW2D8hPJEnqKzXOvu15UHEoGyngAXCz0EQ==} + + '@vue/reactivity@3.5.33': + resolution: {integrity: sha512-p8UfIqyIhb0rYGlSgSBV+lPhF2iUSBcRy7enhTmPqKWadHy9kcOFYF1AejYBP9P+avnd3OBbD49DU4pLWX/94A==} + + '@vue/runtime-core@3.5.33': + resolution: {integrity: sha512-UpFF45RI9//a7rvq7RdOQblb4tup7hHG9QsmIrxkFQLzQ7R8/iNQ5LE15NhLZ1/WcHMU2b47u6P33CPUelHyIQ==} + + '@vue/runtime-dom@3.5.33': + resolution: {integrity: sha512-IOxMsAOwquhfITgmOgaPYl7/j8gKUxUFoflRc+u4LxyD3+783xne8vNta1PONVCvCV9A0w7hkyEepINDqfO0tw==} + + '@vue/server-renderer@3.5.33': + resolution: {integrity: sha512-0xylq/8/h44lVG0pZFknv1XIdEgymq2E9n59uTWJBG+dIgiT0TMCSsxrN7nO16Z0MU0MPjFcguBbZV8Itk52Hw==} + peerDependencies: + vue: 3.5.33 + + '@vue/shared@3.5.33': + resolution: {integrity: sha512-5vR2QIlmaLG77Ygd4pMP6+SGQ5yox9VhtnbDWTy9DzMzdmeLxZ1QqxrywEZ9sa1AVubfIJyaCG3ytyWU81ufcQ==} + + '@vueuse/core@10.11.1': + resolution: {integrity: sha512-guoy26JQktXPcz+0n3GukWIy/JDNKti9v6VEMu6kV2sYBsWuGiTU8OWdg+ADfUbHg3/3DlqySDe7JmdHrktiww==} + + '@vueuse/core@13.9.0': + resolution: {integrity: sha512-ts3regBQyURfCE2BcytLqzm8+MmLlo5Ln/KLoxDVcsZ2gzIwVNnQpQOL/UKV8alUqjSZOlpFZcRNsLRqj+OzyA==} + peerDependencies: + vue: ^3.5.0 + + '@vueuse/integrations@13.9.0': + resolution: {integrity: sha512-SDobKBbPIOe0cVL7QxMzGkuUGHvWTdihi9zOrrWaWUgFKe15cwEcwfWmgrcNzjT6kHnNmWuTajPHoIzUjYNYYQ==} + peerDependencies: + async-validator: ^4 + axios: ^1 + change-case: ^5 + drauu: ^0.4 + focus-trap: ^7 + fuse.js: ^7 + idb-keyval: ^6 + jwt-decode: ^4 + nprogress: ^0.2 + qrcode: ^1.5 + sortablejs: ^1 + universal-cookie: ^7 || ^8 + vue: ^3.5.0 + peerDependenciesMeta: + async-validator: + optional: true + axios: + optional: true + change-case: + optional: true + drauu: + optional: true + focus-trap: + optional: true + fuse.js: + optional: true + idb-keyval: + optional: true + jwt-decode: + optional: true + nprogress: + optional: true + qrcode: + optional: true + sortablejs: + optional: true + universal-cookie: + optional: true + + '@vueuse/metadata@10.11.1': + resolution: {integrity: sha512-IGa5FXd003Ug1qAZmyE8wF3sJ81xGLSqTqtQ6jaVfkeZ4i5kS2mwQF61yhVqojRnenVew5PldLyRgvdl4YYuSw==} + + '@vueuse/metadata@13.9.0': + resolution: {integrity: sha512-1AFRvuiGphfF7yWixZa0KwjYH8ulyjDCC0aFgrGRz8+P4kvDFSdXLVfTk5xAN9wEuD1J6z4/myMoYbnHoX07zg==} + + '@vueuse/shared@10.11.1': + resolution: {integrity: sha512-LHpC8711VFZlDaYUXEBbFBCQ7GS3dVU9mjOhhMhXP6txTV4EhYQg/KGnQuvt/sPAtoUKq7VVUnL6mVtFoL42sA==} + + '@vueuse/shared@13.9.0': + resolution: {integrity: sha512-e89uuTLMh0U5cZ9iDpEI2senqPGfbPRTHM/0AaQkcxnpqjkZqDYP8rpfm7edOz8s+pOCOROEy1PIveSW8+fL5g==} + peerDependencies: + vue: ^3.5.0 + + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} + engines: {node: '>=0.4.0'} + hasBin: true + + ai@6.0.33: + resolution: {integrity: sha512-bVokbmy2E2QF6Efl+5hOJx5MRWoacZ/CZY/y1E+VcewknvGlgaiCzMu8Xgddz6ArFJjiMFNUPHKxAhIePE4rmg==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + + aria-hidden@1.2.6: + resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} + engines: {node: '>=10'} + + ast-kit@2.2.0: + resolution: {integrity: sha512-m1Q/RaVOnTp9JxPX+F+Zn7IcLYMzM8kZofDImfsKZd8MbR+ikdOzTeztStWqfrqIxZnYWryyI9ePm3NGjnZgGw==} + engines: {node: '>=20.19.0'} + + ast-walker-scope@0.8.3: + resolution: {integrity: sha512-cbdCP0PGOBq0ASG+sjnKIoYkWMKhhz+F/h9pRexUdX2Hd38+WOlBkRKlqkGOSm0YQpcFMQBJeK4WspUAkwsEdg==} + engines: {node: '>=20.19.0'} + + bail@2.0.2: + resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} + + baseline-browser-mapping@2.10.27: + resolution: {integrity: sha512-zEs/ufmZoUd7WftKpKyXaT6RFxpQ5Qm9xytKRHvJfxFV9DFJkZph9RvJ1LcOUi0Z1ZVijMte65JbILeV+8QQEA==} + engines: {node: '>=6.0.0'} + hasBin: true + + birpc@2.9.0: + resolution: {integrity: sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==} + + browserslist@4.28.2: + resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + caniuse-lite@1.0.30001792: + resolution: {integrity: sha512-hVLMUZFgR4JJ6ACt1uEESvQN1/dBVqPAKY0hgrV70eN3391K6juAfTjKZLKvOMsx8PxA7gsY1/tLMMTcfFLLpw==} + + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + + chalk@5.6.2: + resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + + character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + + character-entities@2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + + chokidar@5.0.0: + resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} + engines: {node: '>= 20.19.0'} + + class-variance-authority@0.7.1: + resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + comma-separated-tokens@2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + + confbox@0.2.4: + resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==} + + convert-hrtime@5.0.0: + resolution: {integrity: sha512-lOETlkIeYSJWcbbcvjRKGxVMXJR+8+OQb/mTPbA4ObPMytYIsUbuOE0Jzy60hjARYszq1id0j8KgVhC+WGZVTg==} + engines: {node: '>=12'} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + cookie@1.1.1: + resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} + engines: {node: '>=18'} + + crelt@1.0.6: + resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + cva@1.0.0-beta.4: + resolution: {integrity: sha512-F/JS9hScapq4DBVQXcK85l9U91M6ePeXoBMSp7vypzShoefUBxjQTo3g3935PUHgQd+IW77DjbPRIxugy4/GCQ==} + peerDependencies: + typescript: '>= 4.5.5' + peerDependenciesMeta: + typescript: + optional: true + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decode-named-character-reference@1.3.0: + resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} + + defu@6.1.7: + resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} + + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + + dompurify@3.2.7: + resolution: {integrity: sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==} + + electron-to-chromium@1.5.352: + resolution: {integrity: sha512-9wHk8x6dyuimoe18EdiDPWKExNdxYqo4fn4FwOVVper6RxT3cmpBwBkWWfSOCYJjQdIco/nPhJhNLmn4Ufg1Yg==} + + enhanced-resolve@5.21.2: + resolution: {integrity: sha512-xe9vQb5kReirPUxgQrXA3ihgbCqssmTiM7cOZ+Gzu+VeGWgpV98lLZvp0dl4yriyAePcewxGUs9UpKD8PET9KQ==} + engines: {node: '>=10.13.0'} + + entities@6.0.1: + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} + engines: {node: '>=0.12'} + + entities@7.0.1: + resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} + engines: {node: '>=0.12'} + + esbuild@0.27.7: + resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} + engines: {node: '>=18'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + eventsource-parser@3.0.8: + resolution: {integrity: sha512-70QWGkr4snxr0OXLRWsFLeRBIRPuQOvt4s8QYjmUlmlkyTZkRqS7EDVRZtzU3TiyDbXSzaOeF0XUKy8PchzukQ==} + engines: {node: '>=18.0.0'} + + exsolve@1.0.8: + resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} + + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + flatted@3.4.2: + resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} + + focus-trap@7.8.0: + resolution: {integrity: sha512-/yNdlIkpWbM0ptxno3ONTuf+2g318kh2ez3KSeZN5dZ8YC6AAmgeWz+GasYYiBJPFaYcSAPeu4GfhUaChzIJXA==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-timeout@1.0.2: + resolution: {integrity: sha512-939eZS4gJ3htTHAldmyyuzlrD58P03fHG49v2JfFXbV6OhvZKRC9j2yAtdHw/zrp2zXHuv05zMIy40F0ge7spA==} + engines: {node: '>=18'} + + fuse.js@7.3.0: + resolution: {integrity: sha512-plz8RVjfcDedTGfVngWH1jmJvBvAwi1v2jecfDerbEnMcmOYUEEwKFTHbNoCiYyzaK2Ws8lABkTCcRSqCY1q4w==} + engines: {node: '>=10'} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-own-enumerable-keys@1.0.0: + resolution: {integrity: sha512-PKsK2FSrQCyxcGHsGrLDcK0lx+0Ke+6e8KFFozA9/fIQLhQzPaRvJFdcz7+Axg3jUH/Mq+NI4xa5u/UT2tQskA==} + engines: {node: '>=14.16'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + guess-json-indent@3.0.1: + resolution: {integrity: sha512-LWZ3Vr8BG7DHE3TzPYFqkhjNRw4vYgFSsv2nfMuHklAlOfiy54/EwiDQuQfFVLxENCVv20wpbjfTayooQHrEhQ==} + engines: {node: '>=18.18.0'} + + hast-util-embedded@3.0.0: + resolution: {integrity: sha512-naH8sld4Pe2ep03qqULEtvYr7EjrLK2QHY8KJR6RJkTUjPGObe1vnx585uzem2hGra+s1q08DZZpfgDVYRbaXA==} + + hast-util-format@1.1.0: + resolution: {integrity: sha512-yY1UDz6bC9rDvCWHpx12aIBGRG7krurX0p0Fm6pT547LwDIZZiNr8a+IHDogorAdreULSEzP82Nlv5SZkHZcjA==} + + hast-util-from-html@2.0.3: + resolution: {integrity: sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==} + + hast-util-from-parse5@8.0.3: + resolution: {integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==} + + hast-util-has-property@3.0.0: + resolution: {integrity: sha512-MNilsvEKLFpV604hwfhVStK0usFY/QmM5zX16bo7EjnAEGofr5YyI37kzopBlZJkHD4t887i+q/C8/tr5Q94cA==} + + hast-util-is-body-ok-link@3.0.1: + resolution: {integrity: sha512-0qpnzOBLztXHbHQenVB8uNuxTnm/QBFUOmdOSsEn7GnBtyY07+ENTWVFBAnXd/zEgd9/SUG3lRY7hSIBWRgGpQ==} + + hast-util-is-element@3.0.0: + resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==} + + hast-util-minify-whitespace@1.0.1: + resolution: {integrity: sha512-L96fPOVpnclQE0xzdWb/D12VT5FabA7SnZOUMtL1DbXmYiHJMXZvFkIZfiMmTCNJHUeO2K9UYNXoVyfz+QHuOw==} + + hast-util-parse-selector@4.0.0: + resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==} + + hast-util-phrasing@3.0.1: + resolution: {integrity: sha512-6h60VfI3uBQUxHqTyMymMZnEbNl1XmEGtOxxKYL7stY2o601COo62AWAYBQR9lZbYXYSBoxag8UpPRXK+9fqSQ==} + + hast-util-raw@9.1.0: + resolution: {integrity: sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==} + + hast-util-sanitize@5.0.2: + resolution: {integrity: sha512-3yTWghByc50aGS7JlGhk61SPenfE/p1oaFeNwkOOyrscaOkMGrcW9+Cy/QAIOBpZxP1yqDIzFMR0+Np0i0+usg==} + + hast-util-to-html@9.0.5: + resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==} + + hast-util-to-parse5@8.0.1: + resolution: {integrity: sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==} + + hast-util-to-text@4.0.2: + resolution: {integrity: sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==} + + hast-util-whitespace@3.0.0: + resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} + + hastscript@9.0.1: + resolution: {integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==} + + highlight.js@11.11.1: + resolution: {integrity: sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==} + engines: {node: '>=12.0.0'} + + hookable@5.5.3: + resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} + + hookable@6.1.1: + resolution: {integrity: sha512-U9LYDy1CwhMCnprUfeAZWZGByVbhd54hwepegYTK7Pi5NvqEj63ifz5z+xukznehT7i6NIZRu89Ay1AZmRsLEQ==} + + html-void-elements@3.0.0: + resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} + + html-whitespace-sensitive-tag-names@3.0.1: + resolution: {integrity: sha512-q+310vW8zmymYHALr1da4HyXUQ0zgiIwIicEfotYPWGN0OJVEN/58IJ3A4GBYcEq3LGAZqKb+ugvP0GNB9CEAA==} + + identifier-regex@1.0.1: + resolution: {integrity: sha512-ZrYyM0sozNPZlvBvE7Oq9Bn44n0qKGrYu5sQ0JzMUnjIhpgWYE2JB6aBoFwEYdPjqj7jPyxXTMJiHDOxDfd8yw==} + engines: {node: '>=18'} + + is-absolute-url@4.0.1: + resolution: {integrity: sha512-/51/TKE88Lmm7Gc4/8btclNXWS+g50wXhYJq8HWIBAGUBnoAdRu1aXeh364t/O7wXDAcTJDP8PNuNKWUDWie+A==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + is-identifier@1.0.1: + resolution: {integrity: sha512-HQ5v4rEJ7REUV54bCd2l5FaD299SGDEn2UPoVXaTHAyGviLq2menVUD2udi3trQ32uvB6LdAh/0ck2EuizrtpA==} + engines: {node: '>=18'} + + is-obj@3.0.0: + resolution: {integrity: sha512-IlsXEHOjtKhpN8r/tRFj2nDyTmHvcfNeu/nrRIcXE17ROeatXchkojffa1SpdqW4cr/Fj6QkEf/Gn4zf6KKvEQ==} + engines: {node: '>=12'} + + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + + is-regexp@3.1.0: + resolution: {integrity: sha512-rbku49cWloU5bSMI+zaRaXdQHXnthP6DZ/vLnfdSKyL4zUzuWnomtOEiZZOd+ioQ+avFo/qau3KPTc7Fjy1uPA==} + engines: {node: '>=12'} + + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} + hasBin: true + + js-base64@3.7.8: + resolution: {integrity: sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-schema@0.4.0: + resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + jsonc-parser@3.3.1: + resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} + + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} + + local-pkg@1.1.2: + resolution: {integrity: sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==} + engines: {node: '>=14'} + + longest-streak@3.1.0: + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + + lowlight@3.3.0: + resolution: {integrity: sha512-0JNhgFoPvP6U6lE/UdVsSq99tn6DhjjpAj5MxG49ewd2mOBVtwWYIT8ClyABhq198aXXODMU6Ox8DrGy/CpTZQ==} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + lucide-react@0.469.0: + resolution: {integrity: sha512-28vvUnnKQ/dBwiCQtwJw7QauYnE7yd2Cyp4tTTJpvglX4EMpbflcdBgrgToX2j71B3YvugK/NH3BGUk+E/p/Fw==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + lucide-react@0.553.0: + resolution: {integrity: sha512-BRgX5zrWmNy/lkVAe0dXBgd7XQdZ3HTf+Hwe3c9WK6dqgnj9h+hxV+MDncM88xDWlCq27+TKvHGE70ViODNILw==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + magic-string-ast@1.0.3: + resolution: {integrity: sha512-CvkkH1i81zl7mmb94DsRiFeG9V2fR2JeuK8yDgS8oiZSFa++wWLEgZ5ufEOyLHbvSbD1gTRKv9NdX69Rnvr9JA==} + engines: {node: '>=20.19.0'} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + make-asynchronous@1.1.0: + resolution: {integrity: sha512-ayF7iT+44LXdxJLTrTd3TLQpFDDvPCBxXxbv+pMUSuHA5Q8zyAfwkRP6aHHwNVFBUFWtxAHqwNJxF8vMZLAbVg==} + engines: {node: '>=18'} + + markdown-table@3.0.4: + resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} + + marked@14.0.0: + resolution: {integrity: sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==} + engines: {node: '>= 18'} + hasBin: true + + mdast-util-find-and-replace@3.0.2: + resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} + + mdast-util-from-markdown@2.0.3: + resolution: {integrity: sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==} + + mdast-util-gfm-autolink-literal@2.0.1: + resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} + + mdast-util-gfm-footnote@2.1.0: + resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==} + + mdast-util-gfm-strikethrough@2.0.0: + resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==} + + mdast-util-gfm-table@2.0.0: + resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} + + mdast-util-gfm-task-list-item@2.0.0: + resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==} + + mdast-util-gfm@3.1.0: + resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==} + + mdast-util-phrasing@4.1.0: + resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + + mdast-util-to-hast@13.2.1: + resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} + + mdast-util-to-markdown@2.1.2: + resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} + + mdast-util-to-string@4.0.0: + resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + + microdiff@1.5.0: + resolution: {integrity: sha512-Drq+/THMvDdzRYrK0oxJmOKiC24ayUV8ahrt8l3oRK51PWt6gdtrIGrlIH3pT/lFh1z93FbAcidtsHcWbnRz8Q==} + + micromark-core-commonmark@2.0.3: + resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} + + micromark-extension-gfm-autolink-literal@2.1.0: + resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==} + + micromark-extension-gfm-footnote@2.1.0: + resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==} + + micromark-extension-gfm-strikethrough@2.1.0: + resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==} + + micromark-extension-gfm-table@2.1.1: + resolution: {integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==} + + micromark-extension-gfm-tagfilter@2.0.0: + resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==} + + micromark-extension-gfm-task-list-item@2.1.0: + resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==} + + micromark-extension-gfm@3.0.0: + resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==} + + micromark-factory-destination@2.0.1: + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + + micromark-factory-label@2.0.1: + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + + micromark-factory-space@2.0.1: + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} + + micromark-factory-title@2.0.1: + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + + micromark-factory-whitespace@2.0.1: + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-chunked@2.0.1: + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + + micromark-util-classify-character@2.0.1: + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + + micromark-util-combine-extensions@2.0.1: + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + + micromark-util-decode-string@2.0.1: + resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-html-tag-name@2.0.1: + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} + + micromark-util-normalize-identifier@2.0.1: + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + + micromark-util-resolve-all@2.0.1: + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-subtokenize@2.1.0: + resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.2: + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} + + micromark@4.0.2: + resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} + + mlly@1.8.2: + resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==} + + monaco-editor@0.55.1: + resolution: {integrity: sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==} + + monaco-languageserver-types@0.4.0: + resolution: {integrity: sha512-QQ3BZiU5LYkJElGncSNb5AKoJ/LCs6YBMCJMAz9EA7v+JaOdn3kx2cXpPTcZfKA5AEsR0vc97sAw+5mdNhVBmw==} + + monaco-marker-data-provider@1.2.5: + resolution: {integrity: sha512-5ZdcYukhPwgYMCvlZ9H5uWs5jc23BQ8fFF5AhSIdrz5mvYLsqGZ58ZLxTv8rCX6+AxdJ8+vxg1HVSk+F2bLosg==} + + monaco-types@0.1.2: + resolution: {integrity: sha512-8LwfrlWXsedHwAL41xhXyqzPibS8IqPuIXr9NdORhonS495c2/wky+sI1PRLvMCuiI0nqC2NH1six9hdiRY4Xg==} + + monaco-worker-manager@2.0.1: + resolution: {integrity: sha512-kdPL0yvg5qjhKPNVjJoym331PY/5JC11aPJXtCZNwWRvBr6jhkIamvYAyiY5P1AWFmNOy0aRDRoMdZfa71h8kg==} + peerDependencies: + monaco-editor: '>=0.30.0' + + monaco-yaml@5.4.1: + resolution: {integrity: sha512-YQ6d/Ei98Uk073SJLFbwuSi95qhnl8F8NNmIUqN2XhDt9psZN2LqQ1T7pPQ866NJb2wFj44IrjnANgpa2jTfag==} + peerDependencies: + monaco-editor: '>=0.36' + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + muggle-string@0.4.1: + resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} + + nanoid@3.3.12: + resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + nanoid@5.1.11: + resolution: {integrity: sha512-v+KEsUv2ps74PaSKv0gHTxTCgMXOIfBEbaqa6w6ISIGC7ZsvHN4N9oJ8d4cmf0n5oTzQz2SLmThbQWhjd/8eKg==} + engines: {node: ^18 || >=20} + hasBin: true + + neverpanic@0.0.7: + resolution: {integrity: sha512-GFRTSX2JAEATOCQYlyFkR+9FJPl0pD24toE1foqYAsL6aPLlRKn6L0UFOtJhZCxEbDv+SUsiW4AcPs9cIFwkFw==} + peerDependencies: + typescript: '5' + + node-releases@2.0.38: + resolution: {integrity: sha512-3qT/88Y3FbH/Kx4szpQQ4HzUbVrHPKTLVpVocKiLfoYvw9XSGOX2FmD2d6DrXbVYyAQTF2HeF6My8jmzx7/CRw==} + + p-event@6.0.1: + resolution: {integrity: sha512-Q6Bekk5wpzW5qIyUP4gdMEujObYstZl6DMMOSenwBvV0BlE5LkDwkjs5yHbZmdCEq2o4RJx4tE1vwxFVf2FG1w==} + engines: {node: '>=16.17'} + + p-timeout@6.1.4: + resolution: {integrity: sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==} + engines: {node: '>=14.16'} + + parse-ms@4.0.0: + resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==} + engines: {node: '>=18'} + + parse5@7.3.0: + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + + path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + perfect-debounce@2.1.0: + resolution: {integrity: sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} + engines: {node: '>=12'} + + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + + pkg-types@2.3.1: + resolution: {integrity: sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==} + + postcss@8.5.14: + resolution: {integrity: sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==} + engines: {node: ^10 || ^12 || >=14} + + prettier@3.8.3: + resolution: {integrity: sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==} + engines: {node: '>=14'} + hasBin: true + + pretty-ms@9.3.0: + resolution: {integrity: sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==} + engines: {node: '>=18'} + + property-information@7.1.0: + resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} + + quansync@0.2.11: + resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} + + radix-vue@1.9.17: + resolution: {integrity: sha512-mVCu7I2vXt1L2IUYHTt0sZMz7s1K2ZtqKeTIxG3yC5mMFfLBG4FtE1FDeRMpDd+Hhg/ybi9+iXmAP1ISREndoQ==} + peerDependencies: + vue: '>= 3.2.0' + + react-dom@19.2.6: + resolution: {integrity: sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==} + peerDependencies: + react: ^19.2.6 + + react-refresh@0.18.0: + resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==} + engines: {node: '>=0.10.0'} + + react@19.2.6: + resolution: {integrity: sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==} + engines: {node: '>=0.10.0'} + + readdirp@5.0.0: + resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} + engines: {node: '>= 20.19.0'} + + rehype-external-links@3.0.0: + resolution: {integrity: sha512-yp+e5N9V3C6bwBeAC4n796kc86M4gJCdlVhiMTxIrJG5UHDMh+PJANf9heqORJbt1nrCbDwIlAZKjANIaVBbvw==} + + rehype-format@5.0.1: + resolution: {integrity: sha512-zvmVru9uB0josBVpr946OR8ui7nJEdzZobwLOOqHb/OOD88W0Vk2SqLwoVOj0fM6IPCCO6TaV9CvQvJMWwukFQ==} + + rehype-parse@9.0.1: + resolution: {integrity: sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==} + + rehype-raw@7.0.0: + resolution: {integrity: sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==} + + rehype-sanitize@6.0.0: + resolution: {integrity: sha512-CsnhKNsyI8Tub6L4sm5ZFsme4puGfc6pYylvXo1AeqaGbjOYyzNv3qZPwvs0oMJ39eryyeOdmxwUIo94IpEhqg==} + + rehype-stringify@10.0.1: + resolution: {integrity: sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==} + + remark-gfm@4.0.1: + resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} + + remark-parse@11.0.0: + resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} + + remark-rehype@11.1.2: + resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==} + + remark-stringify@11.0.0: + resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} + + reserved-identifiers@1.2.0: + resolution: {integrity: sha512-yE7KUfFvaBFzGPs5H3Ops1RevfUEsDc5Iz65rOwWg4lE8HJSYtle77uul3+573457oHvBKuHYDl/xqUkKpEEdw==} + engines: {node: '>=18'} + + rollup@4.60.3: + resolution: {integrity: sha512-pAQK9HalE84QSm4Po3EmWIZPd3FnjkShVkiMlz1iligWYkWQ7wHYd1PF/T7QZ5TVSD6uSTon5gBVMSM4JfBV+A==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + + scule@1.3.0: + resolution: {integrity: sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + set-cookie-parser@3.1.0: + resolution: {integrity: sha512-kjnC1DXBHcxaOaOXBHBeRtltsDG2nUiUni+jP92M9gYdW12rsmx92UsfpH7o5tDRs7I1ZZPSQJQGv3UaRfCiuw==} + + shell-quote@1.8.3: + resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==} + engines: {node: '>= 0.4'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + space-separated-tokens@2.0.2: + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + + string-byte-length@3.0.1: + resolution: {integrity: sha512-yJ8vP0HMwZ54CcA8S8mKoXbkezpZHANFtmafFo8lGxZThCQcAwRHjdFabuSLgOzxj9OFJcmssmiAvmcOK4O2Hw==} + engines: {node: '>=18.18.0'} + + string-byte-slice@3.0.1: + resolution: {integrity: sha512-GWv2K4lYyd2+AhmKH3BV+OVx62xDX+99rSLfKpaqFiQU7uOMaUY1tDjdrRD4gsrCr9lTyjMgjna7tZcCOw+Smg==} + engines: {node: '>=18.18.0'} + + stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + + stringify-object@6.0.0: + resolution: {integrity: sha512-6f94vIED6vmJJfh3lyVsVWxCYSfI5uM+16ntED/Ql37XIyV6kj0mRAAiTeMMc/QLYIaizC3bUprQ8pQnDDrKfA==} + engines: {node: '>=20'} + + style-mod@4.1.3: + resolution: {integrity: sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==} + + super-regex@1.1.0: + resolution: {integrity: sha512-WHkws2ZflZe41zj6AolvvmaTrWds/VuyeYr9iPVv/oQeaIoVxMKaushfFWpOGDT+GuBrM/sVqF8KUCYQlSSTdQ==} + engines: {node: '>=18'} + + swrv@1.2.0: + resolution: {integrity: sha512-lH/g4UcNyj+7lzK4eRGT4C68Q4EhQ6JtM9otPRIASfhhzfLWtbZPHcMuhuba7S9YVYuxkMUGImwMyGpfbkH07A==} + peerDependencies: + vue: '>=3.2.26 < 4' + + tabbable@6.4.0: + resolution: {integrity: sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==} + + tagged-tag@1.0.0: + resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} + engines: {node: '>=20'} + + tailwind-merge@2.6.1: + resolution: {integrity: sha512-Oo6tHdpZsGpkKG88HJ8RR1rg/RdnEkQEfMoEk2x1XRI3F1AxeU+ijRXpiVUF4UbLfcxxRGw6TbUINKYdWVsQTQ==} + + tailwind-merge@3.5.0: + resolution: {integrity: sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A==} + + tailwindcss@4.2.4: + resolution: {integrity: sha512-HhKppgO81FQof5m6TEnuBWCZGgfRAWbaeOaGT00KOy/Pf/j6oUihdvBpA7ltCeAvZpFhW3j0PTclkxsd4IXYDA==} + + tapable@2.3.3: + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} + engines: {node: '>=6'} + + time-span@5.1.0: + resolution: {integrity: sha512-75voc/9G4rDIJleOo4jPvN4/YC4GRZrY8yy1uU4lwrB3XEQbWve8zXoO5No4eFrGcTAMYyoY67p8jRQdtA1HbA==} + engines: {node: '>=12'} + + tinyglobby@0.2.16: + resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} + engines: {node: '>=12.0.0'} + + trim-lines@3.0.1: + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + + trough@2.2.0: + resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + + truncate-json@3.0.1: + resolution: {integrity: sha512-QVsbr1WhGLq2F0oDyYbqtOXcf3gcnL8C9H5EX8bBwAr8ZWvWGJzukpPrDrWgJMrNtgDbo74BIjI4kJu3q2xQWw==} + engines: {node: '>=18.18.0'} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + type-fest@4.41.0: + resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} + engines: {node: '>=16'} + + type-fest@5.6.0: + resolution: {integrity: sha512-8ZiHFm91orbSAe2PSAiSVBVko18pbhbiB3U9GglSzF/zCGkR+rxpHx6sEMCUm4kxY4LjDIUGgCfUMtwfZfjfUA==} + engines: {node: '>=20'} + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + ufo@1.6.4: + resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==} + + undici-types@7.16.0: + resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + + unhead@2.1.13: + resolution: {integrity: sha512-jO9M1sI6b2h/1KpIu4Jeu+ptumLmUKboRRLxys5pYHFeT+lqTzfNHbYUX9bxVDhC1FBszAGuWcUVlmvIPsah8Q==} + + unified@11.0.5: + resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} + + unist-util-find-after@5.0.0: + resolution: {integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==} + + unist-util-is@6.0.1: + resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} + + unist-util-position@5.0.0: + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + + unist-util-visit-parents@6.0.2: + resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} + + unist-util-visit@5.1.0: + resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} + + unplugin-utils@0.3.1: + resolution: {integrity: sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog==} + engines: {node: '>=20.19.0'} + + unplugin@3.0.0: + resolution: {integrity: sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg==} + engines: {node: ^20.19.0 || >=22.12.0} + + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + vfile-location@5.0.3: + resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} + + vfile-message@4.0.3: + resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} + + vfile@6.0.3: + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + + vite-plugin-monaco-editor@1.1.0: + resolution: {integrity: sha512-IvtUqZotrRoVqwT0PBBDIZPNraya3BxN/bfcNfnxZ5rkJiGcNtO5eAOWWSgT7zullIAEqQwxMU83yL9J5k7gww==} + peerDependencies: + monaco-editor: '>=0.33.0' + + vite@7.3.3: + resolution: {integrity: sha512-/4XH147Ui7OGTjg3HbdWe5arnZQSbfuRzdr9Ec7TQi5I7R+ir0Rlc9GIvD4v0XZurELqA035KVXJXpR61xhiTA==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vscode-jsonrpc@8.2.0: + resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==} + engines: {node: '>=14.0.0'} + + vscode-languageserver-protocol@3.17.5: + resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==} + + vscode-languageserver-textdocument@1.0.12: + resolution: {integrity: sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==} + + vscode-languageserver-types@3.17.5: + resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==} + + vscode-uri@3.1.0: + resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} + + vue-component-type-helpers@3.2.8: + resolution: {integrity: sha512-9689efAXhN/EV86plgkL/XFiJSXhGtWPG6JDboZ+QnjlUWUUQrQ0ILKQtw4iQsuwIwu5k6Aw+JnehDe7161e7A==} + + vue-demi@0.14.10: + resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==} + engines: {node: '>=12'} + hasBin: true + peerDependencies: + '@vue/composition-api': ^1.0.0-rc.1 + vue: ^3.0.0-0 || ^2.6.0 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + + vue-router@5.0.4: + resolution: {integrity: sha512-lCqDLCI2+fKVRl2OzXuzdSWmxXFLQRxQbmHugnRpTMyYiT+hNaycV0faqG5FBHDXoYrZ6MQcX87BvbY8mQ20Bg==} + peerDependencies: + '@pinia/colada': '>=0.21.2' + '@vue/compiler-sfc': ^3.5.17 + pinia: ^3.0.4 + vue: ^3.5.0 + peerDependenciesMeta: + '@pinia/colada': + optional: true + '@vue/compiler-sfc': + optional: true + pinia: + optional: true + + vue-sonner@1.3.2: + resolution: {integrity: sha512-UbZ48E9VIya3ToiRHAZUbodKute/z/M1iT8/3fU8zEbwBRE11AKuHikssv18LMk2gTTr6eMQT4qf6JoLHWuj/A==} + + vue@3.5.33: + resolution: {integrity: sha512-1AgChhx5w3ALgT4oK3acm2Es/7jyZhWSVUfs3rOBlGQC0rjEDkS7G4lWlJJGGNQD+BV3reCwbQrOe1mPNwKHBQ==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + w3c-keyname@2.2.8: + resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} + + web-namespaces@2.0.1: + resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} + + web-worker@1.5.0: + resolution: {integrity: sha512-RiMReJrTAiA+mBjGONMnjVDP2u3p9R1vkcGz6gDIrOMT3oGuYwX2WRMYI9ipkphSuE5XKEhydbhNEJh4NY9mlw==} + + webpack-virtual-modules@0.6.2: + resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yaml@2.8.4: + resolution: {integrity: sha512-ml/JPOj9fOQK8RNnWojA67GbZ0ApXAUlN2UQclwv2eVgTgn7O9gg9o7paZWKMp4g0H3nTLtS9LVzhkpOFIKzog==} + engines: {node: '>= 14.6'} + hasBin: true + + zod@4.4.3: + resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} + + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + +snapshots: + + '@ai-sdk/gateway@3.0.13(zod@4.4.3)': + dependencies: + '@ai-sdk/provider': 3.0.2 + '@ai-sdk/provider-utils': 4.0.5(zod@4.4.3) + '@vercel/oidc': 3.1.0 + zod: 4.4.3 + + '@ai-sdk/provider-utils@4.0.5(zod@4.4.3)': + dependencies: + '@ai-sdk/provider': 3.0.2 + '@standard-schema/spec': 1.1.0 + eventsource-parser: 3.0.8 + zod: 4.4.3 + + '@ai-sdk/provider@3.0.2': + dependencies: + json-schema: 0.4.0 + + '@ai-sdk/vue@3.0.33(vue@3.5.33(typescript@5.9.3))(zod@4.4.3)': + dependencies: + '@ai-sdk/provider-utils': 4.0.5(zod@4.4.3) + ai: 6.0.33(zod@4.4.3) + swrv: 1.2.0(vue@3.5.33(typescript@5.9.3)) + vue: 3.5.33(typescript@5.9.3) + transitivePeerDependencies: + - zod + + '@babel/code-frame@7.29.0': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.29.3': {} + + '@babel/core@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helpers': 7.29.2 + '@babel/parser': 7.29.3 + '@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.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.29.1': + dependencies: + '@babel/parser': 7.29.3 + '@babel/types': 7.29.0 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@7.28.6': + dependencies: + '@babel/compat-data': 7.29.3 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.28.2 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-globals@7.28.0': {} + + '@babel/helper-module-imports@7.28.6': + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-plugin-utils@7.28.6': {} + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.28.5': {} + + '@babel/helper-validator-option@7.27.1': {} + + '@babel/helpers@7.29.2': + dependencies: + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + + '@babel/parser@7.29.3': + dependencies: + '@babel/types': 7.29.0 + + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/template@7.28.6': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/parser': 7.29.3 + '@babel/types': 7.29.0 + + '@babel/traverse@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.29.3 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.29.0': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + + '@codemirror/autocomplete@6.20.1': + dependencies: + '@codemirror/language': 6.12.3 + '@codemirror/state': 6.6.0 + '@codemirror/view': 6.41.1 + '@lezer/common': 1.5.2 + + '@codemirror/commands@6.10.3': + dependencies: + '@codemirror/language': 6.12.3 + '@codemirror/state': 6.6.0 + '@codemirror/view': 6.41.1 + '@lezer/common': 1.5.2 + + '@codemirror/lang-css@6.3.1': + dependencies: + '@codemirror/autocomplete': 6.20.1 + '@codemirror/language': 6.12.3 + '@codemirror/state': 6.6.0 + '@lezer/common': 1.5.2 + '@lezer/css': 1.3.3 + + '@codemirror/lang-html@6.4.11': + dependencies: + '@codemirror/autocomplete': 6.20.1 + '@codemirror/lang-css': 6.3.1 + '@codemirror/lang-javascript': 6.2.5 + '@codemirror/language': 6.12.3 + '@codemirror/state': 6.6.0 + '@codemirror/view': 6.41.1 + '@lezer/common': 1.5.2 + '@lezer/css': 1.3.3 + '@lezer/html': 1.3.13 + + '@codemirror/lang-javascript@6.2.5': + dependencies: + '@codemirror/autocomplete': 6.20.1 + '@codemirror/language': 6.12.3 + '@codemirror/lint': 6.9.5 + '@codemirror/state': 6.6.0 + '@codemirror/view': 6.41.1 + '@lezer/common': 1.5.2 + '@lezer/javascript': 1.5.4 + + '@codemirror/lang-json@6.0.2': + dependencies: + '@codemirror/language': 6.12.3 + '@lezer/json': 1.0.3 + + '@codemirror/lang-xml@6.1.0': + dependencies: + '@codemirror/autocomplete': 6.20.1 + '@codemirror/language': 6.12.3 + '@codemirror/state': 6.6.0 + '@codemirror/view': 6.41.1 + '@lezer/common': 1.5.2 + '@lezer/xml': 1.0.6 + + '@codemirror/lang-yaml@6.1.3': + dependencies: + '@codemirror/autocomplete': 6.20.1 + '@codemirror/language': 6.12.3 + '@codemirror/state': 6.6.0 + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.10 + '@lezer/yaml': 1.0.4 + + '@codemirror/language@6.12.3': + dependencies: + '@codemirror/state': 6.6.0 + '@codemirror/view': 6.41.1 + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.10 + style-mod: 4.1.3 + + '@codemirror/lint@6.9.5': + dependencies: + '@codemirror/state': 6.6.0 + '@codemirror/view': 6.41.1 + crelt: 1.0.6 + + '@codemirror/state@6.6.0': + dependencies: + '@marijn/find-cluster-break': 1.0.2 + + '@codemirror/view@6.41.1': + dependencies: + '@codemirror/state': 6.6.0 + crelt: 1.0.6 + style-mod: 4.1.3 + w3c-keyname: 2.2.8 + + '@esbuild/aix-ppc64@0.27.7': + optional: true + + '@esbuild/android-arm64@0.27.7': + optional: true + + '@esbuild/android-arm@0.27.7': + optional: true + + '@esbuild/android-x64@0.27.7': + optional: true + + '@esbuild/darwin-arm64@0.27.7': + optional: true + + '@esbuild/darwin-x64@0.27.7': + optional: true + + '@esbuild/freebsd-arm64@0.27.7': + optional: true + + '@esbuild/freebsd-x64@0.27.7': + optional: true + + '@esbuild/linux-arm64@0.27.7': + optional: true + + '@esbuild/linux-arm@0.27.7': + optional: true + + '@esbuild/linux-ia32@0.27.7': + optional: true + + '@esbuild/linux-loong64@0.27.7': + optional: true + + '@esbuild/linux-mips64el@0.27.7': + optional: true + + '@esbuild/linux-ppc64@0.27.7': + optional: true + + '@esbuild/linux-riscv64@0.27.7': + optional: true + + '@esbuild/linux-s390x@0.27.7': + optional: true + + '@esbuild/linux-x64@0.27.7': + optional: true + + '@esbuild/netbsd-arm64@0.27.7': + optional: true + + '@esbuild/netbsd-x64@0.27.7': + optional: true + + '@esbuild/openbsd-arm64@0.27.7': + optional: true + + '@esbuild/openbsd-x64@0.27.7': + optional: true + + '@esbuild/openharmony-arm64@0.27.7': + optional: true + + '@esbuild/sunos-x64@0.27.7': + optional: true + + '@esbuild/win32-arm64@0.27.7': + optional: true + + '@esbuild/win32-ia32@0.27.7': + optional: true + + '@esbuild/win32-x64@0.27.7': + optional: true + + '@flanksource/clicky-ui@0.2.1(@tanstack/react-query@5.100.9(react@19.2.6))(@types/react@19.2.14)(@vue/compiler-sfc@3.5.33)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(tailwindcss@4.2.4)(typescript@5.9.3)': + dependencies: + '@iconify/react': 5.2.1(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.6) + '@radix-ui/react-slot': 1.2.4(@types/react@19.2.14)(react@19.2.6) + '@scalar/api-reference-react': 0.9.33(@vue/compiler-sfc@3.5.33)(react@19.2.6)(tailwindcss@4.2.4)(typescript@5.9.3) + class-variance-authority: 0.7.1 + clsx: 2.1.1 + lucide-react: 0.469.0(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + tailwind-merge: 2.6.1 + tailwindcss: 4.2.4 + optionalDependencies: + '@tanstack/react-query': 5.100.9(react@19.2.6) + transitivePeerDependencies: + - '@pinia/colada' + - '@types/react' + - '@vue/compiler-sfc' + - '@vue/composition-api' + - async-validator + - axios + - change-case + - drauu + - idb-keyval + - jwt-decode + - nprogress + - pinia + - qrcode + - sortablejs + - supports-color + - typescript + - universal-cookie + + '@floating-ui/core@1.7.5': + dependencies: + '@floating-ui/utils': 0.2.11 + + '@floating-ui/dom@1.7.6': + dependencies: + '@floating-ui/core': 1.7.5 + '@floating-ui/utils': 0.2.11 + + '@floating-ui/utils@0.2.10': {} + + '@floating-ui/utils@0.2.11': {} + + '@floating-ui/vue@1.1.11(vue@3.5.33(typescript@5.9.3))': + dependencies: + '@floating-ui/dom': 1.7.6 + '@floating-ui/utils': 0.2.11 + vue-demi: 0.14.10(vue@3.5.33(typescript@5.9.3)) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + + '@floating-ui/vue@1.1.9(vue@3.5.33(typescript@5.9.3))': + dependencies: + '@floating-ui/dom': 1.7.6 + '@floating-ui/utils': 0.2.10 + vue-demi: 0.14.10(vue@3.5.33(typescript@5.9.3)) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + + '@headlessui/tailwindcss@0.2.2(tailwindcss@4.2.4)': + dependencies: + tailwindcss: 4.2.4 + + '@headlessui/vue@1.7.23(vue@3.5.33(typescript@5.9.3))': + dependencies: + '@tanstack/vue-virtual': 3.13.24(vue@3.5.33(typescript@5.9.3)) + vue: 3.5.33(typescript@5.9.3) + + '@iconify/react@5.2.1(react@19.2.6)': + dependencies: + '@iconify/types': 2.0.0 + react: 19.2.6 + + '@iconify/types@2.0.0': {} + + '@internationalized/date@3.12.1': + dependencies: + '@swc/helpers': 0.5.21 + + '@internationalized/number@3.6.6': + dependencies: + '@swc/helpers': 0.5.21 + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@lezer/common@1.5.2': {} + + '@lezer/css@1.3.3': + dependencies: + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.10 + + '@lezer/highlight@1.2.3': + dependencies: + '@lezer/common': 1.5.2 + + '@lezer/html@1.3.13': + dependencies: + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.10 + + '@lezer/javascript@1.5.4': + dependencies: + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.10 + + '@lezer/json@1.0.3': + dependencies: + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.10 + + '@lezer/lr@1.4.10': + dependencies: + '@lezer/common': 1.5.2 + + '@lezer/xml@1.0.6': + dependencies: + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.10 + + '@lezer/yaml@1.0.4': + dependencies: + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.10 + + '@marijn/find-cluster-break@1.0.2': {} + + '@opentelemetry/api@1.9.0': {} + + '@phosphor-icons/core@2.1.1': {} + + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.14)(react@19.2.6)': + dependencies: + react: 19.2.6 + optionalDependencies: + '@types/react': 19.2.14 + + '@radix-ui/react-slot@1.2.4(@types/react@19.2.14)(react@19.2.6)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.6) + react: 19.2.6 + optionalDependencies: + '@types/react': 19.2.14 + + '@replit/codemirror-css-color-picker@6.3.0(@codemirror/language@6.12.3)(@codemirror/state@6.6.0)(@codemirror/view@6.41.1)': + dependencies: + '@codemirror/language': 6.12.3 + '@codemirror/state': 6.6.0 + '@codemirror/view': 6.41.1 + + '@rolldown/pluginutils@1.0.0-rc.3': {} + + '@rollup/rollup-android-arm-eabi@4.60.3': + optional: true + + '@rollup/rollup-android-arm64@4.60.3': + optional: true + + '@rollup/rollup-darwin-arm64@4.60.3': + optional: true + + '@rollup/rollup-darwin-x64@4.60.3': + optional: true + + '@rollup/rollup-freebsd-arm64@4.60.3': + optional: true + + '@rollup/rollup-freebsd-x64@4.60.3': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.60.3': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.60.3': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.60.3': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.60.3': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.60.3': + optional: true + + '@rollup/rollup-linux-loong64-musl@4.60.3': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.60.3': + optional: true + + '@rollup/rollup-linux-ppc64-musl@4.60.3': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.60.3': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.60.3': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.60.3': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.60.3': + optional: true + + '@rollup/rollup-linux-x64-musl@4.60.3': + optional: true + + '@rollup/rollup-openbsd-x64@4.60.3': + optional: true + + '@rollup/rollup-openharmony-arm64@4.60.3': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.60.3': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.60.3': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.60.3': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.60.3': + optional: true + + '@scalar/agent-chat@0.10.14(@vue/compiler-sfc@3.5.33)(tailwindcss@4.2.4)(typescript@5.9.3)': + dependencies: + '@ai-sdk/vue': 3.0.33(vue@3.5.33(typescript@5.9.3))(zod@4.4.3) + '@scalar/api-client': 3.6.0(@vue/compiler-sfc@3.5.33)(tailwindcss@4.2.4)(typescript@5.9.3) + '@scalar/components': 0.24.2(tailwindcss@4.2.4)(typescript@5.9.3) + '@scalar/helpers': 0.6.0 + '@scalar/icons': 0.7.2(typescript@5.9.3) + '@scalar/json-magic': 0.12.12 + '@scalar/openapi-types': 0.8.0 + '@scalar/themes': 0.15.3 + '@scalar/types': 0.9.6 + '@scalar/use-toasts': 0.10.2(typescript@5.9.3) + '@scalar/workspace-store': 0.49.2(typescript@5.9.3) + '@vueuse/core': 13.9.0(vue@3.5.33(typescript@5.9.3)) + ai: 6.0.33(zod@4.4.3) + js-base64: 3.7.8 + neverpanic: 0.0.7(typescript@5.9.3) + truncate-json: 3.0.1 + vue: 3.5.33(typescript@5.9.3) + zod: 4.4.3 + transitivePeerDependencies: + - '@pinia/colada' + - '@vue/compiler-sfc' + - '@vue/composition-api' + - async-validator + - axios + - change-case + - drauu + - idb-keyval + - jwt-decode + - nprogress + - pinia + - qrcode + - sortablejs + - supports-color + - tailwindcss + - typescript + - universal-cookie + + '@scalar/api-client@3.6.0(@vue/compiler-sfc@3.5.33)(tailwindcss@4.2.4)(typescript@5.9.3)': + dependencies: + '@headlessui/tailwindcss': 0.2.2(tailwindcss@4.2.4) + '@headlessui/vue': 1.7.23(vue@3.5.33(typescript@5.9.3)) + '@scalar/components': 0.24.2(tailwindcss@4.2.4)(typescript@5.9.3) + '@scalar/helpers': 0.6.0 + '@scalar/icons': 0.7.2(typescript@5.9.3) + '@scalar/json-magic': 0.12.12 + '@scalar/oas-utils': 0.15.2(typescript@5.9.3) + '@scalar/openapi-types': 0.8.0 + '@scalar/postman-to-openapi': 0.7.5 + '@scalar/sidebar': 0.9.10(tailwindcss@4.2.4)(typescript@5.9.3) + '@scalar/snippetz': 0.9.6 + '@scalar/themes': 0.15.3 + '@scalar/typebox': 0.1.3 + '@scalar/types': 0.9.6 + '@scalar/use-codemirror': 0.14.11(typescript@5.9.3) + '@scalar/use-hooks': 0.4.3(typescript@5.9.3) + '@scalar/use-toasts': 0.10.2(typescript@5.9.3) + '@scalar/validation': 0.3.2 + '@scalar/workspace-store': 0.49.2(typescript@5.9.3) + '@types/har-format': 1.2.16 + '@vueuse/core': 13.9.0(vue@3.5.33(typescript@5.9.3)) + '@vueuse/integrations': 13.9.0(focus-trap@7.8.0)(fuse.js@7.3.0)(vue@3.5.33(typescript@5.9.3)) + cookie: 1.1.1 + focus-trap: 7.8.0 + fuse.js: 7.3.0 + js-base64: 3.7.8 + monaco-editor: 0.55.1 + monaco-yaml: 5.4.1(monaco-editor@0.55.1) + nanoid: 5.1.11 + pretty-ms: 9.3.0 + radix-vue: 1.9.17(vue@3.5.33(typescript@5.9.3)) + set-cookie-parser: 3.1.0 + shell-quote: 1.8.3 + vite-plugin-monaco-editor: 1.1.0(monaco-editor@0.55.1) + vue: 3.5.33(typescript@5.9.3) + vue-router: 5.0.4(@vue/compiler-sfc@3.5.33)(vue@3.5.33(typescript@5.9.3)) + yaml: 2.8.4 + zod: 4.4.3 + transitivePeerDependencies: + - '@pinia/colada' + - '@vue/compiler-sfc' + - '@vue/composition-api' + - async-validator + - axios + - change-case + - drauu + - idb-keyval + - jwt-decode + - nprogress + - pinia + - qrcode + - sortablejs + - supports-color + - tailwindcss + - typescript + - universal-cookie + + '@scalar/api-reference-react@0.9.33(@vue/compiler-sfc@3.5.33)(react@19.2.6)(tailwindcss@4.2.4)(typescript@5.9.3)': + dependencies: + '@scalar/api-reference': 1.55.2(@vue/compiler-sfc@3.5.33)(tailwindcss@4.2.4)(typescript@5.9.3) + '@scalar/types': 0.9.6 + react: 19.2.6 + transitivePeerDependencies: + - '@pinia/colada' + - '@vue/compiler-sfc' + - '@vue/composition-api' + - async-validator + - axios + - change-case + - drauu + - idb-keyval + - jwt-decode + - nprogress + - pinia + - qrcode + - sortablejs + - supports-color + - tailwindcss + - typescript + - universal-cookie + + '@scalar/api-reference@1.55.2(@vue/compiler-sfc@3.5.33)(tailwindcss@4.2.4)(typescript@5.9.3)': + dependencies: + '@headlessui/vue': 1.7.23(vue@3.5.33(typescript@5.9.3)) + '@scalar/agent-chat': 0.10.14(@vue/compiler-sfc@3.5.33)(tailwindcss@4.2.4)(typescript@5.9.3) + '@scalar/api-client': 3.6.0(@vue/compiler-sfc@3.5.33)(tailwindcss@4.2.4)(typescript@5.9.3) + '@scalar/code-highlight': 0.3.4 + '@scalar/components': 0.24.2(tailwindcss@4.2.4)(typescript@5.9.3) + '@scalar/helpers': 0.6.0 + '@scalar/icons': 0.7.2(typescript@5.9.3) + '@scalar/oas-utils': 0.15.2(typescript@5.9.3) + '@scalar/sidebar': 0.9.10(tailwindcss@4.2.4)(typescript@5.9.3) + '@scalar/snippetz': 0.9.6 + '@scalar/themes': 0.15.3 + '@scalar/types': 0.9.6 + '@scalar/use-hooks': 0.4.3(typescript@5.9.3) + '@scalar/use-toasts': 0.10.2(typescript@5.9.3) + '@scalar/workspace-store': 0.49.2(typescript@5.9.3) + '@unhead/vue': 2.1.13(vue@3.5.33(typescript@5.9.3)) + '@vueuse/core': 13.9.0(vue@3.5.33(typescript@5.9.3)) + fuse.js: 7.3.0 + microdiff: 1.5.0 + nanoid: 5.1.11 + vue: 3.5.33(typescript@5.9.3) + yaml: 2.8.4 + transitivePeerDependencies: + - '@pinia/colada' + - '@vue/compiler-sfc' + - '@vue/composition-api' + - async-validator + - axios + - change-case + - drauu + - idb-keyval + - jwt-decode + - nprogress + - pinia + - qrcode + - sortablejs + - supports-color + - tailwindcss + - typescript + - universal-cookie + + '@scalar/code-highlight@0.3.4': + dependencies: + hast-util-to-text: 4.0.2 + highlight.js: 11.11.1 + lowlight: 3.3.0 + rehype-external-links: 3.0.0 + rehype-format: 5.0.1 + rehype-parse: 9.0.1 + rehype-raw: 7.0.0 + rehype-sanitize: 6.0.0 + rehype-stringify: 10.0.1 + remark-gfm: 4.0.1 + remark-parse: 11.0.0 + remark-rehype: 11.1.2 + remark-stringify: 11.0.0 + unified: 11.0.5 + unist-util-visit: 5.1.0 + transitivePeerDependencies: + - supports-color + + '@scalar/components@0.24.2(tailwindcss@4.2.4)(typescript@5.9.3)': + dependencies: + '@floating-ui/utils': 0.2.10 + '@floating-ui/vue': 1.1.9(vue@3.5.33(typescript@5.9.3)) + '@headlessui/tailwindcss': 0.2.2(tailwindcss@4.2.4) + '@headlessui/vue': 1.7.23(vue@3.5.33(typescript@5.9.3)) + '@scalar/code-highlight': 0.3.4 + '@scalar/helpers': 0.6.0 + '@scalar/icons': 0.7.2(typescript@5.9.3) + '@scalar/themes': 0.15.3 + '@scalar/use-hooks': 0.4.3(typescript@5.9.3) + '@vueuse/core': 13.9.0(vue@3.5.33(typescript@5.9.3)) + cva: 1.0.0-beta.4(typescript@5.9.3) + nanoid: 5.1.11 + radix-vue: 1.9.17(vue@3.5.33(typescript@5.9.3)) + vue: 3.5.33(typescript@5.9.3) + vue-component-type-helpers: 3.2.8 + transitivePeerDependencies: + - '@vue/composition-api' + - supports-color + - tailwindcss + - typescript + + '@scalar/helpers@0.6.0': {} + + '@scalar/icons@0.7.2(typescript@5.9.3)': + dependencies: + '@phosphor-icons/core': 2.1.1 + '@types/node': 24.12.3 + chalk: 5.6.2 + vue: 3.5.33(typescript@5.9.3) + transitivePeerDependencies: + - typescript + + '@scalar/json-magic@0.12.12': + dependencies: + '@scalar/helpers': 0.6.0 + pathe: 2.0.3 + yaml: 2.8.4 + + '@scalar/oas-utils@0.15.2(typescript@5.9.3)': + dependencies: + '@scalar/helpers': 0.6.0 + '@scalar/themes': 0.15.3 + '@scalar/types': 0.9.6 + '@scalar/workspace-store': 0.49.2(typescript@5.9.3) + flatted: 3.4.2 + vue: 3.5.33(typescript@5.9.3) + yaml: 2.8.4 + transitivePeerDependencies: + - typescript + + '@scalar/openapi-types@0.8.0': {} + + '@scalar/openapi-upgrader@0.2.7': + dependencies: + '@scalar/openapi-types': 0.8.0 + + '@scalar/postman-to-openapi@0.7.5': + dependencies: + '@scalar/helpers': 0.6.0 + '@scalar/openapi-types': 0.8.0 + + '@scalar/sidebar@0.9.10(tailwindcss@4.2.4)(typescript@5.9.3)': + dependencies: + '@scalar/components': 0.24.2(tailwindcss@4.2.4)(typescript@5.9.3) + '@scalar/helpers': 0.6.0 + '@scalar/icons': 0.7.2(typescript@5.9.3) + '@scalar/themes': 0.15.3 + '@scalar/use-hooks': 0.4.3(typescript@5.9.3) + '@scalar/workspace-store': 0.49.2(typescript@5.9.3) + vue: 3.5.33(typescript@5.9.3) + transitivePeerDependencies: + - '@vue/composition-api' + - supports-color + - tailwindcss + - typescript + + '@scalar/snippetz@0.9.6': + dependencies: + '@scalar/types': 0.9.6 + js-base64: 3.7.8 + stringify-object: 6.0.0 + + '@scalar/themes@0.15.3': + dependencies: + nanoid: 5.1.11 + + '@scalar/typebox@0.1.3': {} + + '@scalar/types@0.9.6': + dependencies: + '@scalar/helpers': 0.6.0 + nanoid: 5.1.11 + type-fest: 5.6.0 + zod: 4.4.3 + + '@scalar/use-codemirror@0.14.11(typescript@5.9.3)': + dependencies: + '@codemirror/autocomplete': 6.20.1 + '@codemirror/commands': 6.10.3 + '@codemirror/lang-css': 6.3.1 + '@codemirror/lang-html': 6.4.11 + '@codemirror/lang-json': 6.0.2 + '@codemirror/lang-xml': 6.1.0 + '@codemirror/lang-yaml': 6.1.3 + '@codemirror/language': 6.12.3 + '@codemirror/lint': 6.9.5 + '@codemirror/state': 6.6.0 + '@codemirror/view': 6.41.1 + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@replit/codemirror-css-color-picker': 6.3.0(@codemirror/language@6.12.3)(@codemirror/state@6.6.0)(@codemirror/view@6.41.1) + vue: 3.5.33(typescript@5.9.3) + transitivePeerDependencies: + - typescript + + '@scalar/use-hooks@0.4.3(typescript@5.9.3)': + dependencies: + '@scalar/use-toasts': 0.10.2(typescript@5.9.3) + '@vueuse/core': 13.9.0(vue@3.5.33(typescript@5.9.3)) + cva: 1.0.0-beta.4(typescript@5.9.3) + tailwind-merge: 3.5.0 + vue: 3.5.33(typescript@5.9.3) + zod: 4.4.3 + transitivePeerDependencies: + - typescript + + '@scalar/use-toasts@0.10.2(typescript@5.9.3)': + dependencies: + vue: 3.5.33(typescript@5.9.3) + vue-sonner: 1.3.2 + transitivePeerDependencies: + - typescript + + '@scalar/validation@0.3.2': {} + + '@scalar/workspace-store@0.49.2(typescript@5.9.3)': + dependencies: + '@scalar/helpers': 0.6.0 + '@scalar/json-magic': 0.12.12 + '@scalar/openapi-upgrader': 0.2.7 + '@scalar/snippetz': 0.9.6 + '@scalar/typebox': 0.1.3 + '@scalar/types': 0.9.6 + '@scalar/validation': 0.3.2 + js-base64: 3.7.8 + type-fest: 5.6.0 + vue: 3.5.33(typescript@5.9.3) + yaml: 2.8.4 + transitivePeerDependencies: + - typescript + + '@standard-schema/spec@1.1.0': {} + + '@swc/helpers@0.5.21': + dependencies: + tslib: 2.8.1 + + '@tailwindcss/node@4.2.4': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.21.2 + jiti: 2.7.0 + lightningcss: 1.32.0 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.2.4 + + '@tailwindcss/oxide-android-arm64@4.2.4': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.2.4': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.2.4': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.2.4': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.4': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.2.4': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.2.4': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.2.4': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.2.4': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.2.4': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.2.4': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.2.4': + optional: true + + '@tailwindcss/oxide@4.2.4': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.2.4 + '@tailwindcss/oxide-darwin-arm64': 4.2.4 + '@tailwindcss/oxide-darwin-x64': 4.2.4 + '@tailwindcss/oxide-freebsd-x64': 4.2.4 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.2.4 + '@tailwindcss/oxide-linux-arm64-gnu': 4.2.4 + '@tailwindcss/oxide-linux-arm64-musl': 4.2.4 + '@tailwindcss/oxide-linux-x64-gnu': 4.2.4 + '@tailwindcss/oxide-linux-x64-musl': 4.2.4 + '@tailwindcss/oxide-wasm32-wasi': 4.2.4 + '@tailwindcss/oxide-win32-arm64-msvc': 4.2.4 + '@tailwindcss/oxide-win32-x64-msvc': 4.2.4 + + '@tailwindcss/vite@4.2.4(vite@7.3.3(@types/node@24.12.3)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.4))': + dependencies: + '@tailwindcss/node': 4.2.4 + '@tailwindcss/oxide': 4.2.4 + tailwindcss: 4.2.4 + vite: 7.3.3(@types/node@24.12.3)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.4) + + '@tanstack/query-core@5.100.9': {} + + '@tanstack/react-query@5.100.9(react@19.2.6)': + dependencies: + '@tanstack/query-core': 5.100.9 + react: 19.2.6 + + '@tanstack/virtual-core@3.14.0': {} + + '@tanstack/vue-virtual@3.13.24(vue@3.5.33(typescript@5.9.3))': + dependencies: + '@tanstack/virtual-core': 3.14.0 + vue: 3.5.33(typescript@5.9.3) + + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.29.3 + '@babel/types': 7.29.0 + '@types/babel__generator': 7.27.0 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.28.0 + + '@types/babel__generator@7.27.0': + dependencies: + '@babel/types': 7.29.0 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.29.3 + '@babel/types': 7.29.0 + + '@types/babel__traverse@7.28.0': + dependencies: + '@babel/types': 7.29.0 + + '@types/debug@4.1.13': + dependencies: + '@types/ms': 2.1.0 + + '@types/estree@1.0.8': {} + + '@types/har-format@1.2.16': {} + + '@types/hast@3.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/ms@2.1.0': {} + + '@types/node@24.12.3': + dependencies: + undici-types: 7.16.0 + + '@types/react-dom@19.2.3(@types/react@19.2.14)': + dependencies: + '@types/react': 19.2.14 + + '@types/react@19.2.14': + dependencies: + csstype: 3.2.3 + + '@types/trusted-types@2.0.7': + optional: true + + '@types/unist@3.0.3': {} + + '@types/web-bluetooth@0.0.20': {} + + '@types/web-bluetooth@0.0.21': {} + + '@ungap/structured-clone@1.3.1': {} + + '@unhead/vue@2.1.13(vue@3.5.33(typescript@5.9.3))': + dependencies: + hookable: 6.1.1 + unhead: 2.1.13 + vue: 3.5.33(typescript@5.9.3) + + '@vercel/oidc@3.1.0': {} + + '@vitejs/plugin-react@5.2.0(vite@7.3.3(@types/node@24.12.3)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.4))': + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.29.0) + '@rolldown/pluginutils': 1.0.0-rc.3 + '@types/babel__core': 7.20.5 + react-refresh: 0.18.0 + vite: 7.3.3(@types/node@24.12.3)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.4) + transitivePeerDependencies: + - supports-color + + '@vue-macros/common@3.1.2(vue@3.5.33(typescript@5.9.3))': + dependencies: + '@vue/compiler-sfc': 3.5.33 + ast-kit: 2.2.0 + local-pkg: 1.1.2 + magic-string-ast: 1.0.3 + unplugin-utils: 0.3.1 + optionalDependencies: + vue: 3.5.33(typescript@5.9.3) + + '@vue/compiler-core@3.5.33': + dependencies: + '@babel/parser': 7.29.3 + '@vue/shared': 3.5.33 + entities: 7.0.1 + estree-walker: 2.0.2 + source-map-js: 1.2.1 + + '@vue/compiler-dom@3.5.33': + dependencies: + '@vue/compiler-core': 3.5.33 + '@vue/shared': 3.5.33 + + '@vue/compiler-sfc@3.5.33': + dependencies: + '@babel/parser': 7.29.3 + '@vue/compiler-core': 3.5.33 + '@vue/compiler-dom': 3.5.33 + '@vue/compiler-ssr': 3.5.33 + '@vue/shared': 3.5.33 + estree-walker: 2.0.2 + magic-string: 0.30.21 + postcss: 8.5.14 + source-map-js: 1.2.1 + + '@vue/compiler-ssr@3.5.33': + dependencies: + '@vue/compiler-dom': 3.5.33 + '@vue/shared': 3.5.33 + + '@vue/devtools-api@8.1.1': + dependencies: + '@vue/devtools-kit': 8.1.1 + + '@vue/devtools-kit@8.1.1': + dependencies: + '@vue/devtools-shared': 8.1.1 + birpc: 2.9.0 + hookable: 5.5.3 + perfect-debounce: 2.1.0 + + '@vue/devtools-shared@8.1.1': {} + + '@vue/reactivity@3.5.33': + dependencies: + '@vue/shared': 3.5.33 + + '@vue/runtime-core@3.5.33': + dependencies: + '@vue/reactivity': 3.5.33 + '@vue/shared': 3.5.33 + + '@vue/runtime-dom@3.5.33': + dependencies: + '@vue/reactivity': 3.5.33 + '@vue/runtime-core': 3.5.33 + '@vue/shared': 3.5.33 + csstype: 3.2.3 + + '@vue/server-renderer@3.5.33(vue@3.5.33(typescript@5.9.3))': + dependencies: + '@vue/compiler-ssr': 3.5.33 + '@vue/shared': 3.5.33 + vue: 3.5.33(typescript@5.9.3) + + '@vue/shared@3.5.33': {} + + '@vueuse/core@10.11.1(vue@3.5.33(typescript@5.9.3))': + dependencies: + '@types/web-bluetooth': 0.0.20 + '@vueuse/metadata': 10.11.1 + '@vueuse/shared': 10.11.1(vue@3.5.33(typescript@5.9.3)) + vue-demi: 0.14.10(vue@3.5.33(typescript@5.9.3)) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + + '@vueuse/core@13.9.0(vue@3.5.33(typescript@5.9.3))': + dependencies: + '@types/web-bluetooth': 0.0.21 + '@vueuse/metadata': 13.9.0 + '@vueuse/shared': 13.9.0(vue@3.5.33(typescript@5.9.3)) + vue: 3.5.33(typescript@5.9.3) + + '@vueuse/integrations@13.9.0(focus-trap@7.8.0)(fuse.js@7.3.0)(vue@3.5.33(typescript@5.9.3))': + dependencies: + '@vueuse/core': 13.9.0(vue@3.5.33(typescript@5.9.3)) + '@vueuse/shared': 13.9.0(vue@3.5.33(typescript@5.9.3)) + vue: 3.5.33(typescript@5.9.3) + optionalDependencies: + focus-trap: 7.8.0 + fuse.js: 7.3.0 + + '@vueuse/metadata@10.11.1': {} + + '@vueuse/metadata@13.9.0': {} + + '@vueuse/shared@10.11.1(vue@3.5.33(typescript@5.9.3))': + dependencies: + vue-demi: 0.14.10(vue@3.5.33(typescript@5.9.3)) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + + '@vueuse/shared@13.9.0(vue@3.5.33(typescript@5.9.3))': + dependencies: + vue: 3.5.33(typescript@5.9.3) + + acorn@8.16.0: {} + + ai@6.0.33(zod@4.4.3): + dependencies: + '@ai-sdk/gateway': 3.0.13(zod@4.4.3) + '@ai-sdk/provider': 3.0.2 + '@ai-sdk/provider-utils': 4.0.5(zod@4.4.3) + '@opentelemetry/api': 1.9.0 + zod: 4.4.3 + + aria-hidden@1.2.6: + dependencies: + tslib: 2.8.1 + + ast-kit@2.2.0: + dependencies: + '@babel/parser': 7.29.3 + pathe: 2.0.3 + + ast-walker-scope@0.8.3: + dependencies: + '@babel/parser': 7.29.3 + ast-kit: 2.2.0 + + bail@2.0.2: {} + + baseline-browser-mapping@2.10.27: {} + + birpc@2.9.0: {} + + browserslist@4.28.2: + dependencies: + baseline-browser-mapping: 2.10.27 + caniuse-lite: 1.0.30001792 + electron-to-chromium: 1.5.352 + node-releases: 2.0.38 + update-browserslist-db: 1.2.3(browserslist@4.28.2) + + caniuse-lite@1.0.30001792: {} + + ccount@2.0.1: {} + + chalk@5.6.2: {} + + character-entities-html4@2.1.0: {} + + character-entities-legacy@3.0.0: {} + + character-entities@2.0.2: {} + + chokidar@5.0.0: + dependencies: + readdirp: 5.0.0 + + class-variance-authority@0.7.1: + dependencies: + clsx: 2.1.1 + + clsx@2.1.1: {} + + comma-separated-tokens@2.0.3: {} + + confbox@0.1.8: {} + + confbox@0.2.4: {} + + convert-hrtime@5.0.0: {} + + convert-source-map@2.0.0: {} + + cookie@1.1.1: {} + + crelt@1.0.6: {} + + csstype@3.2.3: {} + + cva@1.0.0-beta.4(typescript@5.9.3): + dependencies: + clsx: 2.1.1 + optionalDependencies: + typescript: 5.9.3 + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + decode-named-character-reference@1.3.0: + dependencies: + character-entities: 2.0.2 + + defu@6.1.7: {} + + dequal@2.0.3: {} + + detect-libc@2.1.2: {} + + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + + dompurify@3.2.7: + optionalDependencies: + '@types/trusted-types': 2.0.7 + + electron-to-chromium@1.5.352: {} + + enhanced-resolve@5.21.2: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.3 + + entities@6.0.1: {} + + entities@7.0.1: {} + + esbuild@0.27.7: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.7 + '@esbuild/android-arm': 0.27.7 + '@esbuild/android-arm64': 0.27.7 + '@esbuild/android-x64': 0.27.7 + '@esbuild/darwin-arm64': 0.27.7 + '@esbuild/darwin-x64': 0.27.7 + '@esbuild/freebsd-arm64': 0.27.7 + '@esbuild/freebsd-x64': 0.27.7 + '@esbuild/linux-arm': 0.27.7 + '@esbuild/linux-arm64': 0.27.7 + '@esbuild/linux-ia32': 0.27.7 + '@esbuild/linux-loong64': 0.27.7 + '@esbuild/linux-mips64el': 0.27.7 + '@esbuild/linux-ppc64': 0.27.7 + '@esbuild/linux-riscv64': 0.27.7 + '@esbuild/linux-s390x': 0.27.7 + '@esbuild/linux-x64': 0.27.7 + '@esbuild/netbsd-arm64': 0.27.7 + '@esbuild/netbsd-x64': 0.27.7 + '@esbuild/openbsd-arm64': 0.27.7 + '@esbuild/openbsd-x64': 0.27.7 + '@esbuild/openharmony-arm64': 0.27.7 + '@esbuild/sunos-x64': 0.27.7 + '@esbuild/win32-arm64': 0.27.7 + '@esbuild/win32-ia32': 0.27.7 + '@esbuild/win32-x64': 0.27.7 + + escalade@3.2.0: {} + + escape-string-regexp@5.0.0: {} + + estree-walker@2.0.2: {} + + eventsource-parser@3.0.8: {} + + exsolve@1.0.8: {} + + extend@3.0.2: {} + + fast-deep-equal@3.1.3: {} + + fdir@6.5.0(picomatch@4.0.4): + optionalDependencies: + picomatch: 4.0.4 + + flatted@3.4.2: {} + + focus-trap@7.8.0: + dependencies: + tabbable: 6.4.0 + + fsevents@2.3.3: + optional: true + + function-timeout@1.0.2: {} + + fuse.js@7.3.0: {} + + gensync@1.0.0-beta.2: {} + + get-own-enumerable-keys@1.0.0: {} + + graceful-fs@4.2.11: {} + + guess-json-indent@3.0.1: {} + + hast-util-embedded@3.0.0: + dependencies: + '@types/hast': 3.0.4 + hast-util-is-element: 3.0.0 + + hast-util-format@1.1.0: + dependencies: + '@types/hast': 3.0.4 + hast-util-embedded: 3.0.0 + hast-util-minify-whitespace: 1.0.1 + hast-util-phrasing: 3.0.1 + hast-util-whitespace: 3.0.0 + html-whitespace-sensitive-tag-names: 3.0.1 + unist-util-visit-parents: 6.0.2 + + hast-util-from-html@2.0.3: + dependencies: + '@types/hast': 3.0.4 + devlop: 1.1.0 + hast-util-from-parse5: 8.0.3 + parse5: 7.3.0 + vfile: 6.0.3 + vfile-message: 4.0.3 + + hast-util-from-parse5@8.0.3: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + devlop: 1.1.0 + hastscript: 9.0.1 + property-information: 7.1.0 + vfile: 6.0.3 + vfile-location: 5.0.3 + web-namespaces: 2.0.1 + + hast-util-has-property@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-is-body-ok-link@3.0.1: + dependencies: + '@types/hast': 3.0.4 + + hast-util-is-element@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-minify-whitespace@1.0.1: + dependencies: + '@types/hast': 3.0.4 + hast-util-embedded: 3.0.0 + hast-util-is-element: 3.0.0 + hast-util-whitespace: 3.0.0 + unist-util-is: 6.0.1 + + hast-util-parse-selector@4.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-phrasing@3.0.1: + dependencies: + '@types/hast': 3.0.4 + hast-util-embedded: 3.0.0 + hast-util-has-property: 3.0.0 + hast-util-is-body-ok-link: 3.0.1 + hast-util-is-element: 3.0.0 + + hast-util-raw@9.1.0: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + '@ungap/structured-clone': 1.3.1 + hast-util-from-parse5: 8.0.3 + hast-util-to-parse5: 8.0.1 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.1 + parse5: 7.3.0 + unist-util-position: 5.0.0 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + web-namespaces: 2.0.1 + zwitch: 2.0.4 + + hast-util-sanitize@5.0.2: + dependencies: + '@types/hast': 3.0.4 + '@ungap/structured-clone': 1.3.1 + unist-util-position: 5.0.0 + + hast-util-to-html@9.0.5: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + comma-separated-tokens: 2.0.3 + hast-util-whitespace: 3.0.0 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.1 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + stringify-entities: 4.0.4 + zwitch: 2.0.4 + + hast-util-to-parse5@8.0.1: + dependencies: + '@types/hast': 3.0.4 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + web-namespaces: 2.0.1 + zwitch: 2.0.4 + + hast-util-to-text@4.0.2: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + hast-util-is-element: 3.0.0 + unist-util-find-after: 5.0.0 + + hast-util-whitespace@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hastscript@9.0.1: + dependencies: + '@types/hast': 3.0.4 + comma-separated-tokens: 2.0.3 + hast-util-parse-selector: 4.0.0 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + + highlight.js@11.11.1: {} + + hookable@5.5.3: {} + + hookable@6.1.1: {} + + html-void-elements@3.0.0: {} + + html-whitespace-sensitive-tag-names@3.0.1: {} + + identifier-regex@1.0.1: + dependencies: + reserved-identifiers: 1.2.0 + + is-absolute-url@4.0.1: {} + + is-identifier@1.0.1: + dependencies: + identifier-regex: 1.0.1 + super-regex: 1.1.0 + + is-obj@3.0.0: {} + + is-plain-obj@4.1.0: {} + + is-regexp@3.1.0: {} + + jiti@2.7.0: {} + + js-base64@3.7.8: {} + + js-tokens@4.0.0: {} + + jsesc@3.1.0: {} + + json-schema@0.4.0: {} + + json5@2.2.3: {} + + jsonc-parser@3.3.1: {} + + lightningcss-android-arm64@1.32.0: + optional: true + + lightningcss-darwin-arm64@1.32.0: + optional: true + + lightningcss-darwin-x64@1.32.0: + optional: true + + lightningcss-freebsd-x64@1.32.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + + lightningcss-linux-arm64-musl@1.32.0: + optional: true + + lightningcss-linux-x64-gnu@1.32.0: + optional: true + + lightningcss-linux-x64-musl@1.32.0: + optional: true + + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + + lightningcss-win32-x64-msvc@1.32.0: + optional: true + + lightningcss@1.32.0: + dependencies: + detect-libc: 2.1.2 + 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 + + local-pkg@1.1.2: + dependencies: + mlly: 1.8.2 + pkg-types: 2.3.1 + quansync: 0.2.11 + + longest-streak@3.1.0: {} + + lowlight@3.3.0: + dependencies: + '@types/hast': 3.0.4 + devlop: 1.1.0 + highlight.js: 11.11.1 + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + lucide-react@0.469.0(react@19.2.6): + dependencies: + react: 19.2.6 + + lucide-react@0.553.0(react@19.2.6): + dependencies: + react: 19.2.6 + + magic-string-ast@1.0.3: + dependencies: + magic-string: 0.30.21 + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + make-asynchronous@1.1.0: + dependencies: + p-event: 6.0.1 + type-fest: 4.41.0 + web-worker: 1.5.0 + + markdown-table@3.0.4: {} + + marked@14.0.0: {} + + mdast-util-find-and-replace@3.0.2: + dependencies: + '@types/mdast': 4.0.4 + escape-string-regexp: 5.0.0 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + mdast-util-from-markdown@2.0.3: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + mdast-util-to-string: 4.0.0 + micromark: 4.0.2 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-decode-string: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-stringify-position: 4.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-autolink-literal@2.0.1: + dependencies: + '@types/mdast': 4.0.4 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-find-and-replace: 3.0.2 + micromark-util-character: 2.1.1 + + mdast-util-gfm-footnote@2.1.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + micromark-util-normalize-identifier: 2.0.1 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-strikethrough@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-table@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + markdown-table: 3.0.4 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-task-list-item@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm@3.1.0: + dependencies: + mdast-util-from-markdown: 2.0.3 + mdast-util-gfm-autolink-literal: 2.0.1 + mdast-util-gfm-footnote: 2.1.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.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-phrasing@4.1.0: + dependencies: + '@types/mdast': 4.0.4 + unist-util-is: 6.0.1 + + mdast-util-to-hast@13.2.1: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@ungap/structured-clone': 1.3.1 + devlop: 1.1.0 + micromark-util-sanitize-uri: 2.0.1 + trim-lines: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + + mdast-util-to-markdown@2.1.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + longest-streak: 3.1.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-string: 4.0.0 + micromark-util-classify-character: 2.0.1 + micromark-util-decode-string: 2.0.1 + unist-util-visit: 5.1.0 + zwitch: 2.0.4 + + mdast-util-to-string@4.0.0: + dependencies: + '@types/mdast': 4.0.4 + + microdiff@1.5.0: {} + + micromark-core-commonmark@2.0.3: + dependencies: + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-factory-destination: 2.0.1 + micromark-factory-label: 2.0.1 + micromark-factory-space: 2.0.1 + micromark-factory-title: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-html-tag-name: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-autolink-literal@2.1.0: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-footnote@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-strikethrough@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-table@2.1.1: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-tagfilter@2.0.0: + dependencies: + micromark-util-types: 2.0.2 + + micromark-extension-gfm-task-list-item@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm@3.0.0: + dependencies: + micromark-extension-gfm-autolink-literal: 2.1.0 + micromark-extension-gfm-footnote: 2.1.0 + micromark-extension-gfm-strikethrough: 2.1.0 + micromark-extension-gfm-table: 2.1.1 + micromark-extension-gfm-tagfilter: 2.0.0 + micromark-extension-gfm-task-list-item: 2.1.0 + micromark-util-combine-extensions: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-destination@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-label@2.0.1: + dependencies: + devlop: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-space@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.2 + + micromark-factory-title@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-whitespace@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-chunked@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-classify-character@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-combine-extensions@2.0.1: + dependencies: + micromark-util-chunked: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-decode-numeric-character-reference@2.0.2: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-decode-string@2.0.1: + dependencies: + decode-named-character-reference: 1.3.0 + micromark-util-character: 2.1.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-symbol: 2.0.1 + + micromark-util-encode@2.0.1: {} + + micromark-util-html-tag-name@2.0.1: {} + + micromark-util-normalize-identifier@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-resolve-all@2.0.1: + dependencies: + micromark-util-types: 2.0.2 + + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 + + micromark-util-subtokenize@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-symbol@2.0.1: {} + + micromark-util-types@2.0.2: {} + + micromark@4.0.2: + dependencies: + '@types/debug': 4.1.13 + debug: 4.4.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + transitivePeerDependencies: + - supports-color + + mlly@1.8.2: + dependencies: + acorn: 8.16.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.4 + + monaco-editor@0.55.1: + dependencies: + dompurify: 3.2.7 + marked: 14.0.0 + + monaco-languageserver-types@0.4.0: + dependencies: + monaco-types: 0.1.2 + vscode-languageserver-protocol: 3.17.5 + vscode-uri: 3.1.0 + + monaco-marker-data-provider@1.2.5: + dependencies: + monaco-types: 0.1.2 + + monaco-types@0.1.2: {} + + monaco-worker-manager@2.0.1(monaco-editor@0.55.1): + dependencies: + monaco-editor: 0.55.1 + + monaco-yaml@5.4.1(monaco-editor@0.55.1): + dependencies: + jsonc-parser: 3.3.1 + monaco-editor: 0.55.1 + monaco-languageserver-types: 0.4.0 + monaco-marker-data-provider: 1.2.5 + monaco-types: 0.1.2 + monaco-worker-manager: 2.0.1(monaco-editor@0.55.1) + path-browserify: 1.0.1 + prettier: 3.8.3 + vscode-languageserver-textdocument: 1.0.12 + vscode-languageserver-types: 3.17.5 + vscode-uri: 3.1.0 + yaml: 2.8.4 + + ms@2.1.3: {} + + muggle-string@0.4.1: {} + + nanoid@3.3.12: {} + + nanoid@5.1.11: {} + + neverpanic@0.0.7(typescript@5.9.3): + dependencies: + typescript: 5.9.3 + + node-releases@2.0.38: {} + + p-event@6.0.1: + dependencies: + p-timeout: 6.1.4 + + p-timeout@6.1.4: {} + + parse-ms@4.0.0: {} + + parse5@7.3.0: + dependencies: + entities: 6.0.1 + + path-browserify@1.0.1: {} + + pathe@2.0.3: {} + + perfect-debounce@2.1.0: {} + + picocolors@1.1.1: {} + + picomatch@4.0.4: {} + + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.8.2 + pathe: 2.0.3 + + pkg-types@2.3.1: + dependencies: + confbox: 0.2.4 + exsolve: 1.0.8 + pathe: 2.0.3 + + postcss@8.5.14: + dependencies: + nanoid: 3.3.12 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prettier@3.8.3: {} + + pretty-ms@9.3.0: + dependencies: + parse-ms: 4.0.0 + + property-information@7.1.0: {} + + quansync@0.2.11: {} + + radix-vue@1.9.17(vue@3.5.33(typescript@5.9.3)): + dependencies: + '@floating-ui/dom': 1.7.6 + '@floating-ui/vue': 1.1.11(vue@3.5.33(typescript@5.9.3)) + '@internationalized/date': 3.12.1 + '@internationalized/number': 3.6.6 + '@tanstack/vue-virtual': 3.13.24(vue@3.5.33(typescript@5.9.3)) + '@vueuse/core': 10.11.1(vue@3.5.33(typescript@5.9.3)) + '@vueuse/shared': 10.11.1(vue@3.5.33(typescript@5.9.3)) + aria-hidden: 1.2.6 + defu: 6.1.7 + fast-deep-equal: 3.1.3 + nanoid: 5.1.11 + vue: 3.5.33(typescript@5.9.3) + transitivePeerDependencies: + - '@vue/composition-api' + + react-dom@19.2.6(react@19.2.6): + dependencies: + react: 19.2.6 + scheduler: 0.27.0 + + react-refresh@0.18.0: {} + + react@19.2.6: {} + + readdirp@5.0.0: {} + + rehype-external-links@3.0.0: + dependencies: + '@types/hast': 3.0.4 + '@ungap/structured-clone': 1.3.1 + hast-util-is-element: 3.0.0 + is-absolute-url: 4.0.1 + space-separated-tokens: 2.0.2 + unist-util-visit: 5.1.0 + + rehype-format@5.0.1: + dependencies: + '@types/hast': 3.0.4 + hast-util-format: 1.1.0 + + rehype-parse@9.0.1: + dependencies: + '@types/hast': 3.0.4 + hast-util-from-html: 2.0.3 + unified: 11.0.5 + + rehype-raw@7.0.0: + dependencies: + '@types/hast': 3.0.4 + hast-util-raw: 9.1.0 + vfile: 6.0.3 + + rehype-sanitize@6.0.0: + dependencies: + '@types/hast': 3.0.4 + hast-util-sanitize: 5.0.2 + + rehype-stringify@10.0.1: + dependencies: + '@types/hast': 3.0.4 + hast-util-to-html: 9.0.5 + unified: 11.0.5 + + remark-gfm@4.0.1: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-gfm: 3.1.0 + micromark-extension-gfm: 3.0.0 + remark-parse: 11.0.0 + remark-stringify: 11.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-parse@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.3 + micromark-util-types: 2.0.2 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-rehype@11.1.2: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + mdast-util-to-hast: 13.2.1 + unified: 11.0.5 + vfile: 6.0.3 + + remark-stringify@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-to-markdown: 2.1.2 + unified: 11.0.5 + + reserved-identifiers@1.2.0: {} + + rollup@4.60.3: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.60.3 + '@rollup/rollup-android-arm64': 4.60.3 + '@rollup/rollup-darwin-arm64': 4.60.3 + '@rollup/rollup-darwin-x64': 4.60.3 + '@rollup/rollup-freebsd-arm64': 4.60.3 + '@rollup/rollup-freebsd-x64': 4.60.3 + '@rollup/rollup-linux-arm-gnueabihf': 4.60.3 + '@rollup/rollup-linux-arm-musleabihf': 4.60.3 + '@rollup/rollup-linux-arm64-gnu': 4.60.3 + '@rollup/rollup-linux-arm64-musl': 4.60.3 + '@rollup/rollup-linux-loong64-gnu': 4.60.3 + '@rollup/rollup-linux-loong64-musl': 4.60.3 + '@rollup/rollup-linux-ppc64-gnu': 4.60.3 + '@rollup/rollup-linux-ppc64-musl': 4.60.3 + '@rollup/rollup-linux-riscv64-gnu': 4.60.3 + '@rollup/rollup-linux-riscv64-musl': 4.60.3 + '@rollup/rollup-linux-s390x-gnu': 4.60.3 + '@rollup/rollup-linux-x64-gnu': 4.60.3 + '@rollup/rollup-linux-x64-musl': 4.60.3 + '@rollup/rollup-openbsd-x64': 4.60.3 + '@rollup/rollup-openharmony-arm64': 4.60.3 + '@rollup/rollup-win32-arm64-msvc': 4.60.3 + '@rollup/rollup-win32-ia32-msvc': 4.60.3 + '@rollup/rollup-win32-x64-gnu': 4.60.3 + '@rollup/rollup-win32-x64-msvc': 4.60.3 + fsevents: 2.3.3 + + scheduler@0.27.0: {} + + scule@1.3.0: {} + + semver@6.3.1: {} + + set-cookie-parser@3.1.0: {} + + shell-quote@1.8.3: {} + + source-map-js@1.2.1: {} + + space-separated-tokens@2.0.2: {} + + string-byte-length@3.0.1: {} + + string-byte-slice@3.0.1: {} + + stringify-entities@4.0.4: + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + + stringify-object@6.0.0: + dependencies: + get-own-enumerable-keys: 1.0.0 + is-identifier: 1.0.1 + is-obj: 3.0.0 + is-regexp: 3.1.0 + + style-mod@4.1.3: {} + + super-regex@1.1.0: + dependencies: + function-timeout: 1.0.2 + make-asynchronous: 1.1.0 + time-span: 5.1.0 + + swrv@1.2.0(vue@3.5.33(typescript@5.9.3)): + dependencies: + vue: 3.5.33(typescript@5.9.3) + + tabbable@6.4.0: {} + + tagged-tag@1.0.0: {} + + tailwind-merge@2.6.1: {} + + tailwind-merge@3.5.0: {} + + tailwindcss@4.2.4: {} + + tapable@2.3.3: {} + + time-span@5.1.0: + dependencies: + convert-hrtime: 5.0.0 + + tinyglobby@0.2.16: + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + + trim-lines@3.0.1: {} + + trough@2.2.0: {} + + truncate-json@3.0.1: + dependencies: + guess-json-indent: 3.0.1 + string-byte-length: 3.0.1 + string-byte-slice: 3.0.1 + + tslib@2.8.1: {} + + type-fest@4.41.0: {} + + type-fest@5.6.0: + dependencies: + tagged-tag: 1.0.0 + + typescript@5.9.3: {} + + ufo@1.6.4: {} + + undici-types@7.16.0: {} + + unhead@2.1.13: + dependencies: + hookable: 6.1.1 + + unified@11.0.5: + dependencies: + '@types/unist': 3.0.3 + bail: 2.0.2 + devlop: 1.1.0 + extend: 3.0.2 + is-plain-obj: 4.1.0 + trough: 2.2.0 + vfile: 6.0.3 + + unist-util-find-after@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-is@6.0.1: + dependencies: + '@types/unist': 3.0.3 + + unist-util-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-stringify-position@4.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-parents@6.0.2: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-visit@5.1.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + unplugin-utils@0.3.1: + dependencies: + pathe: 2.0.3 + picomatch: 4.0.4 + + unplugin@3.0.0: + dependencies: + '@jridgewell/remapping': 2.3.5 + picomatch: 4.0.4 + webpack-virtual-modules: 0.6.2 + + update-browserslist-db@1.2.3(browserslist@4.28.2): + dependencies: + browserslist: 4.28.2 + escalade: 3.2.0 + picocolors: 1.1.1 + + vfile-location@5.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile: 6.0.3 + + vfile-message@4.0.3: + dependencies: + '@types/unist': 3.0.3 + unist-util-stringify-position: 4.0.0 + + vfile@6.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile-message: 4.0.3 + + vite-plugin-monaco-editor@1.1.0(monaco-editor@0.55.1): + dependencies: + monaco-editor: 0.55.1 + + vite@7.3.3(@types/node@24.12.3)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.4): + dependencies: + esbuild: 0.27.7 + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + postcss: 8.5.14 + rollup: 4.60.3 + tinyglobby: 0.2.16 + optionalDependencies: + '@types/node': 24.12.3 + fsevents: 2.3.3 + jiti: 2.7.0 + lightningcss: 1.32.0 + yaml: 2.8.4 + + vscode-jsonrpc@8.2.0: {} + + vscode-languageserver-protocol@3.17.5: + dependencies: + vscode-jsonrpc: 8.2.0 + vscode-languageserver-types: 3.17.5 + + vscode-languageserver-textdocument@1.0.12: {} + + vscode-languageserver-types@3.17.5: {} + + vscode-uri@3.1.0: {} + + vue-component-type-helpers@3.2.8: {} + + vue-demi@0.14.10(vue@3.5.33(typescript@5.9.3)): + dependencies: + vue: 3.5.33(typescript@5.9.3) + + vue-router@5.0.4(@vue/compiler-sfc@3.5.33)(vue@3.5.33(typescript@5.9.3)): + dependencies: + '@babel/generator': 7.29.1 + '@vue-macros/common': 3.1.2(vue@3.5.33(typescript@5.9.3)) + '@vue/devtools-api': 8.1.1 + ast-walker-scope: 0.8.3 + chokidar: 5.0.0 + json5: 2.2.3 + local-pkg: 1.1.2 + magic-string: 0.30.21 + mlly: 1.8.2 + muggle-string: 0.4.1 + pathe: 2.0.3 + picomatch: 4.0.4 + scule: 1.3.0 + tinyglobby: 0.2.16 + unplugin: 3.0.0 + unplugin-utils: 0.3.1 + vue: 3.5.33(typescript@5.9.3) + yaml: 2.8.4 + optionalDependencies: + '@vue/compiler-sfc': 3.5.33 + + vue-sonner@1.3.2: {} + + vue@3.5.33(typescript@5.9.3): + dependencies: + '@vue/compiler-dom': 3.5.33 + '@vue/compiler-sfc': 3.5.33 + '@vue/runtime-dom': 3.5.33 + '@vue/server-renderer': 3.5.33(vue@3.5.33(typescript@5.9.3)) + '@vue/shared': 3.5.33 + optionalDependencies: + typescript: 5.9.3 + + w3c-keyname@2.2.8: {} + + web-namespaces@2.0.1: {} + + web-worker@1.5.0: {} + + webpack-virtual-modules@0.6.2: {} + + yallist@3.1.1: {} + + yaml@2.8.4: {} + + zod@4.4.3: {} + + zwitch@2.0.4: {} diff --git a/opensearch/ui-src/src/main.tsx b/opensearch/ui-src/src/main.tsx new file mode 100644 index 0000000..035b08a --- /dev/null +++ b/opensearch/ui-src/src/main.tsx @@ -0,0 +1,457 @@ +import React, { useEffect, useMemo, useState } from "react"; +import { createRoot } from "react-dom/client"; +import { Database, FileJson, Play, Search } from "lucide-react"; +import { Button, FilterBar, Select } from "@flanksource/clicky-ui/components"; +import { DataTable, JsonView, type DataTableColumn } from "@flanksource/clicky-ui/data"; +import { InlineError } from "@flanksource/clicky-ui/rpc"; +import "@flanksource/clicky-ui/styles.css"; +import { pluginBuildDate, pluginVersion } from "./version"; +import "./styles.css"; + +const FIELD_CLASS = "flex min-w-40 flex-col gap-1"; +const LABEL_CLASS = "text-[11px] font-semibold text-slate-500"; +const INPUT_CLASS = + "h-8 w-full rounded-md border border-slate-300 bg-white px-2 text-[13px] text-slate-950 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 disabled:cursor-not-allowed disabled:opacity-50"; + +type ProfileParam = { + name: string; + operator: string; + description?: string; + required?: boolean; +}; + +type TracingColumn = { + name: string; + field: string; + detail?: boolean; +}; + +type ProfileSummary = { + name: string; + format: string; + backend: string; + index: string; + params: ProfileParam[]; + columns: TracingColumn[]; + defaults: Record; +}; + +type Trace = { + timestamp?: string; + trace_id?: string; + span_id?: string; + parent_id?: string; + service_name?: string; + operation_name?: string; + status?: string; + duration_ms?: number; + cells?: Record; + attributes?: Record; + raw?: Record; + children?: Trace[]; +}; + +type TraceRow = Record & { + _id: string; + _depth: number; + _trace: Trace; +}; + +type TraceResult = { + profile: string; + index: string; + total: number; + traces: Trace[]; +}; + +type QueryPreview = { + profile: string; + request: { + index: string; + limit: number; + query: Record; + }; +}; + +type OperationError = Error & { + status?: number; + url?: string; + responseBody?: string; +}; + +function configIDFromURL(): string { + return new URLSearchParams(window.location.search).get("config_id") ?? ""; +} + +function operationURL(op: string): string { + const base = window.location.pathname.replace(/\/ui\/.*$/, ""); + const url = new URL(base + "/operations/" + op, window.location.origin); + const configID = configIDFromURL(); + if (configID) url.searchParams.set("config_id", configID); + return url.toString(); +} + +async function callOp(op: string, params: Record = {}): Promise { + const url = operationURL(op); + const res = await fetch(url, { + method: "POST", + headers: { "Content-Type": "application/json" }, + credentials: "same-origin", + body: JSON.stringify(params), + }); + if (!res.ok) { + const responseBody = await res.text(); + const err = new Error(responseBody || `${op} returned ${res.status}`) as OperationError; + err.status = res.status; + err.url = url; + err.responseBody = responseBody; + throw err; + } + return (await res.json()) as T; +} + +function App() { + const [profiles, setProfiles] = useState([]); + const [profileName, setProfileName] = useState(""); + const [params, setParams] = useState>({}); + const [from, setFrom] = useState(""); + const [to, setTo] = useState(""); + const [limit, setLimit] = useState(100); + const [result, setResult] = useState(null); + const [preview, setPreview] = useState(null); + const [selected, setSelected] = useState(null); + const [pendingAction, setPendingAction] = useState<"preview" | "query" | null>(null); + const [error, setError] = useState(null); + + useEffect(() => { + callOp("profiles-list") + .then((items) => { + setProfiles(items); + const first = items[0]; + if (first) { + setProfileName(first.name); + setParams(defaultParams(first)); + } + }) + .catch(setError); + }, []); + + const profile = useMemo( + () => profiles.find((item) => item.name === profileName), + [profiles, profileName], + ); + + const rows = useMemo(() => flattenTraces(result?.traces ?? []), [result]); + const columns = useMemo(() => buildColumns(profile?.columns ?? []), [profile?.columns]); + const loading = pendingAction !== null; + + function selectProfile(name: string) { + const next = profiles.find((item) => item.name === name); + setProfileName(name); + setParams(next ? defaultParams(next) : {}); + setResult(null); + setSelected(null); + setPreview(null); + } + + async function runPreview() { + if (!profile) return; + setPendingAction("preview"); + setError(null); + try { + const next = await callOp("query-preview", requestBody(profileName, params, from, to, limit)); + setPreview(next); + } catch (err) { + setError(err); + } finally { + setPendingAction(null); + } + } + + async function runQuery() { + if (!profile) return; + setPendingAction("query"); + setError(null); + try { + const next = await callOp("trace-query", requestBody(profileName, params, from, to, limit)); + const nextRows = flattenTraces(next.traces); + setResult(next); + setSelected(nextRows[0] ?? null); + setPreview(null); + } catch (err) { + setError(err); + } finally { + setPendingAction(null); + } + } + + return ( +
+
+ + + onChange(e.target.value)} /> +
+ ); +} + +function TraceNumberField({ + label, + value, + onChange, +}: { + label: string; + value: number; + onChange: (value: number) => void; +}) { + return ( +
+ + onChange(Number(e.target.value) || 100)} + /> +
+ ); +} + +function buildColumns(columns: TracingColumn[]): Array> { + return columns + .filter((col) => !col.detail) + .map((col) => { + const column: DataTableColumn = { + key: col.name, + label: col.name, + sortable: true, + filterable: true, + grow: /operation|message|name/i.test(col.name), + shrink: /status|duration/i.test(col.name), + align: /duration|count|size|ms$/i.test(col.name) ? "right" : "left", + render: (value, row) => renderCell(value, col, row), + filterValue: (value) => (value == null ? "" : String(value)), + sortValue: sortValue, + cellClassName: cellClass(col), + }; + + if (/time|timestamp/i.test(col.name) || /time|timestamp/i.test(col.field)) { + column.kind = "timestamp"; + column.timestamp = { mode: "auto" }; + } else if (/status/i.test(col.name)) { + column.kind = "status"; + column.status = { showLabel: true }; + } + + return column; + }); +} + +function defaultParams(profile: ProfileSummary): Record { + const out: Record = {}; + for (const [key, value] of Object.entries(profile.defaults ?? {})) { + if (value != null) out[key] = String(value); + } + return out; +} + +function requestBody(profile: string, params: Record, from: string, to: string, limit: number) { + const cleanParams: Record = {}; + for (const [key, value] of Object.entries(params)) { + if (value.trim()) cleanParams[key] = value.trim(); + } + return { profile, params: cleanParams, from: from.trim(), to: to.trim(), limit }; +} + +function flattenTraces(traces: Trace[]): TraceRow[] { + const out: TraceRow[] = []; + const walk = (trace: Trace, depth: number) => { + const row: TraceRow = { + ...(trace.cells ?? {}), + _id: `${trace.trace_id || "trace"}:${trace.span_id || out.length}`, + _depth: depth, + _trace: trace, + }; + out.push(row); + for (const child of trace.children ?? []) walk(child, depth + 1); + }; + for (const trace of traces) walk(trace, 0); + return out; +} + +function renderCell(value: unknown, col: TracingColumn, row: TraceRow): React.ReactNode { + if (value == null) return ""; + const text = formatValue(value); + const content = /operation|name/i.test(col.name) && row._depth > 0 ? `${" ".repeat(row._depth)}${text}` : text; + return ( + + {content} + + ); +} + +function formatValue(value: unknown): string { + if (typeof value === "number" && Number.isFinite(value)) { + return value % 1 === 0 ? String(value) : value.toFixed(2); + } + if (typeof value === "object") return JSON.stringify(value); + return String(value); +} + +function sortValue(value: unknown): unknown { + if (typeof value === "number") return value; + if (typeof value === "string") { + const timestamp = Date.parse(value); + if (Number.isFinite(timestamp) && /[-:T]/.test(value)) return timestamp; + const numeric = Number(value); + if (Number.isFinite(numeric) && value.trim() !== "") return numeric; + } + return value; +} + +function cellClass(col: TracingColumn): string { + if (/id$/i.test(col.name) || col.name.includes("ID")) { + return "inline-block max-w-[360px] truncate align-bottom font-mono"; + } + if (/time|duration/i.test(col.name)) return "font-mono"; + return "inline-block max-w-[360px] truncate align-bottom"; +} + +createRoot(document.getElementById("root")!).render(); diff --git a/opensearch/ui-src/src/styles.css b/opensearch/ui-src/src/styles.css new file mode 100644 index 0000000..f1d8c73 --- /dev/null +++ b/opensearch/ui-src/src/styles.css @@ -0,0 +1 @@ +@import "tailwindcss"; diff --git a/opensearch/ui-src/src/version.ts b/opensearch/ui-src/src/version.ts new file mode 100644 index 0000000..edf4f9f --- /dev/null +++ b/opensearch/ui-src/src/version.ts @@ -0,0 +1,2 @@ +export const pluginVersion = import.meta.env.PLUGIN_VERSION || "dev"; +export const pluginBuildDate = import.meta.env.PLUGIN_BUILD_DATE || ""; diff --git a/opensearch/ui-src/src/vite-env.d.ts b/opensearch/ui-src/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/opensearch/ui-src/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/opensearch/ui-src/tsconfig.json b/opensearch/ui-src/tsconfig.json new file mode 100644 index 0000000..596336d --- /dev/null +++ b/opensearch/ui-src/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["DOM", "DOM.Iterable", "ES2022"], + "allowJs": false, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "module": "ESNext", + "moduleResolution": "Bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx" + }, + "include": ["src"], + "references": [] +} diff --git a/opensearch/ui-src/vite.config.ts b/opensearch/ui-src/vite.config.ts new file mode 100644 index 0000000..35ccf1a --- /dev/null +++ b/opensearch/ui-src/vite.config.ts @@ -0,0 +1,12 @@ +import react from "@vitejs/plugin-react"; +import tailwindcss from "@tailwindcss/vite"; +import { defineConfig } from "vite"; + +export default defineConfig({ + plugins: [tailwindcss(), react()], + base: "./", + build: { + outDir: "../ui", + emptyOutDir: true + } +}); diff --git a/opensearch/ui/index.html b/opensearch/ui/index.html new file mode 100644 index 0000000..8e85153 --- /dev/null +++ b/opensearch/ui/index.html @@ -0,0 +1,13 @@ + + + + + + OpenSearch + + + + +
+ + diff --git a/opensearch/ui_checksum.go b/opensearch/ui_checksum.go new file mode 100644 index 0000000..a28cd5c --- /dev/null +++ b/opensearch/ui_checksum.go @@ -0,0 +1,5 @@ +// Code generated by plugins/opensearch/internal/gen-checksum. DO NOT EDIT. + +package main + +const uiChecksum = "3cd62e3217a7efe783da799150f7aa62dec08278c38a3bf392631fbf81684742"